DungeonCrawl
Loading...
Searching...
No Matches
logger.c File Reference

Implements logging functionality for the game. More...

#include "logger.h"
#include "../thread/thread_handler.h"
#include "logger_config.h"
#include "ringbuffer.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <time.h>
#include <dirent.h>

Go to the source code of this file.

Macros

#define STAT_STRUCT   struct stat
#define STAT_FUNC   stat
#define MKDIR(path)
#define PATH_SEP   "/"
#define MAX_PATH_SIZE   4096
#define LOG_DIRECTORY   "log"
#define LOG_FILE_FORMAT   "log-%d.txt"
#define TIMESTAMP_FORMAT   "%Y-%m-%d %H:%M:%S"
#define MSG_FORMAT   "[%s] [%s] [%s] : %s\n"

Functions

int ensure_log_dir (void)
 Ensures that the predefined log directory already exists, if not create a new one.
int open_log_file (int is_init)
 Opens the log file with the current saved file id in appended modus.
int check_log_file (void)
 This function should be called whenever a new log msg must be written.
int get_latest_file_id (void)
 This function gets the latest file id from the log directory.
void start_log_writer_thread (void)
 Starts the log writer thread.
void log_writer_thread (void)
 This function will be called from a different thread to read from the ringbuffer and then write in the log file.
void init_logger (void)
 Initializes the logging system for the application.
void log_msg (const log_level_t level, const char *module, const char *format,...)
 Logs a formatted message with a specified log level and module.
void shutdown_logger (void)
 Shuts down the logging system for the application.

Variables

const char * log_level_str [] = {"DEBUG", "FINE", "INFO", "WARNING", "ERROR"}
FILE * log_file = NULL
ring_buffer_t log_buffer
bool logger_is_running = false
int file_id = 0

Detailed Description

Implements logging functionality for the game.

Definition in file logger.c.

Macro Definition Documentation

◆ LOG_DIRECTORY

#define LOG_DIRECTORY   "log"

Definition at line 37 of file logger.c.

◆ LOG_FILE_FORMAT

#define LOG_FILE_FORMAT   "log-%d.txt"

Definition at line 38 of file logger.c.

◆ MAX_PATH_SIZE

#define MAX_PATH_SIZE   4096

Definition at line 34 of file logger.c.

◆ MKDIR

#define MKDIR ( path)
Value:
mkdir(path, 0755)

Definition at line 30 of file logger.c.

◆ MSG_FORMAT

#define MSG_FORMAT   "[%s] [%s] [%s] : %s\n"

Definition at line 41 of file logger.c.

◆ PATH_SEP

#define PATH_SEP   "/"

Definition at line 31 of file logger.c.

◆ STAT_FUNC

#define STAT_FUNC   stat

Definition at line 29 of file logger.c.

◆ STAT_STRUCT

#define STAT_STRUCT   struct stat

Definition at line 28 of file logger.c.

◆ TIMESTAMP_FORMAT

#define TIMESTAMP_FORMAT   "%Y-%m-%d %H:%M:%S"

Definition at line 40 of file logger.c.

Function Documentation

◆ check_log_file()

int check_log_file ( void )

This function should be called whenever a new log msg must be written.

Check if the log file is open, if not, a new file will be open.

  • Either by creating a new file if no file is in the log directory.
  • Or creating a new file if the last used file reaches the max size. The new file will get the current file id + 1 or 0, if the id reached the max number of files.
  • Or opening the file that was last used, the current id will be set.
    Returns
    0 if successfully, 1 if the current file was already closed, and a new file wasn't opened

Definition at line 144 of file logger.c.

144 {
145 if (log_file) {
146 fseek(log_file, 0, SEEK_END);
147 const long file_size = ftell(log_file);
148 if (file_size >= MAX_FILE_SIZE) {
149 fclose(log_file);//close the current file
150 file_id = (file_id + 1) % MAX_N_FILES;
151
152 // open a new file
153 if (open_log_file(1) != 0) {
154 // failed to open a new file
155 return 1;
156 }
157 }
158 }
159 return 0;
160}
int open_log_file(int is_init)
Opens the log file with the current saved file id in appended modus.
Definition logger.c:117

◆ ensure_log_dir()

int ensure_log_dir ( void )

Ensures that the predefined log directory already exists, if not create a new one.

Returns
0 if successfully created or already exists, 1 if failed

