From 659142c181a22f58abf970b180e1e22c8c31f2ae Mon Sep 17 00:00:00 2001 From: TheoryOfNekomata Date: Wed, 15 Feb 2023 09:55:15 +0800 Subject: [PATCH] Fix logging Add capability to log outside stderr and stdout. --- src/packages/game/IZ_app.c | 2 ++ src/packages/io/IZ_io.c | 33 ++++++++++++++++++ src/packages/io/IZ_io.h | 5 +++ src/packages/log/IZ_log.c | 64 +++++++++++++++++++++++++---------- src/packages/log/IZ_log.h | 15 +++++--- src/packages/server/IZ_app.c | 4 ++- src/packages/timer/IZ_timer.c | 17 ++++++++++ src/packages/timer/IZ_timer.h | 14 +++++--- 8 files changed, 127 insertions(+), 27 deletions(-) diff --git a/src/packages/game/IZ_app.c b/src/packages/game/IZ_app.c index 59cfcc6..4482671 100644 --- a/src/packages/game/IZ_app.c +++ b/src/packages/game/IZ_app.c @@ -26,6 +26,7 @@ typedef enum { } IZ_AppInitializeResult; IZ_AppInitializeResult IZ_AppInitialize(struct IZ_App* app, u8 argc, const char* argv[]) { + IZ_LogInitialize("game"); IZ_LogInterceptWSMessages(LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE); IZ_LogInfo(IZ_LOG_CATEGORY_GLOBAL, "global", "Starting %s...", IZ_APP_NAME); @@ -76,6 +77,7 @@ void IZ_AppTeardown(struct IZ_App* app) { IZ_InputTeardown(&app->input_state); IZ_VideoTeardown(&app->video_state); IZ_LogInfo(IZ_LOG_CATEGORY_GLOBAL, "global", "Stopping %s...", IZ_APP_NAME); + IZ_LogTeardown(); SDL_Quit(); } diff --git a/src/packages/io/IZ_io.c b/src/packages/io/IZ_io.c index ed8e13a..a5226e0 100644 --- a/src/packages/io/IZ_io.c +++ b/src/packages/io/IZ_io.c @@ -24,3 +24,36 @@ errno_t IZ_fopen(FILE** file, const char* filename, const char* mode) { return *file == NULL ? 1 : 0; #endif } + +errno_t IZ_mkdir(const char* path) { +#if defined IZ_WINDOWS + if (!CreateDirectory(path, NULL)) { + return GetLastError(); + } + return 0; +#else + mkdir(path, 0777); + return 0; +#endif +} + +bool IZ_isdir(const char* path) { +#if defined IZ_WINDOWS + DWORD dwAttrib = GetFileAttributes(path); + + return (dwAttrib != INVALID_FILE_ATTRIBUTES && + (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); +#else + struct stat s; + int err = stat("/path/to/possible_dir", &s); + if(-1 == err) { + if(ENOENT == errno) { + return false; + } + perror("stat"); + exit(1);\ + return; + } + return (S_ISDIR(s.st_mode)) +#endif +} diff --git a/src/packages/io/IZ_io.h b/src/packages/io/IZ_io.h index 8ac0777..6db24c2 100644 --- a/src/packages/io/IZ_io.h +++ b/src/packages/io/IZ_io.h @@ -2,6 +2,7 @@ #define IZ_IO_H #include +#include #include #include "../compat/IZ_windows.h" @@ -9,4 +10,8 @@ int IZ_sprintf(char*, size_t, const char*, ...); errno_t IZ_fopen(FILE**, const char*, const char*); +errno_t IZ_mkdir(const char*); + +bool IZ_isdir(const char*); + #endif diff --git a/src/packages/log/IZ_log.c b/src/packages/log/IZ_log.c index bccd8bb..049d794 100644 --- a/src/packages/log/IZ_log.c +++ b/src/packages/log/IZ_log.c @@ -32,11 +32,38 @@ bool IZ_LogIsSupportedTerminal() { #endif } -bool IZ_LogIsSupportedColor() { +bool IZ_LogIsSupportedColor(FILE* s) { #ifdef IZ_WINDOWS - return _isatty(_fileno(stdout)) && IZ_LogIsSupportedTerminal(); + return _isatty(_fileno(s)) && IZ_LogIsSupportedTerminal(); #else - return isatty(fileno(stdout)) && IZ_LogIsSupportedTerminal(); + return isatty(fileno(s)) && IZ_LogIsSupportedTerminal(); +#endif +} + +void IZ_LogInitialize(const char* context) { +#ifdef IZ_DEBUG + stdout_dest = stdout; + stderr_dest = stderr; +#else + const char* log_dir = "logs"; + if (!IZ_isdir(log_dir)) { + IZ_mkdir(log_dir); + } + char stdout_filename[128] = ""; + char stderr_filename[128] = ""; + char* now = IZ_TimerNowPathSafe(); + + // fixme + sprintf(stdout_filename, "%s/out-%s-%s.log", log_dir, context, now); + sprintf(stderr_filename, "%s/err-%s-%s.log", log_dir, context, now); + IZ_fopen(&stdout_dest, stdout_filename, "a"); + IZ_fopen(&stderr_dest, stderr_filename, "a"); +#endif +} + +void IZ_LogTeardown() { +#ifndef IZ_DEBUG + fclose(stdout_dest); #endif } @@ -48,12 +75,12 @@ void IZ_LogError(const char* context, const char* fmt, ...) { vsnprintf(buffer, sizeof(buffer), fmt, args); va_end(args); - if (IZ_LogIsSupportedColor()) { - fprintf(stdout, RED "%24s" RESET " " BOLD "%-6s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); + if (IZ_LogIsSupportedColor(stdout_dest)) { + fprintf(stdout_dest, RED "%24s" RESET " " BOLD "%-6s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); return; } - fprintf(stderr, "%24s" " " "%-6s" " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); + fprintf(stderr_dest, "%24s" " " "%-6s" " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); #endif } @@ -65,24 +92,24 @@ void IZ_LogInfo(IZ_LogCategory category, const char* context, const char* fmt, . vsnprintf(buffer, sizeof(buffer), fmt, args); va_end(args); - if (IZ_LogIsSupportedColor()) { + if (IZ_LogIsSupportedColor(stdout_dest)) { switch (category) { default: case IZ_LOG_CATEGORY_GENERIC: - fprintf(stdout, CYN "%24s" RESET " " BOLD "%-6s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); + fprintf(stdout_dest, CYN "%24s" RESET " " BOLD "%-6s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); break; case IZ_LOG_CATEGORY_GLOBAL: - fprintf(stdout, MAG "%24s" RESET " " BOLD "%-6s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); + fprintf(stdout_dest, MAG "%24s" RESET " " BOLD "%-6s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); break; case IZ_LOG_CATEGORY_INPUT: - fprintf(stdout, WHT "%24s" RESET " " BOLD "%-6s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); + fprintf(stdout_dest, WHT "%24s" RESET " " BOLD "%-6s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); break; } return; } - fprintf(stdout, "%24s" " %s\n", IZ_LOG_DATE_FUNCTION(), buffer); + fprintf(stdout_dest, "%24s" " " "%-6s" " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); #endif } @@ -94,16 +121,16 @@ void IZ_LogWarn(bool is_critical, const char* context, const char* fmt, ...) { vsnprintf(buffer, sizeof(buffer), fmt, args); va_end(args); - if (IZ_LogIsSupportedColor()) { + if (IZ_LogIsSupportedColor(stdout_dest)) { if (is_critical) { - fprintf(stdout, GRN "%24s" RESET " " BOLD "%-6s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); + fprintf(stdout_dest, GRN "%24s" RESET " " BOLD "%-6s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); } else { - fprintf(stdout, YEL "%24s" RESET " " BOLD "%-6s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); + fprintf(stdout_dest, YEL "%24s" RESET " " BOLD "%-6s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); } return; } - fprintf(stdout, "%24s" " " "%-6s" " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); + fprintf(stdout_dest, "%24s" " " "%-6s" " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); #endif } @@ -114,11 +141,12 @@ void IZ_Log(const char* context, const char* fmt, ...) { va_start(args, fmt); vsnprintf(buffer, sizeof(buffer), fmt, args); va_end(args); - if (IZ_LogIsSupportedColor()) { - fprintf(stdout, BLU "%24s" RESET " " BOLD "%-6s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); + if (IZ_LogIsSupportedColor(stdout_dest)) { + fprintf(stdout_dest, BLU "%24s" RESET " " BOLD "%-6s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); return; } - fprintf(stdout, "%24s" " " "%-6s" " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); + fprintf(stdout_dest, "%24s" " " "%-6s" " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); + fflush(stdout_dest); #endif } diff --git a/src/packages/log/IZ_log.h b/src/packages/log/IZ_log.h index 3afdb9a..c22d2f1 100644 --- a/src/packages/log/IZ_log.h +++ b/src/packages/log/IZ_log.h @@ -22,6 +22,8 @@ #include #include #include "../timer/IZ_timer.h" +#include "../io/IZ_io.h" +#include "../stdinc/IZ_string.h" typedef enum { IZ_LOG_CATEGORY_INPUT, @@ -29,9 +31,14 @@ typedef enum { IZ_LOG_CATEGORY_GENERIC, } IZ_LogCategory; -void IZ_LogError(const char* context, const char* fmt, ...); -void IZ_LogInfo(IZ_LogCategory category, const char* context, const char* fmt, ...); -void IZ_LogWarn(bool is_critical, const char* context, const char* fmt, ...); -void IZ_Log(const char* context, const char* fmt, ...); +static FILE* stdout_dest; +static FILE* stderr_dest; + +void IZ_LogInitialize(const char*); +void IZ_LogError(const char*, const char*, ...); +void IZ_LogInfo(IZ_LogCategory, const char*, const char*, ...); +void IZ_LogWarn(bool, const char*, const char*, ...); +void IZ_Log(const char*, const char*, ...); +void IZ_LogTeardown(void); #endif diff --git a/src/packages/server/IZ_app.c b/src/packages/server/IZ_app.c index 7b7290c..ac807c6 100644 --- a/src/packages/server/IZ_app.c +++ b/src/packages/server/IZ_app.c @@ -12,6 +12,8 @@ IZ_ProcedureResult IZ_AppInitialize(IZ_App *app, u8 argc, const char **argv) { IZ_memset(app, 0, sizeof(IZ_App)); signal(SIGINT, IZ_AppHandleSignal); + IZ_LogInitialize("server"); + // IZ_LogInterceptWSMessages(app->config.log_level); IZ_LogInterceptWSMessages(LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE); @@ -38,7 +40,7 @@ IZ_ProcedureResult IZ_AppInitialize(IZ_App *app, u8 argc, const char **argv) { void IZ_AppTeardown(IZ_App* app) { IZ_RepoTeardown(&app->repo_state); IZ_WSServerTeardown(&app->net_state.binding); - lwsl_user("Server closed. Bye!\n"); + IZ_LogTeardown(); } void IZ_AppPrintHelpOptions() { diff --git a/src/packages/timer/IZ_timer.c b/src/packages/timer/IZ_timer.c index a43ffdf..dc7475b 100644 --- a/src/packages/timer/IZ_timer.c +++ b/src/packages/timer/IZ_timer.c @@ -67,3 +67,20 @@ char* IZ_TimerNow() { sprintf(buffer, "%s.%03dZ", formatted, milliseconds < 0 ? 0 : milliseconds % 1000); return buffer; } + +/** + * Gets the formatted time in the current instant that can be safely added in file paths. + * @return The formatted time in the current instant. + */ +char* IZ_TimerNowPathSafe() { + struct timespec t; + clock_gettime(CLOCK_REALTIME, &t); + static char buffer[32]; + unsigned int seconds = t.tv_sec; + unsigned int milliseconds = t.tv_nsec / 1000000; + static char formatted[32]; + time_t current_time = seconds; + strftime(formatted, sizeof(formatted), "%Y%m%d%H%M%S", gmtime(¤t_time)); + sprintf(buffer, "%s%03d", formatted, milliseconds < 0 ? 0 : milliseconds % 1000); + return buffer; +} diff --git a/src/packages/timer/IZ_timer.h b/src/packages/timer/IZ_timer.h index c71fe76..ef40ecd 100644 --- a/src/packages/timer/IZ_timer.h +++ b/src/packages/timer/IZ_timer.h @@ -17,26 +17,32 @@ static time_t IZ_TIMER_START_TIMESTAMP = 0; * Gets the start timestamp. * @sa IZ_TIMER_START_TIMESTAMP */ -void IZ_TimerStart(); +void IZ_TimerStart(void); /** * Gets the number of microseconds since the application timer has been started. * @return The number of microseconds. * @sa IZ_TimerElapsed() */ -unsigned int IZ_TimerElapsedRaw(); +unsigned int IZ_TimerElapsedRaw(void); /** * Gets the formatted elapsed time since the application timer has been started. * @return The formatted elapsed time. * @sa IZ_TimerElapsedRaw() */ -char* IZ_TimerElapsed(); +char* IZ_TimerElapsed(void); /** * Gets the formatted time in the current instant. * @return The formatted time in the current instant. */ -char* IZ_TimerNow(); +char* IZ_TimerNow(void); + +/** + * Gets the formatted time in the current instant that can be safely added in file paths. + * @return The formatted time in the current instant. + */ +char* IZ_TimerNowPathSafe(void); #endif