From b9039f161c57aa73f490b59a7f920ea3e062539b Mon Sep 17 00:00:00 2001 From: Alexander Popov Date: Thu, 30 May 2024 22:58:07 +0300 Subject: [PATCH] added -DLOG_DONT_CODE --- .clang-format | 4 +++ .screenshot.png | Bin 0 -> 36372 bytes LICENSE | 1 + README.md | 13 +++----- src/log.c | 85 +++++++++++++++++++++++++----------------------- src/log.h | 7 ++-- 6 files changed, 59 insertions(+), 51 deletions(-) create mode 100644 .clang-format create mode 100644 .screenshot.png diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..bb26014 --- /dev/null +++ b/.clang-format @@ -0,0 +1,4 @@ +Language: Cpp +BasedOnStyle: LLVM +IndentWidth: 2 +ColumnLimit: 80 diff --git a/.screenshot.png b/.screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..44f42edd68be5306becfc65254946100dbab70e3 GIT binary patch literal 36372 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 J=kaNM_&*EW0viAT literal 0 HcmV?d00001 diff --git a/LICENSE b/LICENSE index 39ddd05..10b55e1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,5 @@ Copyright (c) 2020 rxi +Copyright (c) 2024 iiiypuk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/README.md b/README.md index a8756e9..72479ef 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,7 @@ # log.c A simple logging library implemented in C99 -![screenshot](https://cloud.githubusercontent.com/assets/3920290/23831970/a2415e96-0723-11e7-9886-f8f5d2de60fe.png) - +![Screenshot](./.screenshot.png) ## Usage **[log.c](src/log.c?raw=1)** and **[log.h](src/log.h?raw=1)** should be dropped @@ -30,19 +29,16 @@ Resulting in a line with the given format printed to stderr: 20:18:26 TRACE src/main.c:11: Hello world ``` - #### log_set_quiet(bool enable) Quiet-mode can be enabled by passing `true` to the `log_set_quiet()` function. While this mode is enabled the library will not output anything to `stderr`, but will continue to write to files and callbacks if any are set. - #### log_set_level(int level) The current logging level can be set by using the `log_set_level()` function. All logs below the given level will not be written to `stderr`. By default the level is `LOG_TRACE`, such that nothing is ignored. - #### log_add_fp(FILE *fp, int level) One or more file pointers where the log will be written can be provided to the library by using the `log_add_fp()` function. The data written to the file @@ -55,28 +51,27 @@ output is of the following format: Any messages below the given `level` are ignored. If the library failed to add a file pointer a value less-than-zero is returned. - #### log_add_callback(log_LogFn fn, void *udata, int level) One or more callback functions which are called with the log data can be provided to the library by using the `log_add_callback()` function. A callback function is passed a `log_Event` structure containing the `line` number, `filename`, `fmt` string, `va` printf va\_list, `level` and the given `udata`. - #### log_set_lock(log_LockFn fn, void *udata) If the log will be written to from multiple threads a lock function can be set. The function is passed the boolean `true` if the lock should be acquired or `false` if the lock should be released and the given `udata` value. - #### const char* log_level_string(int level) Returns the name of the given log level as a string. - #### LOG_USE_COLOR If the library is compiled with `-DLOG_USE_COLOR` ANSI color escape codes will be used when printing. +#### LOG_DONT_CODE +If the library is compiled with `-DLOG_DONT_CODE`, then the source code file name +and line number will be removed from the output. ## License This library is free software; you can redistribute it and/or modify it under diff --git a/src/log.c b/src/log.c index 1a7626e..262a0b8 100644 --- a/src/log.c +++ b/src/log.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2020 rxi + * Copyright (c) 2024 iiiypuk * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -38,7 +39,7 @@ static struct { Callback callbacks[MAX_CALLBACKS]; } L; - +// clang-format off static const char *level_strings[] = { "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL" }; @@ -48,86 +49,91 @@ static const char *level_colors[] = { "\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m" }; #endif +// clang-format on +#ifndef LOG_DONT_CODE static void stdout_callback(log_Event *ev) { char buf[16]; buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->time)] = '\0'; #ifdef LOG_USE_COLOR - fprintf( - ev->udata, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", - buf, level_colors[ev->level], level_strings[ev->level], - ev->file, ev->line); -#else - fprintf( - ev->udata, "%s %-5s %s:%d: ", - buf, level_strings[ev->level], ev->file, ev->line); -#endif + fprintf(ev->udata, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", buf, + level_colors[ev->level], level_strings[ev->level], ev->file, + ev->line); +#else // LOG_USE_COLOR + fprintf(ev->udata, "%s %-5s %s:%d: ", buf, level_strings[ev->level], ev->file, + ev->line); +#endif // LOG_USE_COLOR vfprintf(ev->udata, ev->fmt, ev->ap); fprintf(ev->udata, "\n"); fflush(ev->udata); } +#else // LOG_DONT_CODE + +static void stdout_callback(log_Event *ev) { + char buf[16]; + buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->time)] = '\0'; +#ifdef LOG_USE_COLOR + fprintf(ev->udata, "%s %s%-5s\x1b[0m ", buf, level_colors[ev->level], + level_strings[ev->level]); +#else // LOG_USE_COLOR + fprintf(ev->udata, "%s %-5s ", buf, level_strings[ev->level]); +#endif // LOG_USE_COLOR + vfprintf(ev->udata, ev->fmt, ev->ap); + fprintf(ev->udata, "\n"); + fflush(ev->udata); +} + +#endif // LOG_DONT_CODE static void file_callback(log_Event *ev) { char buf[64]; buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0'; - fprintf( - ev->udata, "%s %-5s %s:%d: ", - buf, level_strings[ev->level], ev->file, ev->line); + fprintf(ev->udata, "%s %-5s %s:%d: ", buf, level_strings[ev->level], ev->file, + ev->line); vfprintf(ev->udata, ev->fmt, ev->ap); fprintf(ev->udata, "\n"); fflush(ev->udata); } - -static void lock(void) { - if (L.lock) { L.lock(true, L.udata); } +static void lock(void) { + if (L.lock) { + L.lock(true, L.udata); + } } - static void unlock(void) { - if (L.lock) { L.lock(false, L.udata); } -} - - -const char* log_level_string(int level) { - return level_strings[level]; + if (L.lock) { + L.lock(false, L.udata); + } } +const char *log_level_string(int level) { return level_strings[level]; } void log_set_lock(log_LockFn fn, void *udata) { L.lock = fn; L.udata = udata; } +void log_set_level(int level) { L.level = level; } -void log_set_level(int level) { - L.level = level; -} - - -void log_set_quiet(bool enable) { - L.quiet = enable; -} - +void log_set_quiet(bool enable) { L.quiet = enable; } int log_add_callback(log_LogFn fn, void *udata, int level) { for (int i = 0; i < MAX_CALLBACKS; i++) { if (!L.callbacks[i].fn) { - L.callbacks[i] = (Callback) { fn, udata, level }; + L.callbacks[i] = (Callback){fn, udata, level}; return 0; } } return -1; } - int log_add_fp(FILE *fp, int level) { return log_add_callback(file_callback, fp, level); } - static void init_event(log_Event *ev, void *udata) { if (!ev->time) { time_t t = time(NULL); @@ -136,13 +142,12 @@ static void init_event(log_Event *ev, void *udata) { ev->udata = udata; } - void log_log(int level, const char *file, int line, const char *fmt, ...) { log_Event ev = { - .fmt = fmt, - .file = file, - .line = line, - .level = level, + .fmt = fmt, + .file = file, + .line = line, + .level = level, }; lock(); diff --git a/src/log.h b/src/log.h index b1fae24..1df1a73 100644 --- a/src/log.h +++ b/src/log.h @@ -1,5 +1,6 @@ /** * Copyright (c) 2020 rxi + * Copyright (c) 2024 iiiypuk * * This library is free software; you can redistribute it and/or modify it * under the terms of the MIT license. See `log.c` for details. @@ -8,9 +9,9 @@ #ifndef LOG_H #define LOG_H -#include #include #include +#include #include #define LOG_VERSION "0.1.0" @@ -30,14 +31,16 @@ typedef void (*log_LockFn)(bool lock, void *udata); enum { LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL }; +// clang-format off #define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__) #define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) #define log_info(...) log_log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__) #define log_warn(...) log_log(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__) #define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) #define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__) +// clang-format on -const char* log_level_string(int level); +const char *log_level_string(int level); void log_set_lock(log_LockFn fn, void *udata); void log_set_level(int level); void log_set_quiet(bool enable);