├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── src ├── CMakeLists.txt ├── ulog.c └── ulog.h └── tests ├── CMakeLists.txt ├── ulog_example.c ├── ulog_test.c └── ulog_test.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | build/ 54 | .vscode 55 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | add_subdirectory(tests) 4 | add_subdirectory(src) 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Robert Poor 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # uLog 2 | Lightweight logging for embedded microcontrollers 3 | 4 | ## About uLog 5 | 6 | uLog provides a structured logging mechanism for embedded microcontrollers or any system with limited resources. 7 | It inherits the some concepts behind the popular Log4c and Log4j platforms, but with lower overhead. 8 | 9 | Some features of uLog: 10 | * uLog is easy to incorporate into nearly any environment, comprising one header file and one source file, and is written in pure C. 11 | * uLog provides familiar severity levels (CRITICAL, ERROR, WARNING, INFO, DEBUG, TRACE). 12 | * uLog supports multiple user-defined outputs (console, log file, in-memory buffer, etc), each with its own reporting threshold level. 13 | * uLog is "aggressively standalone" with minimal dependencies, requiring only stdio.h, string.h and stdarg.h. 14 | * uLog gets out of your way when you're not using it: if ULOG_ENABLED is undefined at compile time, no logging code is generated. 15 | * uLog is well tested. See the accompanying ulog_test.c file for details. 16 | 17 | ## A quick intro by example: 18 | 19 | ``` c 20 | #include 21 | #include "ulog.h" 22 | 23 | // To use uLog, you must define a function to process logging messages. It can 24 | // write the messages to a console, to a file, to an in-memory buffer: the 25 | // choice is yours. And you get to choose the format of the message. 26 | // 27 | // The following example prints to the console. 28 | // 29 | // One caveat: msg is a static string and will be over-written at the next call 30 | // to ULOG. This means you may print it or copy it, but saving a pointer to it 31 | // will lead to confusion and astonishment. 32 | // 33 | void my_console_logger(ulog_level_t severity, const char *msg) { 34 | printf("%s [%s]: %s\n", 35 | get_timestamp(), // user defined function 36 | ulog_level_name(severity), 37 | msg); 38 | } 39 | 40 | int main() { 41 | int arg = 42; 42 | 43 | ULOG_INIT(); 44 | 45 | // log messages with a severity of WARNING or higher to the console. The 46 | // user must supply a method for my_console_logger, e.g. along the lines 47 | // of what is shown above. 48 | ULOG_SUBSCRIBE(my_console_logger, ULOG_WARNING_LEVEL); 49 | 50 | // log messages with a severity of DEBUG or higher to a file. The user must 51 | // provide a method for my_file_logger (not shown here). 52 | ULOG_SUBSCRIBE(my_file_logger, ULOG_DEBUG_LEVEL); 53 | 54 | ULOG_INFO("Info, arg=%d", arg); // logs to file but not console 55 | ULOG_CRITICAL("Critical, arg=%d", arg); // logs to file and console 56 | 57 | // dynamically change the threshold for a specific logger 58 | ULOG_SUBSCRIBE(my_console_logger, ULOG_INFO_LEVEL); 59 | 60 | ULOG_INFO("Info, arg=%d", arg); // logs to file and console 61 | 62 | // remove a logger 63 | ULOG_UNSUBSCRIBE(my_file_logger); 64 | 65 | ULOG_INFO("Info, arg=%d", arg); // logs to console only 66 | } 67 | ``` 68 | 69 | ## Questions? Comments? Improvements? 70 | 71 | Comments and pull requests are welcome in https://github.com/rdpoor/ulog/issues 72 | 73 | - R Dunbar Poor 74 | June 2019 75 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Set the project name 2 | project(ulog) 3 | 4 | # Add a library with the above sources 5 | add_library(${PROJECT_NAME} EXCLUDE_FROM_ALL ulog.c) 6 | 7 | target_include_directories(${PROJECT_NAME} PUBLIC .) 8 | -------------------------------------------------------------------------------- /src/ulog.c: -------------------------------------------------------------------------------- 1 | /** 2 | MIT License 3 | 4 | Copyright (c) 2019 R. Dunbar Poor 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | this software and associated documentation files (the "Software"), to deal in 8 | the Software without restriction, including without limitation the rights to 9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | /** 25 | * \file ulog.c 26 | * 27 | * \brief uLog: lightweight logging for embedded systems 28 | * 29 | * See ulog.h for sparse documentation. 30 | */ 31 | 32 | #include "ulog.h" 33 | 34 | #ifdef ULOG_ENABLED // whole file... 35 | 36 | #include 37 | #include 38 | #include 39 | 40 | 41 | // ============================================================================= 42 | // types and definitions 43 | 44 | typedef struct { 45 | ulog_function_t fn; 46 | ulog_level_t threshold; 47 | } subscriber_t; 48 | 49 | static ulog_level_t ulog_lowest_log_level(); 50 | 51 | // ============================================================================= 52 | // local storage 53 | 54 | static subscriber_t s_subscribers[ULOG_MAX_SUBSCRIBERS]; 55 | static char s_message[ULOG_MAX_MESSAGE_LENGTH]; 56 | static ulog_level_t s_lowest_log_level; 57 | 58 | // ============================================================================= 59 | // user-visible code 60 | 61 | void ulog_init() { 62 | memset(s_subscribers, 0, sizeof(s_subscribers)); 63 | s_lowest_log_level = ulog_lowest_log_level(); 64 | } 65 | 66 | // search the s_subscribers table to install or update fn 67 | ulog_err_t ulog_subscribe(ulog_function_t fn, ulog_level_t threshold) { 68 | int available_slot = -1; 69 | int i; 70 | for (i=0; i= s_subscribers[i].threshold) { 133 | s_subscribers[i].fn(severity, s_message); 134 | } 135 | } 136 | } 137 | } 138 | 139 | // ============================================================================= 140 | // private code 141 | 142 | static ulog_level_t ulog_lowest_log_level(){ 143 | ulog_level_t lowest_log_level = ULOG_ALWAYS_LEVEL; 144 | int i; 145 | for (i=0; i 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | this software and associated documentation files (the "Software"), to deal in 8 | the Software without restriction, including without limitation the rights to 9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | /** 25 | * \file 26 | * 27 | * \brief uLog: lightweight logging for embedded systems 28 | * 29 | * A quick intro by example: 30 | * 31 | * #include "ulog.h" 32 | * 33 | * // To use uLog, you must define a function to process logging messages. 34 | * // It can write the messages to a console, to a file, to an in-memory 35 | * // buffer: the choice is yours. And you get to choose the format of 36 | * // the message. This example prints to the console. One caveat: msg 37 | * // is a static string and will be over-written at the next call to ULOG. 38 | * // You may print it or copy it, but saving a pointer to it will lead to 39 | * // confusion and astonishment. 40 | * // 41 | * void my_console_logger(ulog_level_t level, const char *msg) { 42 | * printf("%s [%s]: %s\n", 43 | * get_timestamp(), 44 | * ulog_level_name(level), 45 | * msg); 46 | * } 47 | * 48 | * int main() { 49 | * ULOG_INIT(); 50 | * 51 | * // log to the console messages that are WARNING or more severe. You 52 | * // can re-subscribe at any point to change the severity level. 53 | * ULOG_SUBSCRIBE(my_console_logger, ULOG_WARNING); 54 | * 55 | * // log to a file messages that are DEBUG or more severe 56 | * ULOG_SUBSCRIBE(my_file_logger, ULOG_DEBUG); 57 | * 58 | * int arg = 42; 59 | * ULOG_INFO("Arg is %d", arg); // logs to file but not console 60 | * } 61 | */ 62 | 63 | #ifndef ULOG_H_ 64 | #define ULOG_H_ 65 | 66 | #ifdef __cplusplus 67 | extern "C" { 68 | #endif 69 | 70 | typedef enum { 71 | ULOG_TRACE_LEVEL=100, 72 | ULOG_DEBUG_LEVEL, 73 | ULOG_INFO_LEVEL, 74 | ULOG_WARNING_LEVEL, 75 | ULOG_ERROR_LEVEL, 76 | ULOG_CRITICAL_LEVEL, 77 | ULOG_ALWAYS_LEVEL 78 | } ulog_level_t; 79 | 80 | // The following macros enable or disable uLog. If `ULOG_ENABLED` is 81 | // defined at compile time, a macro such as `ULOG_INFO(...)` expands 82 | // into `ulog_message(ULOG_INFO_LEVEL, ...)`. If `ULOG_ENABLED` is not 83 | // defined, then the same macro expands into `do {} while(0)` and will 84 | // not generate any code at all. 85 | // 86 | // There are two ways to enable uLog: you can uncomment the following 87 | // line, or -- if it is commented out -- you can add -DULOG_ENABLED to 88 | // your compiler switches. 89 | //#define ULOG_ENABLED 90 | 91 | #ifdef ULOG_ENABLED 92 | #define ULOG_INIT() ulog_init() 93 | #define ULOG_SUBSCRIBE(a, b) ulog_subscribe(a, b) 94 | #define ULOG_UNSUBSCRIBE(a) ulog_unsubscribe(a) 95 | #define ULOG_LEVEL_NAME(a) ulog_level_name(a) 96 | #define ULOG(...) ulog_message(__VA_ARGS__) 97 | #define ULOG_TRACE(...) ulog_message(ULOG_TRACE_LEVEL, __VA_ARGS__) 98 | #define ULOG_DEBUG(...) ulog_message(ULOG_DEBUG_LEVEL, __VA_ARGS__) 99 | #define ULOG_INFO(...) ulog_message(ULOG_INFO_LEVEL, __VA_ARGS__) 100 | #define ULOG_WARNING(...) ulog_message(ULOG_WARNING_LEVEL, __VA_ARGS__) 101 | #define ULOG_ERROR(...) ulog_message(ULOG_ERROR_LEVEL, __VA_ARGS__) 102 | #define ULOG_CRITICAL(...) ulog_message(ULOG_CRITICAL_LEVEL, __VA_ARGS__) 103 | #define ULOG_ALWAYS(...) ulog_message(ULOG_ALWAYS_LEVEL, __VA_ARGS__) 104 | #else 105 | // uLog vanishes when disabled at compile time... 106 | #define ULOG_INIT() do {} while(0) 107 | #define ULOG_SUBSCRIBE(a, b) do {} while(0) 108 | #define ULOG_UNSUBSCRIBE(a) do {} while(0) 109 | #define ULOG_LEVEL_NAME(a) do {} while(0) 110 | #define ULOG(s, f, ...) do {} while(0) 111 | #define ULOG_TRACE(f, ...) do {} while(0) 112 | #define ULOG_DEBUG(f, ...) do {} while(0) 113 | #define ULOG_INFO(f, ...) do {} while(0) 114 | #define ULOG_WARNING(f, ...) do {} while(0) 115 | #define ULOG_ERROR(f, ...) do {} while(0) 116 | #define ULOG_CRITICAL(f, ...) do {} while(0) 117 | #define ULOG_ALWAYS(f, ...) do {} while(0) 118 | #endif 119 | 120 | typedef enum { 121 | ULOG_ERR_NONE = 0, 122 | ULOG_ERR_SUBSCRIBERS_EXCEEDED, 123 | ULOG_ERR_NOT_SUBSCRIBED, 124 | } ulog_err_t; 125 | 126 | // define the maximum number of concurrent subscribers 127 | #ifndef ULOG_MAX_SUBSCRIBERS 128 | #define ULOG_MAX_SUBSCRIBERS 6 129 | #endif 130 | // maximum length of formatted log message 131 | #ifndef ULOG_MAX_MESSAGE_LENGTH 132 | #define ULOG_MAX_MESSAGE_LENGTH 120 133 | #endif 134 | /** 135 | * @brief: prototype for uLog subscribers. 136 | */ 137 | typedef void (*ulog_function_t)(ulog_level_t severity, char *msg); 138 | 139 | void ulog_init(void); 140 | ulog_err_t ulog_subscribe(ulog_function_t fn, ulog_level_t threshold); 141 | ulog_err_t ulog_unsubscribe(ulog_function_t fn); 142 | const char *ulog_level_name(ulog_level_t level); 143 | void ulog_message(ulog_level_t severity, const char *fmt, ...); 144 | 145 | #ifdef __cplusplus 146 | } 147 | #endif 148 | 149 | #endif /* ULOG_H_ */ 150 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(ulog_example) 2 | 3 | add_executable(${PROJECT_NAME} ulog_example.c) 4 | target_include_directories(${PROJECT_NAME} PRIVATE ulog) 5 | target_link_libraries(${PROJECT_NAME} ulog) 6 | -------------------------------------------------------------------------------- /tests/ulog_example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "ulog.h" 3 | 4 | // To use uLog, you must define a function to process logging messages. It can 5 | // write the messages to a console, to a file, to an in-memory buffer: the 6 | // choice is yours. And you get to choose the format of the message. 7 | // 8 | // The following example prints to the console. 9 | // 10 | // One caveat: msg is a static string and will be over-written at the next call 11 | // to ULOG. This means you may print it or copy it, but saving a pointer to it 12 | // will lead to confusion and astonishment. 13 | // 14 | void my_console_logger(ulog_level_t severity, char *msg) 15 | { 16 | printf("console: %s [%s]: %s\n", 17 | "time", // user defined function 18 | ulog_level_name(severity), 19 | msg); 20 | } 21 | 22 | void my_file_logger(ulog_level_t severity, char *msg) 23 | { 24 | printf("file: %s [%s]: %s\n", 25 | "time", // user defined function 26 | ulog_level_name(severity), 27 | msg); 28 | } 29 | 30 | int main() 31 | { 32 | int arg = 42; 33 | 34 | ULOG_INIT(); 35 | 36 | // log messages with a severity of WARNING or higher to the console. The 37 | // user must supply a method for my_console_logger, e.g. along the lines 38 | // of what is shown above. 39 | ULOG_SUBSCRIBE(my_console_logger, ULOG_DEBUG_LEVEL); 40 | 41 | // log messages with a severity of DEBUG or higher to a file. The user must 42 | // provide a method for my_file_logger (not shown here). 43 | ULOG_SUBSCRIBE(my_file_logger, ULOG_WARNING_LEVEL); 44 | 45 | ULOG_INFO("Info, arg=%d", arg); // logs to file but not console 46 | ULOG_CRITICAL("Critical, arg=%d", arg); // logs to file and console 47 | 48 | // dynamically change the threshold for a specific logger 49 | ULOG_SUBSCRIBE(my_console_logger, ULOG_INFO_LEVEL); 50 | 51 | ULOG_INFO("Info, arg=%d", arg); // logs to file and console 52 | 53 | // remove a logger 54 | ULOG_UNSUBSCRIBE(my_file_logger); 55 | 56 | ULOG_INFO("Info, arg=%d", arg); // logs to console only 57 | } 58 | -------------------------------------------------------------------------------- /tests/ulog_test.c: -------------------------------------------------------------------------------- 1 | /** 2 | MIT License 3 | 4 | Copyright (c) 2019 R. Dunbar Poor 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | this software and associated documentation files (the "Software"), to deal in 8 | the Software without restriction, including without limitation the rights to 9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | /** 25 | * \file ulog_test.c 26 | * 27 | * \brief unit testing for uLog logging mechanism 28 | */ 29 | 30 | #include "ulog.h" 31 | #include 32 | #include 33 | 34 | int fn_calls[6]; 35 | 36 | void logger_fn0(ulog_level_t severity, char *msg) { 37 | assert(strcmp(msg, "Hello!") == 0); 38 | fn_calls[0]++; 39 | } 40 | 41 | void logger_fn1(ulog_level_t severity, char *msg) { 42 | assert(strcmp(msg, "Hello!") == 0); 43 | fn_calls[1]++; 44 | } 45 | 46 | void logger_fn2(ulog_level_t severity, char *msg) { 47 | assert(strcmp(msg, "Hello!") == 0); 48 | fn_calls[2]++; 49 | } 50 | 51 | void logger_fn3(ulog_level_t severity, char *msg) { 52 | assert(strcmp(msg, "Hello!") == 0); 53 | fn_calls[3]++; 54 | } 55 | 56 | void logger_fn4(ulog_level_t severity, char *msg) { 57 | assert(strcmp(msg, "Hello!") == 0); 58 | fn_calls[4]++; 59 | } 60 | 61 | void logger_fn5(ulog_level_t severity, char *msg) { 62 | assert(strcmp(msg, "Hello!") == 0); 63 | fn_calls[5]++; 64 | } 65 | 66 | void logger_fn6(ulog_level_t severity, char *msg) { 67 | // never actually called 68 | } 69 | 70 | void ulog_test() { 71 | ULOG_INIT(); 72 | memset(fn_calls, 0, sizeof(fn_calls)); 73 | 74 | assert(ULOG_SUBSCRIBE(logger_fn0, ULOG_TRACE_LEVEL) == ULOG_ERR_NONE); 75 | assert(ULOG_SUBSCRIBE(logger_fn1, ULOG_DEBUG_LEVEL) == ULOG_ERR_NONE); 76 | assert(ULOG_SUBSCRIBE(logger_fn2, ULOG_INFO_LEVEL) == ULOG_ERR_NONE); 77 | assert(ULOG_SUBSCRIBE(logger_fn3, ULOG_WARNING_LEVEL) == ULOG_ERR_NONE); 78 | assert(ULOG_SUBSCRIBE(logger_fn4, ULOG_ERROR_LEVEL) == ULOG_ERR_NONE); 79 | assert(ULOG_SUBSCRIBE(logger_fn5, ULOG_CRITICAL_LEVEL) == ULOG_ERR_NONE); 80 | 81 | assert(ULOG_SUBSCRIBE(logger_fn6, ULOG_TRACE_LEVEL) == ULOG_ERR_SUBSCRIBERS_EXCEEDED); 82 | 83 | ULOG_TRACE("Hello!"); 84 | ULOG_DEBUG("Hello!"); 85 | ULOG_INFO("Hello!"); 86 | ULOG_WARNING("Hello!"); 87 | ULOG_ERROR("Hello!"); 88 | ULOG_CRITICAL("Hello!"); 89 | ULOG_ALWAYS("Hello!"); 90 | 91 | assert(fn_calls[0] == 7); // logger_fn0 is at trace level: all messages 92 | assert(fn_calls[1] == 6); 93 | assert(fn_calls[2] == 5); 94 | assert(fn_calls[3] == 4); 95 | assert(fn_calls[4] == 3); 96 | assert(fn_calls[5] == 2); // logger_fn5 receives critical and alwasy only 97 | 98 | // ULOG with explicit severity parameter 99 | ULOG(ULOG_INFO_LEVEL, "Hello!"); 100 | 101 | assert(fn_calls[0] == 8); // logger_fn0 is at trace level: all messages 102 | assert(fn_calls[1] == 7); 103 | assert(fn_calls[2] == 6); // logger_fn2 and lower get info messages 104 | assert(fn_calls[3] == 4); // logger_fn3 and higher don't get info messages 105 | assert(fn_calls[4] == 3); 106 | assert(fn_calls[5] == 2); // logger_fn5 receives critical msgs only 107 | 108 | // reset counters. Test reassigning levels... 109 | memset(fn_calls, 0, sizeof(fn_calls)); 110 | 111 | assert(ULOG_SUBSCRIBE(logger_fn0, ULOG_CRITICAL_LEVEL) == ULOG_ERR_NONE); 112 | assert(ULOG_SUBSCRIBE(logger_fn1, ULOG_ERROR_LEVEL) == ULOG_ERR_NONE); 113 | assert(ULOG_SUBSCRIBE(logger_fn2, ULOG_WARNING_LEVEL) == ULOG_ERR_NONE); 114 | assert(ULOG_SUBSCRIBE(logger_fn3, ULOG_INFO_LEVEL) == ULOG_ERR_NONE); 115 | assert(ULOG_SUBSCRIBE(logger_fn4, ULOG_DEBUG_LEVEL) == ULOG_ERR_NONE); 116 | assert(ULOG_SUBSCRIBE(logger_fn5, ULOG_TRACE_LEVEL) == ULOG_ERR_NONE); 117 | 118 | assert(ULOG_SUBSCRIBE(logger_fn6, ULOG_TRACE_LEVEL) == ULOG_ERR_SUBSCRIBERS_EXCEEDED); 119 | 120 | ULOG_TRACE("Hello!"); 121 | ULOG_DEBUG("Hello!"); 122 | ULOG_INFO("Hello!"); 123 | ULOG_WARNING("Hello!"); 124 | ULOG_ERROR("Hello!"); 125 | ULOG_CRITICAL("Hello!"); 126 | ULOG_ALWAYS("Hello!"); 127 | 128 | assert(fn_calls[0] == 2); // logger_fn0 receives critical and always msgs 129 | assert(fn_calls[1] == 3); 130 | assert(fn_calls[2] == 4); 131 | assert(fn_calls[3] == 5); 132 | assert(fn_calls[4] == 6); 133 | assert(fn_calls[5] == 7); // logger_fn5 is at trace level: all messages 134 | 135 | // reset counters. Test unsubscribe 136 | memset(fn_calls, 0, sizeof(fn_calls)); 137 | 138 | assert(ULOG_UNSUBSCRIBE(logger_fn0) == ULOG_ERR_NONE); 139 | assert(ULOG_UNSUBSCRIBE(logger_fn1) == ULOG_ERR_NONE); 140 | assert(ULOG_UNSUBSCRIBE(logger_fn2) == ULOG_ERR_NONE); 141 | assert(ULOG_UNSUBSCRIBE(logger_fn3) == ULOG_ERR_NONE); 142 | assert(ULOG_UNSUBSCRIBE(logger_fn4) == ULOG_ERR_NONE); 143 | // leave logger_fn5 subscribed 144 | // assert(ULOG_UNSUBSCRIBE(logger_fn5, ULOG_TRACE) == ULOG_ERR_NONE); 145 | 146 | assert(ULOG_UNSUBSCRIBE(logger_fn6) == ULOG_ERR_NOT_SUBSCRIBED); 147 | 148 | ULOG_TRACE("Hello!"); 149 | ULOG_DEBUG("Hello!"); 150 | ULOG_INFO("Hello!"); 151 | ULOG_WARNING("Hello!"); 152 | ULOG_ERROR("Hello!"); 153 | ULOG_CRITICAL("Hello!"); 154 | ULOG_ALWAYS("Hello!"); 155 | 156 | assert(fn_calls[0] == 0); // not subscribed... 157 | assert(fn_calls[1] == 0); 158 | assert(fn_calls[2] == 0); 159 | assert(fn_calls[3] == 0); 160 | assert(fn_calls[4] == 0); 161 | assert(fn_calls[5] == 7); // logger_fn5 is at trace level: all messages 162 | 163 | // ulog_level_name 164 | assert(strcmp(ulog_level_name(ULOG_TRACE_LEVEL), "TRACE") == 0); 165 | assert(strcmp(ulog_level_name(ULOG_DEBUG_LEVEL), "DEBUG") == 0); 166 | assert(strcmp(ulog_level_name(ULOG_INFO_LEVEL), "INFO") == 0); 167 | assert(strcmp(ulog_level_name(ULOG_WARNING_LEVEL), "WARNING") == 0); 168 | assert(strcmp(ulog_level_name(ULOG_ERROR_LEVEL), "ERROR") == 0); 169 | assert(strcmp(ulog_level_name(ULOG_CRITICAL_LEVEL), "CRITICAL") == 0); 170 | assert(strcmp(ulog_level_name(ULOG_ALWAYS_LEVEL), "ALWAYS") == 0); 171 | 172 | } 173 | -------------------------------------------------------------------------------- /tests/ulog_test.h: -------------------------------------------------------------------------------- 1 | /** 2 | MIT License 3 | 4 | Copyright (c) 2019 R. Dunbar Poor 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | this software and associated documentation files (the "Software"), to deal in 8 | the Software without restriction, including without limitation the rights to 9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | /** 25 | * \file ulog_test.h 26 | * 27 | * \brief unit testing for uLog logging mechanism 28 | */ 29 | 30 | #ifndef ULOG_TEST_H_ 31 | #define ULOG_TEST_H_ 32 | 33 | #ifdef __cplusplus 34 | extern "C" { 35 | #endif 36 | 37 | void ulog_test(); 38 | 39 | #ifdef __cplusplus 40 | } 41 | #endif 42 | 43 | #endif /* ULOG_TEST_H_ */ 44 | --------------------------------------------------------------------------------