Definition at line 105 of file logger.c.

105 {
106 STAT_STRUCT st;
107
108 if (STAT_FUNC(LOG_DIRECTORY, &st) == -1) {
109 if (MKDIR(LOG_DIRECTORY) == -1) {
110 return 1;
111 }
112 }
113 return 0;
114}

◆ get_latest_file_id()

int get_latest_file_id ( void )

This function gets the latest file id from the log directory.

Returns
0 or greater if successfully, -1 if failed
Note
This function should only be called once when the logger is initialized.

Definition at line 162 of file logger.c.

162 {
163 if (ensure_log_dir() != 0) {
164 // failed to ensure the log directory
165 return -1;
166 }
167
168 int latest_id = 0;
169 DIR* dir = opendir(LOG_DIRECTORY);
170 struct dirent* entry;
171 time_t latest_time = 0;
172
173 if (!dir) {
174 // failed to open the log directory
175 return -1;
176 }
177
178 // Iterate through the log directory and find the latest used file
179 while ((entry = readdir(dir)) != NULL) {
180 int id;
181 struct stat file_stat;
182
183 if (sscanf(entry->d_name, LOG_FILE_FORMAT, &id) == 1 && id >= 0 && id < MAX_N_FILES) {
184 char filepath[MAX_PATH_SIZE];
185 snprintf(filepath, sizeof(filepath), "%s/%s", LOG_DIRECTORY, entry->d_name);
186
187 if (stat(filepath, &file_stat) == 0) {
188 if (file_stat.st_mtime > latest_time) {
189 // found a newer file
190 latest_time = file_stat.st_mtime;
191 latest_id = id;
192 }
193 }
194 }
195 }
196
197 closedir(dir);
198 return latest_id;
199}
int ensure_log_dir(void)
Ensures that the predefined log directory already exists, if not create a new one.
Definition logger.c:105

◆ init_logger()

void init_logger ( void )

Initializes the logging system for the application.

This function sets up the logging system to be ready for recording log entries. It creates or opens the log file, initializes the ring buffer used for storing log entries temporarily, and starts the thread that asynchronously writes logs to the file. This ensures logging is operational and ready to use for the application's lifetime.

Notes:

  • This function can only be called once during the application's lifecycle. Subsequent calls will have no effect if the logger is already initialized.
  • All required resources for logging, such as the log file and ring buffer, are prepared within this initialization process.
  • If any of the initialization steps fail (e.g., ring buffer initialization or file operations), the function ensures cleanup of allocated resources.

Definition at line 232 of file logger.c.

232 {
233 // ensures the init_logger can only be called when the file is null
234 if (log_file == NULL) {
235 if (init_ringbuffer(&log_buffer) == 0) {
236 file_id = get_latest_file_id();
237 if (file_id == -1 || open_log_file(0) != 0) {
238 fclose(log_file);
239 } else {
241 }
242 }
243 }
244}
int get_latest_file_id(void)
This function gets the latest file id from the log directory.
Definition logger.c:162
void start_log_writer_thread(void)
Starts the log writer thread.
Definition logger.c:201

◆ log_msg()

void log_msg ( log_level_t level,
const char * module,
const char * format,
... )

Logs a formatted message with a specified log level and module.

This function generates a log entry that includes a timestamp, log level, module name, and a custom message formatted using a variable argument list. The log message is written to a ring buffer for asynchronous processing.

Notes:

  • The logging system must be initialized and running before using this function. Otherwise, the function will return without performing any operations.
  • The log level determines the severity or importance of the message.
Parameters
levelThe severity level of the log message (e.g., DEBUG, INFO, ERROR). If the provided log level exceeds the maximum defined levels, the INFO level will be used as a fallback.
moduleA string identifying the module or component generating the log message.
formatA printf-style format string for the message content.
...Additional arguments to be formatted into the log message according to the format string.

Definition at line 246 of file logger.c.

