diff --git a/LICENSE b/LICENSE index db81fa7..1b188c1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2015 Sun Dro +Copyright (c) 2015-2020 Sun Dro (f4tb0y@protonmail.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..670b352 --- /dev/null +++ b/Makefile @@ -0,0 +1,39 @@ +#################################### +# Automatically generated by SMake # +# https://github.com/kala13x/smake # +#################################### + +CFLAGS = -g -O2 -Wall -Isrc +LIBS = -lpthread +NAME = libslog.a +ODIR = lib +OBJ = o + +ifeq ($(UNAME_S),Darwin) +CFLAGS += -DDARWIN +endif + +OBJS = slog.$(OBJ) +OBJECTS = $(patsubst %,$(ODIR)/%,$(OBJS)) +HEADERS = /usr/local/include +INSTALL = /usr/local/lib +VPATH = src + +.c.$(OBJ): + @test -d $(ODIR) || mkdir $(ODIR) + $(CC) $(CFLAGS) -c -o $(ODIR)/$@ $< $(LIBS) + +$(NAME):$(OBJS) + $(AR) rcs -o $(ODIR)/$(NAME) $(OBJECTS) + @test -d $(BUILD) || mkdir $(BUILD) + +.PHONY: install +install: + @test -d $(INSTALL) || mkdir $(INSTALL) + @install -m 0755 $(ODIR)/$(NAME) $(INSTALL)/ + @test -d $(HEADERS) || mkdir $(HEADERS) + @install -m 0755 $(VPATH)/*.h $(HEADERS)/ + +.PHONY: clean +clean: + $(RM) $(ODIR)/$(NAME) $(OBJECTS) diff --git a/README.md b/README.md index 6db41d3..4539a29 100644 --- a/README.md +++ b/README.md @@ -1,193 +1,264 @@ -## slog Logging Library - 1.6 build 1 -Slog is simple and thread safe logging library for C/C++. Software is written for educational purposes and is distributed in the hope that it will be useful for anyone interested in this field. +## slog Logging Library - 1.8 build 22 +SLog is simple and thread safe logging library for C/C++. Software is written for educational purposes and is distributed in the hope that it will be useful for anyone interested in this field. ### Installation -Installation is possible with makefile +Installation is possible with `Makefile` ``` git clone https://github.com/kala13x/slog.git -cd slog/src +cd slog make sudo make install ``` -On Darwin/Apple Platform compile with -``` -make -f Makefile.darwin -``` - ### Usage -If you want to use slog in your C/C++ application, include `slog.h` header in your source file and link slog library with `-lslog` linker flag while compiling your project. See examples directory for more informations. +If you want to use slog in your C/C++ application, include `slog.h` header in your source file and link slog library with `-lslog` linker flag while compiling your project. See example directory for more informations. ### Simple API At first you should initialize slog ```c -slog_init("logfile", "slog.cfg", 1, 0); +int nFlags = SLOG_NOTAG | SLOG_ERROR; +int nFlags |= SLOG_WARN | SLOG_FATAL; + +/* Setting SLOG_FLAGS_ALL will activate all logging levels */ +// nFlags = SLOG_FLAGS_ALL; + +slog_init("logfile", nFlags, 0); +``` + + - First argument is file name where log will be saved. + - Second argument is logging flags which are allowed to print. + - Third argument is thread safety flag *(1 enabled, 0 disabled)*. + +If thread safety flag is greater than zero, function initializes mutex and evety other call of any slog function is protected by mutex locks. + +With the above slog initialization example only errors, warnings and not tagged messages will be printed because there is no other flags activated. +You can also activate or deactivate any logging level after slog initialization with `slog_enable()` and `slog_disable()` functions. + +```c +/* Enable all logging levels */ +slog_enable(SLOG_FLAGS_ALL); + +/* Disable trace level (trace logs will not be printed anymore) */ +slog_disable(SLOG_TRACE); + +/* Enable trace messages again */ +slog_enable(SLOG_TRACE); + +/* Disable all logging levels */ +slog_disable(SLOG_FLAGS_ALL); +``` + +You must deinitialize slog only if the thread safety flag is greater than zero (nTdSafe > 0) while initialization. +```c +slog_destroy(); ``` - - First argument is file name where log will be saved. - - Second argument is config file path to be parsed *(see the next section for more informations about the config file)*. - - Third argument is max log level, if you will not initialize slog, it will only print messages with log level 0. - - Fourth argument is thread safety flag *(1 enabled, 0 disabled)*. We recommend to always enable this flag. +Function destroys the mutex attribute and sets thread safety flag to zero. + +### Configuration -**Note:** Although, you can run slog without initialization, we recommend this action. If you don't initialize slog, you'll only be able to export log messages in console. Also the default config values will be used. +Since version 1.8.* config file is not supported anymore but there is a way to change configuration parameters of already initialized slog. +Parameter | Type | Default | Description +-------------|-------------------|----------------|------------------------------- +sFileName | char array | "slog" | Output file name for logs. +sFilePath | char array | "./" | Output file path for logs. +eColorFormat | SLOG_COLOR_FMT_E | SLOG_COLOR_TAG | Output color format control. +nTraceTid | uint8_t | 0 (disabled) | Trace thread ID and display in output +nToScreen | uint8_t | 1 | Enable screen logging. +nToFile | uint8_t | 0 (disabled) | Enable file logging. +nFlush | uint8_t | 0 (disabled) | Flush stdout after screen log. +nFlags | uint16_t | 0 (no logs) | Allowed log level flags. + +Any of those parameters above can be changed at the runtime with the `slog_config_set()` function. + +Example: +```c +SLogConfig slgCfg; + +/* Setup configuration parameters */ +slgCfg.eColorFormat = SLOG_COLOR_TAG; +strcpy(slgCfg.sFileName, "myproject"); +strcpy(slgCfg.sFilePath, "./logs/"); +slgCfg.nTraceTid = 1; +slgCfg.nToScreen = 1; +slgCfg.nToFile = 0; +slgCfg.nFlush = 1; +slgCfg.nFlags = SLOG_FLAGS_ALL; + +/* Tread safe call to update slog configuration */ +slog_config_set(&slgCfg); +``` -### Config file +If you want to change only few parameters without resetting other ones, you can thread safe read current working configuration and update only needed parameters. -More configuration options can be parsed from config file. +```c +SLogConfig slgCfg; +slog_config_get(&slgCfg); -If the confing file is `NULL`, the default values are set. -Values from the config file override the defaults. +/* Update needed parameters */ +slgCfg.nTraceTid = 1; +slgCfg.nToFile = 1; -Example of config file: +/* Tread safe call to update slog configuration */ +slog_config_set(&slgCfg); ``` -LOGLEVEL 1 -LOGTOFILE 1 -PRETTYLOG 0 -FILESTAMP 1 -LOGFILELEVEL 3 + +### Coloring +There is a color control possibility to colorize whole line, just tag or disable coloring at all. +```c +SLogConfig slgCfg; +slog_config_get(&slgCfg); + +/* Colorize tags only */ +slgCfg.eColorFormat = SLOG_COLOR_TAG; +slog_config_set(&slgCfg); +slog_debug("Message with colorized tag"); + +/* Colorize full line */ +slgCfg.eColorFormat = SLOG_COLOR_FULL; +slog_config_set(&slgCfg); +slog_debug("Message with full line color"); + +/* Disable coloring at all */ +slgCfg.eColorFormat = SLOG_COLOR_DISABLE; +slog_config_set(&slgCfg); +slog_debug("Message without coloring"); ``` -Flag | Default | Internal Name | Description --------------|---------|----------------|------------ -LOGLEVEL | lvl* | slg.level | Max level to print to `stdout`. -LOGTOFILE | 0 | slg.to_file | If 0 will not write to file. -PRETTYLOG | 0 | slg.pretty | If 1 will output with color. -FILESTAMP | 1 | slg.filestamp | If 1 will add date to log name. -LOGFILELEVEL | lvl** | flvl | slg.file_level | Level required to write to file. -**Note:** `LOGFILELEVEL` and `LOGLEVEL` are completely independent of each other. +### Thread tracing +You can trace thread IDs and display in output if additional information is needed while debugging threads. + +Here is an example: +```c +SLogConfig slgCfg; +slog_config_get(&slgCfg); +slgCfg.nTraceTid = 1; +slog_config_set(&slgCfg); + +slog_debug("Message with thread id"); +``` -**`LOGLEVEL` is passed as third argument in `slog_init()`.* +With expected output to be: +``` +(15203) 2017.01.22-19:03:17.03 - Message with thread id. +``` +where `15203` is thread identifier from which the message was printed. ### Logging flags Slog has its logging flags to print something with status code. +- `SLOG_NOTAG` - `SLOG_LIVE` - `SLOG_INFO` - `SLOG_WARN` - `SLOG_DEBUG` +- `SLOG_TRACE` - `SLOG_ERROR` - `SLOG_FATAL` -- `SLOG_PANIC` -- `SLOG_NONE` ### Print and log something -Here is an example on how use slog. +Here is an example on how use slog: +```c +slog("Simple test message"); +``` + +Slog ends strings automatically with new line character `\n`. If you want to display output without adding new line character, you must use `slogwn()` function. ```c -slog(0, SLOG_LIVE, "Test message with level 0"); +slogwn("Simple test message without new line character"); ``` -- First argument is log level. -- Second argument is logging flag. -- Third is message to print and/or save. Slog ends strings automatically with new line character `\n`. + +You can use old way logging function with a bit more control of parameters +```c +slog_print(SLOG_DEBUG, 0, "Simple test message without new line character"); +``` + + - First argument is a log level flag of current message. + - Second argument is a flag to add new line character at the end of the output. + - Third argument is a formated string which will be displayed in the output. *Output, taken from example directory:* -![alt tag](https://github.com/GeorgeGkas/slog/blob/version_1.5/slog.png) +![alt tag](https://github.com/kala13x/slog/blob/master/example/slog.png) #### UPDATE From version 1.5 we provide a cleaner option to generate errors without the need to provide the flag parameter. -We defined macros based on the warning flags. +Here are defined macros based on the logging flags. -- `slog_none()` +- `slog()` +- `slogwn()` - `slog_live()` - `slog_info()` - `slog_warn()` - `slog_debug()` - `slog_error()` +- `slog_trace()` - `slog_fatal()` -- `slog_panic()` -Each macro take the following parameters: - - 1. The log level. - 2. A formated string. Format tags prototype follows the same rules as the C standard library function `printf()`. - 3. Additional arguments. There should be the same number of these arguments as the number of `%-tags` that expect a value. - -Bellow we provide an example that logs a debug message: +Each macro takes a formated string. Format tags prototype follows the same rules as the C standard library function `printf()`. +Here is an example that logs a debug message: ```c -slog_debug(0, "The %s contains between %d and %d billion stars and at least %d billion planets. ", "Milky Way", 200, 400, 100); +slog_debug("The %s contains between %d and %d billion stars and at least %d billion planets. ", "Milky Way", 200, 400, 100); ``` -In addition, we added the option to print the corresponding file name and line number where a slog macro was called. This rule follows the macros which relate to a critical flag, and shown bellow: +In addition, we added the option to print the corresponding file name and line number where a slog macro was called. This rule follows the macros which relate to a critical or trace flag, and shown bellow: -- `slog_warn()` -- `slog_error()` +- `slog_trace()` - `slog_fatal()` -- `slog_panic()` Basic example: ```c /* Log and print something fatal. */ -slog_fatal(0, "Fatal message. We fell into dead zone."); +slog_trace("Trace message trows source location."); ``` -With expected output to be: - - 2017.01.22-19:03:17.03 - [FATAL] -- Fatal message. We fell into dead zone. - -### Colorize output -You can colorize strings with `strclr()` function. Usage is very simple, first argument is color value and second argument is string which we want to colorize. -Color values are: - -- `CLR_NORMAL` -- `CLR_RED` -- `CLR_GREEN` -- `CLR_YELLOW` -- `CLR_BLUE` -- `CLR_NAGENTA` -- `CLR_CYAN` -- `CLR_WHITE` -- `CLR_RESET` +With expected output to be: +``` +2017.01.22-19:03:17.03 - [example.c:71] Trace message trows source location. +``` -For example, if we want to print something with red color, code will be something like that: +You can also trace source location wothout any output message: ```c -char *ret = strclr(CLR_NAGENTA, "Test string"); -slog(0, SLOG_NONE, "This is colorized string: %s", ret); +slog_trace(); ``` -### Get date -You can check and get system date with `get_slog_date()` function. Argument is pointer of SlogDate structure. For example if you want to print system date which uses slog, code will be something like that: -```c -SlogDate date; -slog_get_date(&date); +With expected output to be: ``` -Values will be saved with 24h format at SlogDate structure members. -```c -date.year; -date.mon; -date.day; -date.hour; -date.min; -date.sec; +2017.01.22-19:03:17.03 - [example.c:72] ``` ### Version -`slog_version()` is a function which returns version of slog. If argument is 1, it returns only version and build number. Otherwise it returns full version such as Build number, build name and etc. +`slog_version()` is a function which returns version of slog. If argument is 1, it returns only version and build number. Otherwise it returns full version such as Build number, build date and etc. Usage: ```c -printf("slog Version: %s", slog_version(0)); +printf("slog Version: %s", slog_version(1)); ``` + Output will be something like that: ``` slog Version: 1.5 build 1 (Jan 22 2017) ``` ### Output -Here is example output strings of slog -``` -2017.01.22-19:03:17.03 - [INFO] Loading logger config from: slog.cfg -2017.01.22-19:03:17.03 - [LIVE] Test message with level 0 -2017.01.22-19:03:17.03 - [WARN] -- Warn message with level 1 -2017.01.22-19:03:17.03 - [INFO] Info message with level 2 -2017.01.22-19:03:17.03 - [LIVE] Test message with level 3 -2017.01.22-19:03:17.03 - [DEBUG] Debug message with char argument: test string -2017.01.22-19:03:17.03 - [ERROR] -- Error message with int argument: 69 -2017.01.22-19:03:17.03 - [FATAL] -- Fatal message. We fell into dead zone. -2017.01.22-19:03:17.03 - [PANIC] -- Panic here! We don't have tim.... -2017.01.22-19:03:17.03 - [TEST] This is our own colorized string - +Here is example output messages of slog: +``` +2020.12.13-19:41:41.27 - Simple message without anything +2020.12.13-19:41:41.27 - Simple message with our own new line character +2020.12.13-19:41:41.27 - Old way printed debug message with our own new line character +2020.12.13-19:41:41.27 - Old way printed error message with auto new line character +2020.12.13-19:41:41.27 - Warning message without variable +2020.12.13-19:41:41.27 - Info message with string variable: test string +2020.12.13-19:41:41.27 - Note message with integer variable: 69 +(15203) 2020.12.13-19:41:41.27 - Debug message with enabled thread id tracing +(15203) 2020.12.13-19:41:41.27 - Error message with errno string: Success +(15203) 2020.12.13-19:41:41.27 - Debug message in the file with full line color enabled +(15203) 2020.12.13-19:41:41.27 - [example.c:95] Trace message throws source location +(15203) 2020.12.13-19:41:41.27 - [example.c:98] Fatal message also throws source location +(15203) 2020.12.13-19:41:41.28 - Disabled output coloring +(15203) 2020.12.13-19:41:41.28 - [example.c:108] +(15203) 2020.12.13-19:41:41.28 - Above we traced source location without output message ``` diff --git a/example/Makefile b/example/Makefile index 181e336..74f949d 100644 --- a/example/Makefile +++ b/example/Makefile @@ -1,12 +1,24 @@ -LIB = -lslog -lpthread -lrt +#################################### +# Automatically generated by SMake # +# https://github.com/kala13x/smake # +#################################### + CFLAGS = -g -O2 -Wall +LIBS = -lslog -lpthread +NAME = example +ODIR = . +OBJ = o -example: example.c $(OBJ) - gcc $(CFLAGS) -o example example.c $(LIB) $(OBJ) +OBJS = example.$(OBJ) +OBJECTS = $(patsubst %,$(ODIR)/%,$(OBJS)) -example.o: example.h +.c.$(OBJ): + @test -d $(ODIR) || mkdir $(ODIR) + $(CC) $(CFLAGS) -c -o $(ODIR)/$@ $< $(LIBS) -.PHONY: clean +$(NAME):$(OBJS) + $(CC) $(CFLAGS) -o $(ODIR)/$(NAME) $(OBJECTS) $(LIBS) +.PHONY: clean clean: - $(RM) example *.log $(OBJ) + $(RM) $(ODIR)/$(NAME) $(OBJECTS) diff --git a/example/example.c b/example/example.c index 9c24ade..3845e7b 100644 --- a/example/example.c +++ b/example/example.c @@ -1,75 +1,113 @@ /* - * examples/slog.c - * - * Copyleft (C) 2015 Sun Dro (a.k.a. kala13x) + * example/example.c * - * Example file of useing slog library. + * 2015 - 2020 (c) Sun Dro (f4tb0y@protonmail.com) + * + * This source file is a part of the "slog" project + * Read LICENSE file for more details about copyright + * + * Implementation example of SLog library */ - #include #include +#include #include void greet() { /* Get and print slog version */ printf("=========================================\n"); - printf("slog Version: %s\n", slog_version(0)); + printf("SLog Version: %s\n", slog_version(0)); printf("=========================================\n"); } int main() { /* Used variables */ - char char_arg[32]; - strcpy(char_arg, "test string"); - int int_arg = 69; + SLogConfig slgCfg; + int nInteger = 69; + char sBuffer[12]; + + strcpy(sBuffer, "test string"); + uint16_t nLogFlags = SLOG_ERROR | SLOG_NOTAG; /* Greet users */ greet(); - /* Initialize slog with default parameters */ - slog_init("example", "slog.cfg", 3, 0); + /* Initialize slog and allow only error and not tagged output */ + slog_init("example", nLogFlags, 0); + + /* Just simple log without anything (color, tag, thread id)*/ + slog("Simple message without anything"); - /* Log and print something with level 0 */ - slog(0, SLOG_LIVE, "Test message with level 0"); + /* Simple log without adding new line character at the end */ + slogwn("Simple message with our own new line character\n"); - /* Log and print something with level 1 */ - slog(1, SLOG_WARN, "Warn message with level 1"); + /* Enable all logging flags */ + slog_enable(SLOG_FLAGS_ALL); - /* Log and print something with level 2 */ - slog(2, SLOG_INFO, "Info message with level 2"); + /* Old way logging function with debug tag and disabled new line from argument */ + slog_print(SLOG_DEBUG, 0, "Old way printed debug message with our own new line character\n"); - /* Log and print something with level 3 */ - slog(3, SLOG_LIVE, "Test message with level 3"); + /* Old way logging function with error tag and enabled new line from argument */ + slog_print(SLOG_ERROR, 1, "Old way printed error message with %s", "auto new line character"); - /* Log and print something with char argument */ - slog(0, SLOG_DEBUG, "Debug message with char argument: %s", char_arg); + /* Warning message */ + slog_warn("Warning message without variable"); - /* Log and print something with int argument */ - slog(0, SLOG_ERROR, "Error message with int argument: %d", int_arg); + /* Info message with char*/ + slog_info("Info message with string variable: %s", sBuffer); - /* Test log with higher level than log max value - * This will never be printed while log level argument is higher than max log level */ - slog(4, SLOG_NONE, "[LIVE] Test log with higher level than log max value"); + /* Note message */ + slog_note("Note message with integer variable: %d", nInteger); - /* On the fly change parameters (enable file logger) */ - SlogConfig slgCfg; + /* Trace thread id and print in output */ slog_config_get(&slgCfg); + slgCfg.nTraceTid = 1; + slog_config_set(&slgCfg); + + /* Debug message with string and integer */ + slog_debug("Debug message with enabled thread id tracing"); + + /* Error message with errno string (in this case must be 'Success')*/ + slog_error("Error message with errno string: %s", strerror(errno)); + + /* Disable trace tag */ + slog_disable(SLOG_TRACE); + + /* This will never be printed while SLOG_TRACE is disabled by slog_disable() function */ + slog_trace("Test log with disabled tag"); + + /* Enable file logger and color the whole log output instead of coloring only tags*/ + slog_config_get(&slgCfg); + slgCfg.eColorFormat = SLOG_COLOR_FULL; slgCfg.nToFile = 1; slog_config_set(&slgCfg); /* Print message and save log in the file */ - slog(0, SLOG_DEBUG, "Debug message in the file with int argument: %d", int_arg); + slog_debug("Debug message in the file with full line color enabled"); + + /* Enable trace tag */ + slog_enable(SLOG_TRACE); - /* On the fly change parameters (enable file logger) */ + /* We can trace function and line number with and without output message */ + slog_trace("Trace message throws source location"); + + /* Fatal error message */ + slog_fatal("Fatal message also throws source location"); + + /* Disable output coloring*/ slog_config_get(&slgCfg); - slgCfg.nPretty = 1; + slgCfg.eColorFormat = SLOG_COLOR_DISABLE; slog_config_set(&slgCfg); - /* Print message and save log in the file without colorization*/ - slog(0, SLOG_DEBUG, "Debug message with disabled pretty log"); + slog_debug("Disabled output coloring"); + + /* Just throw source location without output message */ + slog_trace(); + + slog_debug("Above we traced source location without output message"); return 0; } diff --git a/example/run.sh b/example/run.sh new file mode 100755 index 0000000..1158fd3 --- /dev/null +++ b/example/run.sh @@ -0,0 +1,8 @@ +make clean +make + +valgrind --leak-check=full \ + --show-leak-kinds=all \ + --show-error-list=yes \ + --track-origins=yes \ + ./example diff --git a/example/slog.cfg b/example/slog.cfg deleted file mode 100644 index 66a7675..0000000 --- a/example/slog.cfg +++ /dev/null @@ -1,5 +0,0 @@ -LOGLEVEL 1 -LOGFILELEVEL 3 -LOGTOFILE 1 -PRETTYLOG 0 -LOGSTAMP 0 diff --git a/example/slog.png b/example/slog.png new file mode 100644 index 0000000..6370217 Binary files /dev/null and b/example/slog.png differ diff --git a/slog.png b/slog.png deleted file mode 100644 index e856474..0000000 Binary files a/slog.png and /dev/null differ diff --git a/src/Makefile b/src/Makefile deleted file mode 100644 index 5babd37..0000000 --- a/src/Makefile +++ /dev/null @@ -1,27 +0,0 @@ -CFLAGS = -g -O2 -Wall -lpthread -LIB = -lrt -OBJS = slog.o - -LIBINSTALL = /usr/local/lib -HEADINSTALL = /usr/local/include - -.c.o: - $(CC) $(CFLAGS) -c $< $(LIB) - -libslog.a: $(OBJS) - $(AR) rcs libslog.a $(OBJS) - @echo [-] Syncing static library - sync - -install: - @test -d $(LIBINSTALL) || mkdir $(LIBINSTALL) - @test -d $(HEADINSTALL) || mkdir $(HEADINSTALL) - @install -m 0664 libslog.a $(LIBINSTALL)/ - @install -m 0664 slog.h $(HEADINSTALL)/ - @echo [-] Done - -slog.o: slog.h - -.PHONY: clean -clean: - $(RM) libslog.a $(OBJS) diff --git a/src/Makefile.darwin b/src/Makefile.darwin deleted file mode 100644 index d516a83..0000000 --- a/src/Makefile.darwin +++ /dev/null @@ -1,27 +0,0 @@ -CFLAGS = -g -O2 -Wall -lpthread -DDARWIN -LIB = -lrt -OBJS = slog.o - -LIBINSTALL = /usr/local/lib -HEADINSTALL = /usr/local/include - -.c.o: - $(CC) $(CFLAGS) -c $< $(LIB) - -libslog.a: $(OBJS) - $(AR) rcs libslog.a $(OBJS) - @echo [-] Syncing static library - sync - -install: - @test -d $(LIBINSTALL) || mkdir $(LIBINSTALL) - @test -d $(HEADINSTALL) || mkdir $(HEADINSTALL) - @install -m 0664 libslog.a $(LIBINSTALL)/ - @install -m 0664 slog.h $(HEADINSTALL)/ - @echo [-] Done - -slog.o: slog.h - -.PHONY: clean -clean: - $(RM) libslog.a $(OBJS) diff --git a/src/slog.c b/src/slog.c index 0346e18..f231db7 100644 --- a/src/slog.c +++ b/src/slog.c @@ -1,8 +1,7 @@ /* * The MIT License (MIT) - * - * Copyleft (C) 2015 - 2018 Sun Dro (a.k.a. kala13x) - * Copyleft (C) 2017 George G. Gkasdrogkas (a.k.a. GeorgeGkas) + * + * Copyleft (C) 2015-2020 Sun Dro (f4tb0y@protonmail.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,350 +23,292 @@ */ #include +#include +#include #include #include -#include #include #include #include #include #include "slog.h" -/* Max size of string */ -#define MAXMSG 8196 -#define BIGSTR 4098 - -static SlogConfig g_slogCfg; -static SlogTag g_SlogTags[] = +#ifndef DARWIN +#include +#endif +#include + +#ifndef PTHREAD_MUTEX_RECURSIVE +#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP +#endif + +typedef struct SLogDate_ { + uint16_t nYear; + uint8_t nMonth; + uint8_t nDay; + uint8_t nHour; + uint8_t nMin; + uint8_t nSec; + uint8_t nUsec; +} SLogDate; + +typedef struct SLogContext_ { + unsigned int nTdSafe:1; + pthread_mutex_t mutex; + SLogConfig slogConfig; + SLogDate slogDate; +} SLogContext; + +static SLogContext g_slog; + +static void slog_sync_init(SLogContext *pSlog) { - { 0, "NONE", NULL }, - { 1, "LIVE", CLR_NORMAL }, - { 2, "INFO", CLR_GREEN }, - { 3, "WARN", CLR_YELLOW }, - { 4, "DEBUG", CLR_BLUE }, - { 5, "ERROR", CLR_RED}, - { 6, "FATAL", CLR_RED }, - { 7, "PANIC", CLR_WHITE } -}; - -void slog_sync_lock() -{ - if (g_slogCfg.nTdSafe) + if (!pSlog->nTdSafe) return; + pthread_mutexattr_t mutexAttr; + + if (pthread_mutexattr_init(&mutexAttr) || + pthread_mutexattr_settype(&mutexAttr, PTHREAD_MUTEX_RECURSIVE) || + pthread_mutex_init(&pSlog->mutex, &mutexAttr) || + pthread_mutexattr_destroy(&mutexAttr)) { - if (pthread_mutex_lock(&g_slogCfg.slogLock)) - { - printf("[ERROR] Slog can not lock mutex: %d\n", errno); - exit(EXIT_FAILURE); - } + printf("<%s:%d> %s: [ERROR] Can not initialize mutex: %d\n", + __FILE__, __LINE__, __FUNCTION__, errno); + + exit(EXIT_FAILURE); } } -void slog_sync_unlock() +static void slog_lock(SLogContext *pSlog) { - if (g_slogCfg.nTdSafe) + if (pSlog->nTdSafe && pthread_mutex_lock(&pSlog->mutex)) { - if (pthread_mutex_unlock(&g_slogCfg.slogLock)) - { - printf("[ERROR] Slog can not unlock mutex: %d\n", errno); - exit(EXIT_FAILURE); - } + printf("<%s:%d> %s: [ERROR] Can not lock mutex: %d\n", + __FILE__, __LINE__, __FUNCTION__, errno); + + exit(EXIT_FAILURE); } } -void slog_sync_init() +static void slog_unlock(SLogContext *pSlog) { - if (g_slogCfg.nTdSafe) + if (pSlog->nTdSafe && pthread_mutex_unlock(&pSlog->mutex)) { - /* Init mutex attribute */ - pthread_mutexattr_t m_attr; - if (pthread_mutexattr_init(&m_attr) || - pthread_mutexattr_settype(&m_attr, PTHREAD_MUTEX_RECURSIVE) || - pthread_mutex_init(&g_slogCfg.slogLock, &m_attr) || - pthread_mutexattr_destroy(&m_attr)) - { - printf("[ERROR] Slog can not initialize mutex: %d\n", errno); - g_slogCfg.nTdSafe = 0; - g_slogCfg.nSync = 0; - } - - g_slogCfg.nSync = 1; + printf("<%s:%d> %s: [ERROR] Can not unlock mutex: %d\n", + __FILE__, __LINE__, __FUNCTION__, errno); + + exit(EXIT_FAILURE); } } -void slog_sync_destroy() +static const char* slog_get_tag(SLOG_FLAGS_E eFlag) { - if (pthread_mutex_destroy(&g_slogCfg.slogLock)) + switch (eFlag) { - printf("[ERROR] Can not deinitialize mutex: %d\n", errno); - exit(EXIT_FAILURE); + case SLOG_NOTE: return "note"; + case SLOG_INFO: return "info"; + case SLOG_WARN: return "warn"; + case SLOG_DEBUG: return "debug"; + case SLOG_ERROR: return "error"; + case SLOG_TRACE: return "trace"; + case SLOG_FATAL: return "fatal"; + default: break; } - g_slogCfg.nSync = 0; - g_slogCfg.nTdSafe = 0; + return NULL; } -#ifdef DARWIN -static inline int clock_gettime(int clock_id, struct timespec *ts) +static const char* slog_get_color(SLOG_FLAGS_E eFlag) { - struct timeval tv; - - if (clock_id != CLOCK_REALTIME) + switch (eFlag) { - errno = EINVAL; - return -1; + case SLOG_NOTE: return SLOG_CLR_NORMAL; + case SLOG_INFO: return SLOG_CLR_GREEN; + case SLOG_WARN: return SLOG_CLR_YELLOW; + case SLOG_DEBUG: return SLOG_CLR_BLUE; + case SLOG_ERROR: return SLOG_CLR_RED; + case SLOG_TRACE: return SLOG_CLR_CYAN; + case SLOG_FATAL: return SLOG_CLR_MAGENTA; + default: break; } - if (gettimeofday(&tv, NULL) < 0) - { - return -1; - } - ts->tv_sec = tv.tv_sec; - ts->tv_nsec = tv.tv_usec * 1000; - return 0; + + return SLOG_CLR_NORMAL; +} + +static uint8_t slog_get_usec() +{ + struct timeval tv; + if (gettimeofday(&tv, NULL) < 0) return 0; + return (uint8_t)(tv.tv_usec / 10000); } -#endif /* DARWIN */ -void slog_get_date(SlogDate *pDate) +static void slog_get_date(SLogDate *pDate) { struct tm timeinfo; time_t rawtime = time(NULL); localtime_r(&rawtime, &timeinfo); - /* Get System Date */ - pDate->year = timeinfo.tm_year+1900; - pDate->mon = timeinfo.tm_mon+1; - pDate->day = timeinfo.tm_mday; - pDate->hour = timeinfo.tm_hour; - pDate->min = timeinfo.tm_min; - pDate->sec = timeinfo.tm_sec; - - /* Get micro seconds */ - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - pDate->usec = now.tv_nsec / 10000000; + pDate->nYear = timeinfo.tm_year + 1900; + pDate->nMonth = timeinfo.tm_mon + 1; + pDate->nDay = timeinfo.tm_mday; + pDate->nHour = timeinfo.tm_hour; + pDate->nMin = timeinfo.tm_min; + pDate->nSec = timeinfo.tm_sec; + pDate->nUsec = slog_get_usec(); } -const char* slog_version(int nMin) +static void slog_create_tag( char *pOut, size_t nSize, SLOG_FLAGS_E eFlag, const char *pColor) { - static char sVersion[128]; + const char *pTag = slog_get_tag(eFlag); + if (pTag == NULL) return; - /* Version short */ - if (nMin) sprintf(sVersion, "%d.%d.%d", - SLOGVERSION_MAJOR, SLOGVERSION_MINOR, SLOGBUILD_NUM); - - /* Version long */ - else sprintf(sVersion, "%d.%d build %d (%s)", - SLOGVERSION_MAJOR, SLOGVERSION_MINOR, SLOGBUILD_NUM, __DATE__); + if (g_slog.slogConfig.eColorFormat != SLOG_COLOR_TAG) snprintf(pOut, nSize, "<%s> ", pTag); + else snprintf(pOut, nSize, "%s<%s>%s ", pColor, pTag, SLOG_CLR_RESET); +} - return sVersion; +static uint32_t slog_get_tid() +{ +#ifdef DARWIN + return (uint32_t)pthread_self(); +#else + return syscall(__NR_gettid); +#endif } -void slog_prepare_output(const char* pStr, const SlogDate *pDate, int nType, int nColor, char* pOut, int nSize) +static void slog_display_output(char *pStr, uint8_t nNewLine) { - char sDate[32]; - snprintf(sDate, sizeof(sDate), "%02d.%02d.%02d-%02d:%02d:%02d.%02d", - pDate->year, pDate->mon, pDate->day, pDate->hour, - pDate->min, pDate->sec, pDate->usec); - - /* Walk throu */ - int i; - for (i = 0;; i++) - //for (int i = 0;; i++) + if (g_slog.slogConfig.nToScreen) { - if ((nType == SLOG_NONE) && !g_SlogTags[i].nType && (g_SlogTags[i].pDesc == NULL)) - { - snprintf(pOut, nSize, "%s - %s", sDate, pStr); - return; - } - - if ((nType != SLOG_NONE) && (g_SlogTags[i].nType == nType) && (g_SlogTags[i].pDesc != NULL)) - { - if (nColor) - snprintf(pOut, nSize, "%s - [%s%s%s] %s", sDate, g_SlogTags[i].pColor, g_SlogTags[i].pDesc, CLR_RESET, pStr); - else - snprintf(pOut, nSize, "%s - [%s] %s", sDate, g_SlogTags[i].pDesc, pStr); - - return; - } + printf("%s%s", pStr, nNewLine ? "\n" : ""); + if (g_slog.slogConfig.nFlush) fflush(stdout); } -} -void slog_to_file(char *pStr, const char *pFile, SlogDate *pDate) -{ - char sFileName[PATH_MAX]; - memset(sFileName, 0, sizeof(sFileName)); + if (!g_slog.slogConfig.nToFile) return; + const SLogDate *pDate = &g_slog.slogDate; - if (g_slogCfg.nFileStamp) - snprintf(sFileName, sizeof(sFileName), "%s-%02d-%02d-%02d.log", pFile, pDate->year, pDate->mon, pDate->day); - else - snprintf(sFileName, sizeof(sFileName), "%s.log", pFile); + char sFilePath[SLOG_PATH_MAX + SLOG_NAME_MAX + SLOG_DATE_MAX]; + snprintf(sFilePath, sizeof(sFilePath), "%s/%s-%04d-%02d-%02d.log", + g_slog.slogConfig.sFilePath[0] != 0 ? g_slog.slogConfig.sFilePath : ".", + g_slog.slogConfig.sFileName[0] != 0 ? g_slog.slogConfig.sFileName : "slog", + pDate->nYear, pDate->nMonth, pDate->nDay); - FILE *fp = fopen(sFileName, "a"); - if (fp == NULL) return; + FILE *pFile = fopen(sFilePath, "a"); + if (pFile == NULL) return; - fprintf(fp, "%s\n", pStr); - fclose(fp); + fprintf(pFile, "%s%s", pStr, nNewLine ? "\n" : ""); + fclose(pFile); } -int slog_parse_config(const char *pConfig) +static void slog_create_output(char* pOut, size_t nSize, const char* pStr, SLOG_FLAGS_E eFlag) { - if (pConfig == NULL) return 0; + const SLogConfig *pConfig = &g_slog.slogConfig; + const SLogDate *pDate = &g_slog.slogDate; + char sDate[SLOG_DATE_MAX]; - FILE *pFile = fopen(pConfig, "r"); - if(pFile == NULL) return 0; + snprintf(sDate, sizeof(sDate), "%04d.%02d.%02d-%02d:%02d:%02d.%02d", pDate->nYear, + pDate->nMonth, pDate->nDay, pDate->nHour, pDate->nMin, pDate->nSec, pDate->nUsec); - char sArg[256], sName[32]; - while(fscanf(pFile, "%s %[^\n]\n", sName, sArg) == 2) - { - if ((strlen(sName) > 0) && (sName[0] == '#')) - { - /* Skip comment */ - continue; - } - else if (strcmp(sName, "LOGLEVEL") == 0) - { - g_slogCfg.nLogLevel = atoi(sArg); - } - else if (strcmp(sName, "LOGFILELEVEL") == 0) - { - g_slogCfg.nFileLevel = atoi(sArg); - } - else if (strcmp(sName, "LOGTOFILE") == 0) - { - g_slogCfg.nToFile = atoi(sArg); - } - else if (strcmp(sName, "ERRORLOG") == 0) - { - g_slogCfg.nErrLog = atoi(sArg); - } - else if (strcmp(sName, "PRETTYLOG") == 0) - { - g_slogCfg.nPretty = atoi(sArg); - } - else if (strcmp(sName, "FILESTAMP") == 0) - { - g_slogCfg.nFileStamp = atoi(sArg); - } - } + char sTid[SLOG_TAG_MAX]; + char sTag[SLOG_TAG_MAX]; + sTid[0] = sTag[0] = 0; - fclose(pFile); - return 1; + const char *pColor = slog_get_color(eFlag); + slog_create_tag(sTag, sizeof(sTag), eFlag, pColor); + + if (pConfig->nTraceTid) snprintf(sTid, sizeof(sTid), "(%u) ", slog_get_tid()); + if (pConfig->eColorFormat != SLOG_COLOR_FULL) snprintf(pOut, nSize, "%s%s - %s%s", sTid, sDate, sTag, pStr); + else snprintf(pOut, nSize, "%s%s%s - %s%s%s", pColor, sTid, sDate, sTag, pStr, SLOG_CLR_RESET); } -void slog(int nLevel, int nFlag, const char *pMsg, ...) +const char* slog_version(uint8_t nMin) { - slog_sync_lock(); + static char sVersion[SLOG_VERSION_MAX]; - if (g_slogCfg.nSilent && - (nFlag == SLOG_DEBUG || - nFlag == SLOG_LIVE)) - { - slog_sync_unlock(); - return; - } + /* Version short */ + if (nMin) sprintf(sVersion, "%d.%d.%d", + SLOG_VERSION_MAJOR, SLOG_VERSION_MINOR, SLOG_BUILD_NUM); - char sInput[MAXMSG]; - memset(sInput, 0, sizeof(sInput)); + /* Version long */ + else sprintf(sVersion, "%d.%d build %d (%s)", + SLOG_VERSION_MAJOR, SLOG_VERSION_MINOR, SLOG_BUILD_NUM, __DATE__); + + return sVersion; +} - va_list args; - va_start(args, pMsg); - vsprintf(sInput, pMsg, args); - va_end(args); +void slog_config_get(SLogConfig *pCfg) +{ + slog_lock(&g_slog); + *pCfg = g_slog.slogConfig; + slog_unlock(&g_slog); +} - /* Check logging levels */ - if(!nLevel || nLevel <= g_slogCfg.nLogLevel || nLevel <= g_slogCfg.nFileLevel) - { - SlogDate date; - slog_get_date(&date); - - char sMessage[MAXMSG]; - memset(sMessage, 0, sizeof(sMessage)); - - slog_prepare_output(sInput, &date, nFlag, 1, sMessage, sizeof(sMessage)); - if (nLevel <= g_slogCfg.nLogLevel) printf("%s\n", sMessage); - - /* Save log in the file */ - if ((g_slogCfg.nToFile && nLevel <= g_slogCfg.nFileLevel) || - (g_slogCfg.nErrLog && (nFlag == (SLOG_ERROR | SLOG_PANIC | SLOG_FATAL)))) - { - if (g_slogCfg.nPretty) - { - memset(sMessage, 0, sizeof(sMessage)); - slog_prepare_output(sInput, &date, nFlag, 0, sMessage, sizeof(sMessage)); - } - - slog_to_file(sMessage, g_slogCfg.sFileName, &date); - } - } +void slog_config_set(SLogConfig *pCfg) +{ + slog_lock(&g_slog); + g_slog.slogConfig = *pCfg; + slog_unlock(&g_slog); +} - slog_sync_unlock(); +void slog_enable(SLOG_FLAGS_E eFlag) +{ + slog_lock(&g_slog); + g_slog.slogConfig.nFlags |= eFlag; + slog_unlock(&g_slog); } -void slog_config_get(SlogConfig *pCfg) +void slog_disable(SLOG_FLAGS_E eFlag) { - slog_sync_lock(); - memset(pCfg->sFileName, 0, sizeof(pCfg->sFileName)); - strcpy(pCfg->sFileName, g_slogCfg.sFileName); - - pCfg->nFileStamp = g_slogCfg.nFileStamp; - pCfg->nFileLevel = g_slogCfg.nFileLevel; - pCfg->nLogLevel = g_slogCfg.nLogLevel; - pCfg->nToFile = g_slogCfg.nToFile; - pCfg->nPretty = g_slogCfg.nPretty; - pCfg->nTdSafe = g_slogCfg.nTdSafe; - pCfg->nErrLog = g_slogCfg.nErrLog; - pCfg->nSilent = g_slogCfg.nSilent; - slog_sync_unlock(); + slog_lock(&g_slog); + g_slog.slogConfig.nFlags &= ~eFlag; + slog_unlock(&g_slog); } -void slog_config_set(SlogConfig *pCfg) +void slog_print(SLOG_FLAGS_E eFlag, uint8_t nNewLine, const char *pMsg, ...) { - slog_sync_lock(); - memset(g_slogCfg.sFileName, 0, sizeof(g_slogCfg.sFileName)); - strcpy(g_slogCfg.sFileName, pCfg->sFileName); - - g_slogCfg.nFileStamp = pCfg->nFileStamp; - g_slogCfg.nFileLevel = pCfg->nFileLevel; - g_slogCfg.nLogLevel = pCfg->nLogLevel; - g_slogCfg.nToFile = pCfg->nToFile; - g_slogCfg.nPretty = pCfg->nPretty; - g_slogCfg.nTdSafe = pCfg->nTdSafe; - g_slogCfg.nErrLog = pCfg->nErrLog; - g_slogCfg.nSilent = pCfg->nSilent; - - if (g_slogCfg.nTdSafe && !g_slogCfg.nSync) - { - slog_sync_init(); - slog_sync_lock(); - } - else if (!g_slogCfg.nTdSafe && g_slogCfg.nSync) + slog_lock(&g_slog); + + if ((SLOG_FLAGS_CHECK(g_slog.slogConfig.nFlags, eFlag)) && + (g_slog.slogConfig.nToScreen || g_slog.slogConfig.nToFile)) { - g_slogCfg.nTdSafe = 1; - slog_sync_unlock(); - slog_sync_destroy(); + slog_get_date(&g_slog.slogDate); + char sInput[SLOG_MESSAGE_MAX]; + + va_list args; + va_start(args, pMsg); + vsnprintf(sInput, sizeof(sInput), pMsg, args); + va_end(args); + + char sOutput[SLOG_MESSAGE_MAX + SLOG_DATE_MAX + (SLOG_TAG_MAX * 3)]; + slog_create_output(sOutput, sizeof(sOutput), sInput, eFlag); + slog_display_output(sOutput, nNewLine); } - slog_sync_unlock(); + slog_unlock(&g_slog); } -void slog_init(const char* pName, const char* pConf, int nLogLevel, int nTdSafe) +void slog_init(const char* pName, uint16_t nFlags, uint8_t nTdSafe) { /* Set up default values */ - memset(g_slogCfg.sFileName, 0, sizeof(g_slogCfg.sFileName)); - strcpy(g_slogCfg.sFileName, pName); - - g_slogCfg.nLogLevel = nLogLevel; - g_slogCfg.nTdSafe = nTdSafe; - g_slogCfg.nFileStamp = 1; - g_slogCfg.nFileLevel = 0; - g_slogCfg.nErrLog = 0; - g_slogCfg.nSilent = 0; - g_slogCfg.nToFile = 0; - g_slogCfg.nPretty = 0; - g_slogCfg.nSync = 0; - - /* Init mutex sync */ - slog_sync_init(); - - /* Parse config file */ - slog_parse_config(pConf); + SLogConfig *pConfig = &g_slog.slogConfig; + pConfig->eColorFormat = SLOG_COLOR_TAG; + pConfig->sFileName[0] = 0; + pConfig->sFilePath[0] = 0; + pConfig->nTraceTid = 0; + pConfig->nToScreen = 1; + pConfig->nToFile = 0; + pConfig->nFlush = 0; + pConfig->nFlags = nFlags; + + if (pName != NULL) snprintf(pConfig->sFileName, + sizeof(pConfig->sFileName)-1, "%s", pName); + + /* Initialize mutex */ + g_slog.nTdSafe = nTdSafe; + slog_sync_init(&g_slog); } + +void slog_destroy() +{ + if (!g_slog.nTdSafe) return; + pthread_mutex_destroy(&g_slog.mutex); + g_slog.nTdSafe = 0; +} \ No newline at end of file diff --git a/src/slog.h b/src/slog.h index f252ea0..85e3fda 100644 --- a/src/slog.h +++ b/src/slog.h @@ -1,8 +1,7 @@ /* * The MIT License (MIT) - * - * Copyleft (C) 2015 - 2018 Sun Dro (a.k.a. kala13x) - * Copyleft (C) 2017 George G. Gkasdrogkas (a.k.a. GeorgeGkas) + * + * Copyleft (C) 2015-2020 Sun Dro (f4tb0y@protonmail.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,113 +25,119 @@ #ifndef __SLOG_H__ #define __SLOG_H__ -/* For include header in CPP code */ #ifdef __cplusplus extern "C" { #endif +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include #include -/* Definations for version info */ -#define SLOGVERSION_MAJOR 1 -#define SLOGVERSION_MINOR 6 -#define SLOGBUILD_NUM 2 - -/* Loging flags */ -#define SLOG_NONE 0 -#define SLOG_LIVE 1 -#define SLOG_INFO 2 -#define SLOG_WARN 3 -#define SLOG_DEBUG 4 -#define SLOG_ERROR 5 -#define SLOG_FATAL 6 -#define SLOG_PANIC 7 +/* SLog version information */ +#define SLOG_VERSION_MAJOR 1 +#define SLOG_VERSION_MINOR 8 +#define SLOG_BUILD_NUM 22 /* Supported colors */ -#define CLR_NORMAL "\x1B[0m" -#define CLR_RED "\x1B[31m" -#define CLR_GREEN "\x1B[32m" -#define CLR_YELLOW "\x1B[33m" -#define CLR_BLUE "\x1B[34m" -#define CLR_NAGENTA "\x1B[35m" -#define CLR_CYAN "\x1B[36m" -#define CLR_WHITE "\x1B[37m" -#define CLR_RESET "\033[0m" - -#define LVL1(x) #x -#define LVL2(x) LVL1(x) -#define SOURCE_THROW_LOCATION "<"__FILE__":"LVL2(__LINE__)"> -- " - -/* - * Define macros to allow us get further informations - * on the corresponding erros. These macros used as wrappers - * for slog() function. - */ -#define slog_none(LEVEL, ...) \ - slog(LEVEL, SLOG_NONE, __VA_ARGS__); - -#define slog_live(LEVEL, ...) \ - slog(LEVEL, SLOG_LIVE, __VA_ARGS__); - -#define slog_info(LEVEL, ...) \ - slog(LEVEL, SLOG_INFO, __VA_ARGS__); - -#define slog_warn(LEVEL, ...) \ - slog(LEVEL, SLOG_WARN, __VA_ARGS__); - -#define slog_debug(LEVEL, ...) \ - slog(LEVEL, SLOG_DEBUG, __VA_ARGS__); - -#define slog_error(LEVEL, ...) \ - slog(LEVEL, SLOG_ERROR, SOURCE_THROW_LOCATION __VA_ARGS__); - -#define slog_fatal(LEVEL, ...) \ - slog(LEVEL, SLOG_FATAL, SOURCE_THROW_LOCATION __VA_ARGS__); - -#define slog_panic(LEVEL, ...) \ - slog(LEVEL, SLOG_PANIC, SOURCE_THROW_LOCATION __VA_ARGS__); - -/* Flags */ -typedef struct { - char sFileName[64]; - unsigned short nFileLevel; - unsigned short nLogLevel; - unsigned short nFileStamp:1; - unsigned short nToFile:1; - unsigned short nPretty:1; - unsigned short nTdSafe:1; - unsigned short nErrLog:1; - unsigned short nSilent:1; - unsigned short nSync:1; - pthread_mutex_t slogLock; -} SlogConfig; - -/* Date variables */ -typedef struct { - int year; - int mon; - int day; - int hour; - int min; - int sec; - int usec; -} SlogDate; - -typedef struct { - int nType; - const char* pDesc; - const char* pColor; -} SlogTag; - -const char* slog_version(int nMin); - -void slog_config_get(SlogConfig *pCfg); -void slog_config_set(SlogConfig *pCfg); - -void slog_init(const char* pName, const char* pConf, int nLogLevel, int nTdSafe); -void slog(int level, int flag, const char *pMsg, ...); - -/* For include header in CPP code */ +#define SLOG_CLR_NORMAL "\x1B[0m" +#define SLOG_CLR_RED "\x1B[31m" +#define SLOG_CLR_GREEN "\x1B[32m" +#define SLOG_CLR_YELLOW "\x1B[33m" +#define SLOG_CLR_BLUE "\x1B[34m" +#define SLOG_CLR_MAGENTA "\x1B[35m" +#define SLOG_CLR_CYAN "\x1B[36m" +#define SLOG_CLR_WHITE "\x1B[37m" +#define SLOG_CLR_RESET "\033[0m" + +/* Trace source location helpers */ +#define SLOG_TRACE_LVL1(LINE) #LINE +#define SLOG_TRACE_LVL2(LINE) SLOG_TRACE_LVL1(LINE) +#define SLOG_THROW_LOCATION "[" __FILE__ ":" SLOG_TRACE_LVL2(__LINE__) "] " + +/* SLog limits (To be safe while avoiding dynamic allocations) */ +#define SLOG_MESSAGE_MAX 8196 +#define SLOG_VERSION_MAX 128 +#define SLOG_PATH_MAX 2048 +#define SLOG_NAME_MAX 256 +#define SLOG_DATE_MAX 64 +#define SLOG_TAG_MAX 32 + +#define SLOG_FLAGS_CHECK(c, f) (((c) & (f)) == (f)) +#define SLOG_FLAGS_ALL 255 + +/* Log level flags */ +typedef enum +{ + SLOG_NOTAG = (1 << 0), + SLOG_NOTE = (1 << 1), + SLOG_INFO = (1 << 2), + SLOG_WARN = (1 << 3), + SLOG_DEBUG = (1 << 4), + SLOG_TRACE = (1 << 5), + SLOG_ERROR = (1 << 6), + SLOG_FATAL = (1 << 7) +} SLOG_FLAGS_E; + +/* Output coloring control flags */ +typedef enum +{ + SLOG_COLOR_DISABLE = 0, + SLOG_COLOR_TAG, + SLOG_COLOR_FULL +} SLOG_COLOR_FMT_E; + +#define slog(...) \ + slog_print(SLOG_NOTAG, 1, __VA_ARGS__) + +#define slogwn(...) \ + slog_print(SLOG_NOTAG, 0, __VA_ARGS__) + +#define slog_note(...) \ + slog_print(SLOG_NOTE, 1, __VA_ARGS__) + +#define slog_info(...) \ + slog_print(SLOG_INFO, 1, __VA_ARGS__) + +#define slog_warn(...) \ + slog_print(SLOG_WARN, 1, __VA_ARGS__) + +#define slog_debug(...) \ + slog_print(SLOG_DEBUG, 1, __VA_ARGS__) + +#define slog_error(...) \ + slog_print(SLOG_ERROR, 1, __VA_ARGS__) + +#define slog_trace(...) \ + slog_print(SLOG_TRACE, 1, SLOG_THROW_LOCATION __VA_ARGS__) + +#define slog_fatal(...) \ + slog_print(SLOG_FATAL, 1, SLOG_THROW_LOCATION __VA_ARGS__) + +typedef struct SLogConfig { + char sFileName[SLOG_NAME_MAX]; // Output file name for logs + char sFilePath[SLOG_PATH_MAX]; // Output file path for logs + SLOG_COLOR_FMT_E eColorFormat; // Output color format control + uint8_t nTraceTid:1; // Trace thread ID and display in output + uint8_t nToScreen:1; // Enable screen logging + uint8_t nToFile:1; // Enable file logging + uint8_t nFlush:1; // Flush stdout after screen log + uint16_t nFlags; // Allowed log level flags +} SLogConfig; + +const char* slog_version(uint8_t nMin); +void slog_config_get(SLogConfig *pCfg); +void slog_config_set(SLogConfig *pCfg); + +void slog_enable(SLOG_FLAGS_E eFlag); +void slog_disable(SLOG_FLAGS_E eFlag); + +void slog_init(const char* pName, uint16_t nFlags, uint8_t nTdSafe); +void slog_print(SLOG_FLAGS_E eFlag, uint8_t nNewLine, const char *pMsg, ...); +void slog_destroy(); // Needed only if the slog_init() function argument nTdSafe > 0 + #ifdef __cplusplus } #endif