mirror of https://github.com/nirenjan/pinelog.git
				
				
				
			Initial commit
						commit
						45762f497c
					
				|  | @ -0,0 +1,37 @@ | ||||||
|  | # Compiled object files | ||||||
|  | *.o | ||||||
|  | 
 | ||||||
|  | # Generated objects (source, executables, tarballs, etc.) | ||||||
|  | 
 | ||||||
|  | # Vim swap files | ||||||
|  | .*.swp | ||||||
|  | 
 | ||||||
|  | # Autotools objects | ||||||
|  | .deps | ||||||
|  | .dirstamp | ||||||
|  | .libs | ||||||
|  | ar-lib | ||||||
|  | autom4te.cache | ||||||
|  | m4 | ||||||
|  | compile | ||||||
|  | config.* | ||||||
|  | configure | ||||||
|  | depcomp | ||||||
|  | install-sh | ||||||
|  | libtool | ||||||
|  | ltmain.sh | ||||||
|  | missing | ||||||
|  | Makefile | ||||||
|  | Makefile.in | ||||||
|  | *.la | ||||||
|  | *.lo | ||||||
|  | *.m4 | ||||||
|  | stamp-h1 | ||||||
|  | tap-driver.sh | ||||||
|  | test-driver | ||||||
|  | *.log | ||||||
|  | *.trs | ||||||
|  | *.pc | ||||||
|  | 
 | ||||||
|  | # Build directory | ||||||
|  | /build/ | ||||||
|  | @ -0,0 +1,21 @@ | ||||||
|  | MIT License | ||||||
|  | 
 | ||||||
|  | Copyright (c) 2021 Nirenjan Krishnan | ||||||
|  | 
 | ||||||
|  | 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 the Software without restriction, including without limitation the rights | ||||||
|  | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  | copies of the Software, and to permit persons to whom the Software is | ||||||
|  | furnished to do so, subject to the following conditions: | ||||||
|  | 
 | ||||||
|  | The above copyright notice and this permission notice shall be included in all | ||||||
|  | copies or substantial portions of the Software. | ||||||
|  | 
 | ||||||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  | SOFTWARE. | ||||||
|  | @ -0,0 +1,6 @@ | ||||||
|  | Pinelog - a lightweight logging API | ||||||
|  | =================================== | ||||||
|  | 
 | ||||||
|  | Pinelog is a lightweight logging API for C programs that's designed to be | ||||||
|  | included in your program source code. Parameters for Pinelog are configured at | ||||||
|  | build time by means of preprocessor flags. | ||||||
|  | @ -0,0 +1,179 @@ | ||||||
|  | /*
 | ||||||
|  |  * Pinelog lightweight logging library | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2021 Nirenjan Krishnan (nirenjan@nirenjan.org) | ||||||
|  |  * | ||||||
|  |  * SPDX-License-Identifier: MIT | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdarg.h> | ||||||
|  | #include <time.h> | ||||||
|  | #include <errno.h> | ||||||
|  | 
 | ||||||
|  | #include "pinelog.h" | ||||||
|  | 
 | ||||||
|  | /**********************************************************************
 | ||||||
|  |  * Global variables | ||||||
|  |  *********************************************************************/ | ||||||
|  | 
 | ||||||
|  | /** Stream buffer */ | ||||||
|  | static FILE *output_stream = NULL; | ||||||
|  | 
 | ||||||
|  | /** Default logging level */ | ||||||
|  | static int log_level = LOG_LVL_ERROR; | ||||||
|  | 
 | ||||||