246 {
247 if (log_file == NULL || !logger_is_running) {
248 // logger is not initialized or not running
249 return;
250 }
251
252 //get timestamp
253 const time_t now = time(NULL);
254 const struct tm* tm = localtime(&now);
255
256 char timestamp[32];
257 strftime(timestamp, sizeof(timestamp), TIMESTAMP_FORMAT, tm);
258
259 const char* log_level;
260 if (level >= MAX_LOG_LEVEL) {
261 log_level = log_level_str[INFO];
262 } else {
263 log_level = log_level_str[level];
264 }
265
266 va_list args;
267 va_start(args, format);
268 char msg[MAX_MSG_SIZE - MAX_HEADER_SIZE];
269 vsnprintf(msg, sizeof(msg), format, args);
270
271 char log_msg[MAX_MSG_SIZE];
272 snprintf(log_msg, MAX_MSG_SIZE, MSG_FORMAT, timestamp, log_level, module, msg);
273 va_end(args);
274
275 write_to_ringbuffer(&log_buffer, log_msg);
276}
void log_msg(const log_level_t level, const char *module, const char *format,...)
Logs a formatted message with a specified log level and module.
Definition logger.c:246

◆ log_writer_thread()

void log_writer_thread ( void )

This function will be called from a different thread to read from the ringbuffer and then write in the log file.

Definition at line 207 of file logger.c.

207 {
208 bool running = true;
209 while (running) {
210 char log_msg[MAX_MSG_SIZE];
211 if (read_from_ringbuffer(&log_buffer, log_msg) == 0) {
212 // message successfully read from the ringbuffer
214 if (log_file) {
215 fprintf(log_file, "%s", log_msg);
216 fflush(log_file);
217 }
218 }
219 if (!logger_is_running) {
220 // thread must be terminated
221 running = false;
222 }
223 }
224 //closes all pressures
225 if (log_file) {
226 fclose(log_file);
227 log_file = NULL;
228 }
229 free_ringbuffer(&log_buffer);
230}
int check_log_file(void)
This function should be called whenever a new log msg must be written.
Definition logger.c:144

◆ open_log_file()

int open_log_file ( int is_init)

Opens the log file with the current saved file id in appended modus.

If the file already exists, it will be first removed and then created. If no file is found, create a new file corresponding to fopen(...).

Parameters
is_initif 0, no existing file will be removed
Returns
0 if successfully opened, 1 if failed

Definition at line 117 of file logger.c.

117 {
118 char name[16];
119 snprintf(name, sizeof(name), LOG_FILE_FORMAT, file_id);
120
121 char filename[256];
122 snprintf(filename, sizeof(filename), "%s" PATH_SEP "%s", LOG_DIRECTORY, name);
123
124 if (is_init) {
125 // Check if the file already exists
126 FILE* existing_file = fopen(filename, "r");
127 if (existing_file) {
128 fclose(existing_file);
129
130 // If the file already exists, remove it
131 if (remove(filename) != 0) {
132 return 1;
133 }
134 }
135 }
136
137 log_file = fopen(filename, "a");
138 if (!log_file) {
139 return 1;
140 }
141 return 0;
142}

◆ shutdown_logger()

void shutdown_logger ( void )

Shuts down the logging system for the application.

This function terminates the logging system, ensuring that no further log entries are recorded. It sets the logger's running state to false, effectively disabling any ongoing or future logging operations.

Use this function to cleanly release logging resources and mark the completion of logging operations at the end of the application's lifecycle or during application shutdown sequences.

Notes:

  • Once this function is called, logging within the application will cease to function.
  • This function should be called after all dependent systems and processes using the logger are finalized.

Definition at line 278 of file logger.c.

278 {
279 logger_is_running = false;
280}

◆ start_log_writer_thread()

void start_log_writer_thread ( void )

Starts the log writer thread.

This function will be called from the logger initialization function.

Definition at line 201 of file logger.c.

201 {
202 logger_is_running = true;
203
205}
void log_writer_thread(void)
This function will be called from a different thread to read from the ringbuffer and then write in th...
Definition logger.c:207
void start_simple_thread(void(*thread_func)(void))
Starts a new thread with the given function.

Variable Documentation

◆ file_id

int file_id = 0

Definition at line 103 of file logger.c.

◆ log_buffer

ring_buffer_t log_buffer

Definition at line 98 of file logger.c.

◆ log_file

FILE* log_file = NULL

Definition at line 97 of file logger.c.

◆ log_level_str

const char* log_level_str[] = {"DEBUG", "FINE", "INFO", "WARNING", "ERROR"}

Definition at line 43 of file logger.c.

43{"DEBUG", "FINE", "INFO", "WARNING", "ERROR"};

◆ logger_is_running

bool logger_is_running = false

Definition at line 101 of file logger.c.