10#include "ringbuffer.h"
21 #define STAT_STRUCT struct _stat
22 #define STAT_FUNC _stat
23 #define MKDIR(path) _mkdir(path)
28 #define STAT_STRUCT struct stat
29 #define STAT_FUNC stat
30 #define MKDIR(path) mkdir(path, 0755)
34#define MAX_PATH_SIZE 4096
37#define LOG_DIRECTORY "log"
38#define LOG_FILE_FORMAT "log-%d.txt"
40#define TIMESTAMP_FORMAT "%Y-%m-%d %H:%M:%S"
41#define MSG_FORMAT "[%s] [%s] [%s] : %s\n"
43const char* log_level_str[] = {
"DEBUG",
"FINE",
"INFO",
"WARNING",
"ERROR"};
101bool logger_is_running =
false;
108 if (STAT_FUNC(LOG_DIRECTORY, &st) == -1) {
109 if (MKDIR(LOG_DIRECTORY) == -1) {
119 snprintf(name,
sizeof(name), LOG_FILE_FORMAT, file_id);
122 snprintf(filename,
sizeof(filename),
"%s" PATH_SEP
"%s", LOG_DIRECTORY, name);
126 FILE* existing_file = fopen(filename,
"r");
128 fclose(existing_file);
131 if (remove(filename) != 0) {
137 log_file = fopen(filename,
"a");
146 fseek(log_file, 0, SEEK_END);
147 const long file_size = ftell(log_file);
148 if (file_size >= MAX_FILE_SIZE) {
150 file_id = (file_id + 1) % MAX_N_FILES;
169 DIR* dir = opendir(LOG_DIRECTORY);
170 struct dirent* entry;
171 time_t latest_time = 0;
179 while ((entry = readdir(dir)) != NULL) {
181 struct stat file_stat;
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);
187 if (stat(filepath, &file_stat) == 0) {
188 if (file_stat.st_mtime > latest_time) {
190 latest_time = file_stat.st_mtime;
202 logger_is_running =
true;
211 if (read_from_ringbuffer(&log_buffer,
log_msg) == 0) {
215 fprintf(log_file,
"%s",
log_msg);
219 if (!logger_is_running) {
229 free_ringbuffer(&log_buffer);
234 if (log_file == NULL) {
235 if (init_ringbuffer(&log_buffer) == 0) {
246void log_msg(
const log_level_t level,
const char* module,
const char* format, ...) {
247 if (log_file == NULL || !logger_is_running) {
253 const time_t now = time(NULL);
254 const struct tm* tm = localtime(&now);
257 strftime(timestamp,
sizeof(timestamp), TIMESTAMP_FORMAT, tm);
259 const char* log_level;
260 if (level >= MAX_LOG_LEVEL) {
261 log_level = log_level_str[INFO];
263 log_level = log_level_str[level];
267 va_start(args, format);
268 char msg[MAX_MSG_SIZE - MAX_HEADER_SIZE];
269 vsnprintf(msg,
sizeof(msg), format, args);
272 snprintf(
log_msg, MAX_MSG_SIZE, MSG_FORMAT, timestamp, log_level, module, msg);
275 write_to_ringbuffer(&log_buffer,
log_msg);
279 logger_is_running =
false;
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.
void shutdown_logger(void)
Shuts down the logging system for the application.
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 init_logger(void)
Initializes the logging system for the application.
void start_log_writer_thread(void)
Starts the log writer thread.
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 log_writer_thread(void)
This function will be called from a different thread to read from the ringbuffer and then write in th...
Header file for logging functionality of the game.
Configuration file for the logger.
void start_simple_thread(void(*thread_func)(void))
Starts a new thread with the given function.
Exposes functions for the thread_handler.