|  | /* Initialize defaults */ | ||||||
|  | void log_init_defaults(void) | ||||||
|  | { | ||||||
|  |     output_stream = stdout; | ||||||
|  |     log_level = LOG_LVL_ERROR; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int log_set_output_stream(FILE *stream) | ||||||
|  | { | ||||||
|  |     if (stream == NULL) { | ||||||
|  |         return EINVAL; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* If current output stream is not stdout or stderr, then close it */ | ||||||
|  |     if (output_stream != stdout && output_stream != stderr) { | ||||||
|  |         fclose(output_stream); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     setlinebuf(stream); | ||||||
|  |     output_stream = stream; | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int log_set_output_file(const char *file) | ||||||
|  | { | ||||||
|  |     FILE *stream; | ||||||
|  |     if (file == NULL) { | ||||||
|  |         return EINVAL; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     errno = 0; | ||||||
|  |     stream = fopen(file, "w"); | ||||||
|  |     if (stream == NULL) { | ||||||
|  |         return errno; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return log_set_output_stream(stream); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int log_get_level(void) | ||||||
|  | { | ||||||
|  |     return log_level; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int log_set_level(int level) | ||||||
|  | { | ||||||
|  |     if (level < LOG_LVL_NONE || level > LOG_LVL_TRACE) { | ||||||
|  |         return EINVAL; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     log_level = level; | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**********************************************************************
 | ||||||
|  |  * Configure logging parameters | ||||||
|  |  *********************************************************************/ | ||||||
|  | #ifndef PINELOG_SHOW_DATE | ||||||
|  | #define PINELOG_SHOW_DATE 0 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef PINELOG_SHOW_LEVEL | ||||||
|  | #define PINELOG_SHOW_LEVEL 0 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef PINELOG_SHOW_BACKTRACE | ||||||
|  | #define PINELOG_SHOW_BACKTRACE 0 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /**********************************************************************
 | ||||||
|  |  * Configure level strings | ||||||
|  |  *********************************************************************/ | ||||||
|  | #ifndef PINELOG_FATAL | ||||||
|  | #define PINELOG_FATAL "FATAL" | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef PINELOG_ERROR | ||||||
|  | #define PINELOG_ERROR "ERROR" | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef PINELOG_WARNING | ||||||
|  | #define PINELOG_WARNING "WARNING" | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef PINELOG_INFO | ||||||
|  | #define PINELOG_INFO "INFO" | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef PINELOG_DEBUG | ||||||
|  | #define PINELOG_DEBUG "DEBUG" | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef PINELOG_TRACE | ||||||
|  | #define PINELOG_TRACE "TRACE" | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /**********************************************************************
 | ||||||
|  |  * Log the message to the output stream | ||||||
|  |  *********************************************************************/ | ||||||
|  | void log_message(int level, const char *file, int line, const char *fmt, ...) | ||||||
|  | { | ||||||
|  |     va_list ap; | ||||||
|  | 
 | ||||||
|  |     /* Don't log anything if the level is not severe enough */ | ||||||
|  |     if (level > log_level || level < 0) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* Cap the log level */ | ||||||
|  |     if (level > LOG_LVL_TRACE) { | ||||||
|  |         level = LOG_LVL_TRACE; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* Validate and set output stream */ | ||||||
|  |     if (output_stream == NULL) { | ||||||
|  |         output_stream = stdout; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #if PINELOG_SHOW_DATE | ||||||
|  |     do { | ||||||
|  |         time_t t; | ||||||
|  |         struct tm *tmp; | ||||||
|  |         char date_string[20]; | ||||||
|  |         t = time(NULL); | ||||||
|  |         tmp = localtime(&t); | ||||||
|  |         strftime(date_string, sizeof(date_string), "%F %T ", tmp); | ||||||
|  |         fputs(date_string, out_stream); | ||||||
|  |     } while (0); | ||||||
|  |     #endif | ||||||
|  | 
 | ||||||
|  |     #if PINELOG_SHOW_LEVEL | ||||||
|  |     do { | ||||||
|  |         static const char *level_strings[] = { | ||||||
|  |             PINELOG_FATAL, | ||||||
|  |             PINELOG_ERROR, | ||||||
|  |             PINELOG_WARNING, | ||||||
|  |             PINELOG_INFO, | ||||||
|  |             PINELOG_DEBUG, | ||||||
|  |             PINELOG_TRACE, | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         fputs(level_strings[level], out_stream); | ||||||
|  |         fputs(": ", out_stream); | ||||||
|  |     } while (0) | ||||||
|  |     #endif | ||||||
|  | 
 | ||||||
|  |     #if PINELOG_SHOW_BACKTRACE | ||||||
|  |         fprintf(out_stream, "%s:%d ", file, line); | ||||||
|  |     #endif | ||||||
|  | 
 | ||||||
|  |     va_start(ap, fmt); | ||||||
|  |     vfprintf(output_stream, fmt, ap); | ||||||
|  |     va_end(ap); | ||||||
|  | } | ||||||
|  | @ -0,0 +1,151 @@ | ||||||
|  | /*
 | ||||||
|  |  * Pinelog lightweight logging library | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2021 Nirenjan Krishnan (nirenjan@nirenjan.org) | ||||||
|  |  * | ||||||
|  |  * SPDX-License-Identifier: MIT | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * @file logging.h | ||||||
|  |  * @brief Logging utility library | ||||||
|  |  * | ||||||
|  |  * This file contains the prototypes for the pinelog logging library | ||||||
|  |  * used by any programs that need to log messages. | ||||||
|  |  * | ||||||
|  |  * @author Nirenjan Krishnan (nirenjan@nirenjan.org) | ||||||
|  |  */ | ||||||
|  | #ifndef LOGGING_H | ||||||
|  | #define LOGGING_H | ||||||
|  | 
 | ||||||
|  | #include <stdio.h> | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * @brief Logging levels | ||||||
|  |  * | ||||||
|  |  * The log levels indicate the lowest severity level that will actually be | ||||||
|  |  * logged to the logging framework. | ||||||
|  |  */ | ||||||
|  | enum { | ||||||
|  |     /** No messages will be logged */ | ||||||
|  |     LOG_LVL_NONE = -1, | ||||||
|  | 
 | ||||||
|  |     /** Only fatal messages will be logged */ | ||||||
|  |     LOG_LVL_FATAL, | ||||||
|  | 
 | ||||||
|  |     /** Error messages. This is the default log level */ | ||||||
|  |     LOG_LVL_ERROR, | ||||||
|  | 
 | ||||||
|  |     /** Warning messages */ | ||||||
|  |     LOG_LVL_WARNING, | ||||||
|  | 
 | ||||||
|  |     /** Informational messages */ | ||||||
|  |     LOG_LVL_INFO, | ||||||
|  | 
 | ||||||
|  |     /** Debug messages */ | ||||||
|  |     LOG_LVL_DEBUG, | ||||||
|  | 
 | ||||||
|  |     /** Trace messages */ | ||||||
|  |     LOG_LVL_TRACE, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * @brief Initialize the logging library and set the defaults | ||||||
|  |  */ | ||||||
|  | void log_init_defaults(void); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * @brief Set the output stream. Must be a FILE pointer. | ||||||
|  |  * | ||||||
|  |  * @param[in]   stream  Pointer to the output stream | ||||||
|  |  * | ||||||
|  |  * @returns 0 on success, EINVAL if the pointer is not valid. | ||||||
|  |  */ | ||||||
|  | int log_set_output_stream(FILE *stream); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * @brief Set the output file. | ||||||
|  |  * | ||||||
|  |  * @param[in]   file    Filename to write to | ||||||
|  |  * | ||||||
|  |  * @returns 0 on success, EINVAL if the filename pointer is not valid, other | ||||||
|  |  * error if the file could not be opened for writing. | ||||||
|  |  */ | ||||||
|  | int log_set_output_file(const char *file); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * @brief Set the logging level | ||||||
|  |  * | ||||||
|  |  * @param[in]   level   Level to filter | ||||||
|  |  * | ||||||
|  |  * @returns 0 on success, EINVAL if the level is not valid | ||||||
|  |  */ | ||||||
|  | int log_set_level(int level); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * @brief Get the logging level | ||||||
|  |  * | ||||||
|  |  * @returns the configured logging level | ||||||
|  |  */ | ||||||
|  | int log_get_level(void); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * @brief Log a message to the logger | ||||||
|  |  * | ||||||
|  |  * This is the actual function that logs the message. The application should | ||||||
|  |  * never need to call this directly, but instead, should always use the | ||||||
|  |  * \code LOG_* macros. | ||||||
|  |  * | ||||||
|  |  * @param[in]   level   Level to log the message at | ||||||
|  |  * @param[in]   fmt     Format string | ||||||
|  |  * | ||||||
|  |  * @returns None | ||||||
|  |  */ | ||||||
|  | void log_message(int level, const char *file, int line, const char *fmt, ...); | ||||||
|  | 
 | ||||||
|  | #define LOG_FATAL(fmt, ...) do { \ | ||||||
|  |     if (LOG_LVL_FATAL <= log_get_level()) { \ | ||||||
|  |         log_message(LOG_LVL_FATAL, __FILE__, __LINE__, fmt, ##__VA_ARGS__); \ | ||||||
|  |     } \ | ||||||
|  |     exit(1); \ | ||||||
|  | } while (0) | ||||||
|  | 
 | ||||||
|  | #define LOG_ERROR(fmt, ...) do { \ | ||||||
|  |     if (LOG_LVL_ERROR <= log_get_level()) { \ | ||||||
|  |         log_message(LOG_LVL_ERROR, __FILE__, __LINE__, fmt, ##__VA_ARGS__); \ | ||||||
|  |     } \ | ||||||
|  | } while (0) | ||||||
|  | 
 | ||||||
|  | #define LOG_WARN(fmt, ...) do { \ | ||||||
|  |     if (LOG_LVL_WARNING <= log_get_level()) { \ | ||||||
|  |         log_message(LOG_LVL_WARNING, __FILE__, __LINE__, fmt, ##__VA_ARGS__); \ | ||||||
|  |     } \ | ||||||
|  | } while(0) | ||||||
|  | 
 | ||||||
|  | #define LOG_INFO(fmt, ...) do { \ | ||||||
|  |     if (LOG_LVL_INFO <= log_get_level()) { \ | ||||||
|  |         log_message(LOG_LVL_INFO, __FILE__, __LINE__, fmt, ##__VA_ARGS__); \ | ||||||
|  |     } \ | ||||||
|  | } while(0) | ||||||
|  | 
 | ||||||
|  | #define LOG_DEBUG(fmt, ...) do { \ | ||||||
|  |     if (LOG_LVL_DEBUG <= log_get_level()) { \ | ||||||
|  |         log_message(LOG_LVL_DEBUG, __FILE__, __LINE__, fmt, ##__VA_ARGS__); \ | ||||||
|  |     } \ | ||||||
|  | } while(0) | ||||||
|  | 
 | ||||||
|  | #define LOG_TRACE(fmt, ...) do { \ | ||||||
|  |     if (LOG_LVL_TRACE <= log_get_level()) { \ | ||||||
|  |         log_message(LOG_LVL_TRACE, __FILE__, __LINE__, fmt, ##__VA_ARGS__); \ | ||||||
|  |     } \ | ||||||
|  | } while(0) | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #endif // !defined LOGGING_H
 | ||||||
		Loading…
	
		Reference in New Issue