diff --git a/include/stk.h b/include/stk.h index 69f8b05..21a8d82 100644 --- a/include/stk.h +++ b/include/stk.h @@ -5,6 +5,7 @@ #include /* Buffers */ +#define STK_LOG_PREFIX_BUFFER 64 #define STK_MOD_DIR_BUFFER 256 #define STK_MOD_ID_BUFFER 64 #define STK_PATH_MAX 256 diff --git a/include/stk_log.h b/include/stk_log.h index c66fe36..3fb3286 100644 --- a/include/stk_log.h +++ b/include/stk_log.h @@ -7,7 +7,18 @@ extern "C" { #endif -void stk_log(FILE *fp, const char *fmt, ...); +typedef enum { + STK_LOG_ERROR, + STK_LOG_WARN, + STK_LOG_INFO, + STK_LOG_DEBUG +} stk_log_level_t; + +void stk_set_log_output(FILE *fp); +void stk_set_log_prefix(const char *prefix); +void stk_set_log_level(stk_log_level_t min_level); + +void stk_log(stk_log_level_t level, const char *fmt, ...); #ifdef __cplusplus } diff --git a/src/platform.c b/src/platform.c index 1880d73..6b01dee 100644 --- a/src/platform.c +++ b/src/platform.c @@ -4,27 +4,24 @@ #include #ifndef _WIN32 +#include +#include #include +#include +#include +#include +#include #endif #if defined(__linux__) -#include -#include #include -#include -#include #elif defined(_WIN32) #define WIN32_LEAN_AND_MEAN #include #else -#include -#include #include #include -#include -#include #include -#include #endif int is_mod_loaded(const char *module_name); @@ -1009,3 +1006,25 @@ no_change: return NULL; #endif } + +void platform_get_timestamp(char *buffer, size_t size) +{ +#ifdef _WIN32 + SYSTEMTIME st; + GetLocalTime(&st); + sprintf(buffer, "%04d-%02d-%02d %02d:%02d:%02d.%03d", st.wYear, + st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, + st.wMilliseconds); +#else + struct timeval tv; + struct tm *tm_info; + + gettimeofday(&tv, NULL); + tm_info = localtime(&tv.tv_sec); + + sprintf(buffer, "%04d-%02d-%02d %02d:%02d:%02d.%03d", + tm_info->tm_year + 1900, tm_info->tm_mon + 1, tm_info->tm_mday, + tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec, + (int)(tv.tv_usec / 1000)); +#endif +} diff --git a/src/stk.c b/src/stk.c index d4f32ff..7fcde51 100644 --- a/src/stk.c +++ b/src/stk.c @@ -86,7 +86,7 @@ unsigned char stk_init(void) if (test_scan) free(test_scan); if (!test_scan && test_count == 0) { - stk_log(stderr, + stk_log(STK_LOG_ERROR, "FATAL: Cannot create temp directory: %s", stk_tmp_dir); return STK_INIT_TMPDIR_ERROR; @@ -96,7 +96,7 @@ unsigned char stk_init(void) files = platform_directory_init_scan(stk_mod_dir, &file_count); if (file_count > 0 && stk_module_init_memory(file_count) != 0) { - stk_log(stderr, "FATAL: Memory allocation failed"); + stk_log(STK_LOG_ERROR, "FATAL: Memory allocation failed"); return STK_INIT_MEMORY_ERROR; } @@ -109,7 +109,8 @@ unsigned char stk_init(void) if (platform_copy_file(full_path, tmp_path) != STK_PLATFORM_OPERATION_SUCCESS) { - stk_log(stderr, "Failed to copy %s to temp directory", + stk_log(STK_LOG_ERROR, + "Failed to copy %s to temp directory", files[i]); continue; } @@ -117,7 +118,7 @@ unsigned char stk_init(void) load_result = stk_module_load_init(tmp_path, successful_loads); if (load_result != STK_MOD_INIT_SUCCESS) { - stk_log(stderr, "Failed to load module %s: %s", + stk_log(STK_LOG_ERROR, "Failed to load module %s: %s", files[i], stk_error_string(load_result)); } else { successful_loads++; @@ -133,13 +134,14 @@ unsigned char stk_init(void) scanned: watch_handle = platform_directory_watch_start(stk_mod_dir); if (!watch_handle) { - stk_log(stderr, "FATAL: Cannot start directory watch on %s", + stk_log(STK_LOG_ERROR, + "FATAL: Cannot start directory watch on %s", stk_mod_dir); stk_module_unload_all(); return STK_INIT_WATCH_ERROR; } - stk_log(stdout, "stk v%s initialized! Loaded %lu mod%s from %s/", + stk_log(STK_LOG_INFO, "stk v%s initialized! Loaded %lu mod%s from %s/", STK_VERSION_STRING, module_count, module_count != 1 ? "s" : "", stk_mod_dir); @@ -158,12 +160,13 @@ void stk_shutdown(void) if (platform_remove_dir(stk_tmp_dir) != STK_PLATFORM_OPERATION_SUCCESS) { - stk_log(stderr, "Warning: failed to remove temp directory %s", + stk_log(STK_LOG_WARN, + "Warning: failed to remove temp directory %s", stk_tmp_dir); } stk_flags &= ~STK_FLAG_INITIALIZED; - stk_log(stdout, "stk shutdown"); + stk_log(STK_LOG_INFO, "stk shutdown"); } size_t stk_poll(void) @@ -262,7 +265,7 @@ begin_operations: if (platform_copy_file(full_path, tmp_path) != STK_PLATFORM_OPERATION_SUCCESS) { - stk_log(stderr, "Failed to copy %s for reload", + stk_log(STK_LOG_ERROR, "Failed to copy %s for reload", file_list[file_index]); continue; } @@ -271,7 +274,7 @@ begin_operations: load_result = stk_module_load(tmp_path, mod_index); if (load_result != STK_MOD_INIT_SUCCESS) { - stk_log(stderr, "Failed to reload module %s: %s", + stk_log(STK_LOG_ERROR, "Failed to reload module %s: %s", file_list[file_index], stk_error_string(load_result)); } @@ -289,14 +292,14 @@ begin_operations: if (platform_copy_file(full_path, tmp_path) != STK_PLATFORM_OPERATION_SUCCESS) { - stk_log(stderr, "Failed to copy %s for loading", + stk_log(STK_LOG_ERROR, "Failed to copy %s for loading", file_list[file_index]); continue; } load_result = stk_module_load(tmp_path, target_index); if (load_result != STK_MOD_INIT_SUCCESS) { - stk_log(stderr, "Failed to load module %s: %s", + stk_log(STK_LOG_ERROR, "Failed to load module %s: %s", file_list[file_index], stk_error_string(load_result)); } @@ -321,7 +324,7 @@ append_modules: if (platform_copy_file(full_path, tmp_path) != STK_PLATFORM_OPERATION_SUCCESS) { - stk_log(stderr, "Failed to copy %s for loading", + stk_log(STK_LOG_ERROR, "Failed to copy %s for loading", file_list[file_index]); continue; } @@ -329,7 +332,7 @@ append_modules: load_result = stk_module_load(tmp_path, module_count + successful_appends); if (load_result != STK_MOD_INIT_SUCCESS) { - stk_log(stderr, "Failed to load module %s: %s", + stk_log(STK_LOG_ERROR, "Failed to load module %s: %s", file_list[file_index], stk_error_string(load_result)); } else { diff --git a/src/stk_log.c b/src/stk_log.c index d8d9cc3..339927e 100644 --- a/src/stk_log.c +++ b/src/stk_log.c @@ -1,14 +1,86 @@ #include "stk_log.h" +#include "stk.h" #include #include +#include -void stk_log(FILE *fp, const char *fmt, ...) +#define STK_LOG_TIMESTAMP_BUFFER 32 + +extern unsigned char stk_flags; +void platform_get_timestamp(char *buffer, size_t size); + +static FILE *log_output = NULL; +static char log_prefix[STK_LOG_PREFIX_BUFFER] = "stk"; +static stk_log_level_t min_log_level = STK_LOG_INFO; + +static const char *get_level_string(stk_log_level_t level) { - va_list args; - va_start(args, fmt); + char *level_str = ""; + switch (level) { + case STK_LOG_ERROR: + level_str = "ERROR"; + break; + case STK_LOG_WARN: + level_str = "WARN"; + break; + case STK_LOG_INFO: + level_str = "INFO"; + break; + case STK_LOG_DEBUG: + level_str = "DEBUG"; + break; + } - vfprintf(fp, fmt, args); - fputc('\n', fp); + return level_str; +} +void stk_set_log_output(FILE *fp) +{ + if (fp == NULL) + stk_flags &= ~STK_FLAG_LOGGING_ENABLED; + + log_output = fp; +} + +void stk_set_log_prefix(const char *prefix) +{ + if (!prefix) { + log_prefix[0] = '\0'; + return; + } + + strncpy(log_prefix, prefix, STK_LOG_PREFIX_BUFFER - 1); + log_prefix[STK_LOG_PREFIX_BUFFER - 1] = '\0'; +} + +void stk_set_log_level(stk_log_level_t level) { min_log_level = level; } + +void stk_log(stk_log_level_t level, const char *fmt, ...) +{ + FILE *output; + const char *level_str; + char timestamp[STK_LOG_TIMESTAMP_BUFFER]; + va_list args; + + if (!(stk_flags & STK_FLAG_LOGGING_ENABLED)) + return; + + if (level < min_log_level) + return; + + output = log_output ? log_output : stdout; + level_str = get_level_string(level); + platform_get_timestamp(timestamp, sizeof(timestamp)); + + if (log_prefix[0] != '\0') + fprintf(output, "%s [%s] [%s] ", timestamp, log_prefix, + level_str); + else + fprintf(output, "%s [%s] ", timestamp, level_str); + + va_start(args, fmt); + vfprintf(output, fmt, args); va_end(args); + + fputc('\n', output); }