feat(logging)!: add enhanced logging system
BREAKING CHANGE: stk_log() signature changed to require log level - Add log levels (ERROR, WARN, INFO, DEBUG) with runtime filtering - Add timestamps (yyyy-mm-dd HH:MM:SS.mmm format) - Add stk_set_log_output(), stk_set_log_prefix(), stk_set_log_level() - Platform-specific timestamp: GetLocalTime (Windows), gettimeofday (POSIX) - Consolidate duplicate platform includes into POSIX common block - Setting log output to NULL disables logging. Default: INFO level, "stk" prefix, stdout output. All internal messages use appropriate severity levels. Single byte flag controls enable/disable.
This commit is contained in:
+28
-9
@@ -4,27 +4,24 @@
|
||||
#include <string.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <dirent.h>
|
||||
#include <dlfcn.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <dirent.h>
|
||||
#include <dlfcn.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#elif defined(_WIN32)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <dirent.h>
|
||||
#include <dlfcn.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
+77
-5
@@ -1,14 +1,86 @@
|
||||
#include "stk_log.h"
|
||||
#include "stk.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user