Update logging library to include module and string buffer

This commit adds the following changes to pinelog:

- Optional buffer to write the message to prior to writing to the output
  stream. This reduces the likelihood of log messages from multiple
  threads interleaving due to multiple calls to fputs/fprintf, etc. The
  default is to still write directly to the output stream, but the
  integrator can add a define of PINELOG_BUFFER_SZ to the CFLAGS, and
  this will allow the application to log messages that are shorter than
  the above size, including the timestamp, level and backtrace if any.

- Optional module level logging. This allows more fine-grained
  debugging, where the application can control the log levels of the
  individual modules. By default, when modules are configured, they
  default to the global log level, but this can be overridden by the
  application.
master
nirenjan 2021-11-08 16:18:30 -08:00
parent 5355a6ed8e
commit 3be94a24ba
4 changed files with 421 additions and 103 deletions

View File

@ -34,101 +34,198 @@ test_CFLAGS = \
LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) $(top_srcdir)/tap-driver.sh LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) $(top_srcdir)/tap-driver.sh
TESTS = \ TESTS = \
test_ts_lvl_tr \ fp_test_ts_lvl_tr \
test_ts_lvl_notr \ fp_test_ts_lvl_notr \
test_ts_nolvl_tr \ fp_test_ts_nolvl_tr \
test_ts_nolvl_notr \ fp_test_ts_nolvl_notr \
test_nots_lvl_tr \ fp_test_nots_lvl_tr \
test_nots_lvl_notr \ fp_test_nots_lvl_notr \
test_nots_nolvl_tr \ fp_test_nots_nolvl_tr \
test_nots_nolvl_notr \ fp_test_nots_nolvl_notr \
bench_ts_lvl_tr \ fp_bench_ts_lvl_tr \
bench_ts_lvl_notr \ fp_bench_ts_lvl_notr \
bench_ts_nolvl_tr \ fp_bench_ts_nolvl_tr \
bench_ts_nolvl_notr \ fp_bench_ts_nolvl_notr \
bench_nots_lvl_tr \ fp_bench_nots_lvl_tr \
bench_nots_lvl_notr \ fp_bench_nots_lvl_notr \
bench_nots_nolvl_tr \ fp_bench_nots_nolvl_tr \
bench_nots_nolvl_notr fp_bench_nots_nolvl_notr \
str_test_ts_lvl_tr \
str_test_ts_lvl_notr \
str_test_ts_nolvl_tr \
str_test_ts_nolvl_notr \
str_test_nots_lvl_tr \
str_test_nots_lvl_notr \
str_test_nots_nolvl_tr \
str_test_nots_nolvl_notr \
str_bench_ts_lvl_tr \
str_bench_ts_lvl_notr \
str_bench_ts_nolvl_tr \
str_bench_ts_nolvl_notr \
str_bench_nots_lvl_tr \
str_bench_nots_lvl_notr \
str_bench_nots_nolvl_tr \
str_bench_nots_nolvl_notr
check_PROGRAMS = $(TESTS) check_PROGRAMS = $(TESTS)
test_ts_lvl_tr_SOURCES = $(test_SRCFILES) fp_test_ts_lvl_tr_SOURCES = $(test_SRCFILES)
test_ts_lvl_tr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \ fp_test_ts_lvl_tr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=1 -DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_BACKTRACE=1 -DPINELOG_SHOW_DATE=1 -DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_BACKTRACE=1
test_ts_lvl_tr_LDFLAGS = $(WARN_LDFLAGS) fp_test_ts_lvl_tr_LDFLAGS = $(WARN_LDFLAGS)
test_ts_lvl_notr_SOURCES = $(test_SRCFILES) fp_test_ts_lvl_notr_SOURCES = $(test_SRCFILES)
test_ts_lvl_notr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \ fp_test_ts_lvl_notr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=1 -DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_BACKTRACE=0 -DPINELOG_SHOW_DATE=1 -DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_BACKTRACE=0
test_ts_lvl_notr_LDFLAGS = $(WARN_LDFLAGS) fp_test_ts_lvl_notr_LDFLAGS = $(WARN_LDFLAGS)
test_ts_nolvl_tr_SOURCES = $(test_SRCFILES) fp_test_ts_nolvl_tr_SOURCES = $(test_SRCFILES)
test_ts_nolvl_tr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \ fp_test_ts_nolvl_tr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=1 -DPINELOG_SHOW_LEVEL=0 -DPINELOG_SHOW_BACKTRACE=1 -DPINELOG_SHOW_DATE=1 -DPINELOG_SHOW_LEVEL=0 -DPINELOG_SHOW_BACKTRACE=1
test_ts_nolvl_tr_LDFLAGS = $(WARN_LDFLAGS) fp_test_ts_nolvl_tr_LDFLAGS = $(WARN_LDFLAGS)
test_ts_nolvl_notr_SOURCES = $(test_SRCFILES) fp_test_ts_nolvl_notr_SOURCES = $(test_SRCFILES)
test_ts_nolvl_notr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \ fp_test_ts_nolvl_notr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=1 -DPINELOG_SHOW_LEVEL=0 -DPINELOG_SHOW_BACKTRACE=0 -DPINELOG_SHOW_DATE=1 -DPINELOG_SHOW_LEVEL=0 -DPINELOG_SHOW_BACKTRACE=0
test_ts_nolvl_notr_LDFLAGS = $(WARN_LDFLAGS) fp_test_ts_nolvl_notr_LDFLAGS = $(WARN_LDFLAGS)
test_nots_lvl_tr_SOURCES = $(test_SRCFILES) fp_test_nots_lvl_tr_SOURCES = $(test_SRCFILES)
test_nots_lvl_tr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \ fp_test_nots_lvl_tr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=0 -DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_BACKTRACE=1 -DPINELOG_SHOW_DATE=0 -DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_BACKTRACE=1
test_nots_lvl_tr_LDFLAGS = $(WARN_LDFLAGS) fp_test_nots_lvl_tr_LDFLAGS = $(WARN_LDFLAGS)
test_nots_lvl_notr_SOURCES = $(test_SRCFILES) fp_test_nots_lvl_notr_SOURCES = $(test_SRCFILES)
test_nots_lvl_notr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \ fp_test_nots_lvl_notr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=0 -DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_BACKTRACE=0 -DPINELOG_SHOW_DATE=0 -DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_BACKTRACE=0
test_nots_lvl_notr_LDFLAGS = $(WARN_LDFLAGS) fp_test_nots_lvl_notr_LDFLAGS = $(WARN_LDFLAGS)
test_nots_nolvl_tr_SOURCES = $(test_SRCFILES) fp_test_nots_nolvl_tr_SOURCES = $(test_SRCFILES)
test_nots_nolvl_tr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \ fp_test_nots_nolvl_tr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=0 -DPINELOG_SHOW_LEVEL=0 -DPINELOG_SHOW_BACKTRACE=1 -DPINELOG_SHOW_DATE=0 -DPINELOG_SHOW_LEVEL=0 -DPINELOG_SHOW_BACKTRACE=1
test_nots_nolvl_tr_LDFLAGS = $(WARN_LDFLAGS) fp_test_nots_nolvl_tr_LDFLAGS = $(WARN_LDFLAGS)
test_nots_nolvl_notr_SOURCES = $(test_SRCFILES) fp_test_nots_nolvl_notr_SOURCES = $(test_SRCFILES)
test_nots_nolvl_notr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \ fp_test_nots_nolvl_notr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=0 -DPINELOG_SHOW_LEVEL=0 -DPINELOG_SHOW_BACKTRACE=0 -DPINELOG_SHOW_DATE=0 -DPINELOG_SHOW_LEVEL=0 -DPINELOG_SHOW_BACKTRACE=0
test_nots_nolvl_notr_LDFLAGS = $(WARN_LDFLAGS) fp_test_nots_nolvl_notr_LDFLAGS = $(WARN_LDFLAGS)
bench_ts_lvl_tr_SOURCES = $(bench_SRCFILES) fp_bench_ts_lvl_tr_SOURCES = $(bench_SRCFILES)
bench_ts_lvl_tr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \ fp_bench_ts_lvl_tr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=1 -DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_BACKTRACE=1 -DPINELOG_SHOW_DATE=1 -DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_BACKTRACE=1
bench_ts_lvl_tr_LDFLAGS = $(WARN_LDFLAGS) fp_bench_ts_lvl_tr_LDFLAGS = $(WARN_LDFLAGS)
bench_ts_lvl_notr_SOURCES = $(bench_SRCFILES) fp_bench_ts_lvl_notr_SOURCES = $(bench_SRCFILES)
bench_ts_lvl_notr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \ fp_bench_ts_lvl_notr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=1 -DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_BACKTRACE=0 -DPINELOG_SHOW_DATE=1 -DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_BACKTRACE=0
bench_ts_lvl_notr_LDFLAGS = $(WARN_LDFLAGS) fp_bench_ts_lvl_notr_LDFLAGS = $(WARN_LDFLAGS)
bench_ts_nolvl_tr_SOURCES = $(bench_SRCFILES) fp_bench_ts_nolvl_tr_SOURCES = $(bench_SRCFILES)
bench_ts_nolvl_tr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \ fp_bench_ts_nolvl_tr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=1 -DPINELOG_SHOW_LEVEL=0 -DPINELOG_SHOW_BACKTRACE=1 -DPINELOG_SHOW_DATE=1 -DPINELOG_SHOW_LEVEL=0 -DPINELOG_SHOW_BACKTRACE=1
bench_ts_nolvl_tr_LDFLAGS = $(WARN_LDFLAGS) fp_bench_ts_nolvl_tr_LDFLAGS = $(WARN_LDFLAGS)
bench_ts_nolvl_notr_SOURCES = $(bench_SRCFILES) fp_bench_ts_nolvl_notr_SOURCES = $(bench_SRCFILES)
bench_ts_nolvl_notr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \ fp_bench_ts_nolvl_notr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=1 -DPINELOG_SHOW_LEVEL=0 -DPINELOG_SHOW_BACKTRACE=0 -DPINELOG_SHOW_DATE=1 -DPINELOG_SHOW_LEVEL=0 -DPINELOG_SHOW_BACKTRACE=0
bench_ts_nolvl_notr_LDFLAGS = $(WARN_LDFLAGS) fp_bench_ts_nolvl_notr_LDFLAGS = $(WARN_LDFLAGS)
bench_nots_lvl_tr_SOURCES = $(bench_SRCFILES) fp_bench_nots_lvl_tr_SOURCES = $(bench_SRCFILES)
bench_nots_lvl_tr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \ fp_bench_nots_lvl_tr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=0 -DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_BACKTRACE=1 -DPINELOG_SHOW_DATE=0 -DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_BACKTRACE=1
bench_nots_lvl_tr_LDFLAGS = $(WARN_LDFLAGS) fp_bench_nots_lvl_tr_LDFLAGS = $(WARN_LDFLAGS)
bench_nots_lvl_notr_SOURCES = $(bench_SRCFILES) fp_bench_nots_lvl_notr_SOURCES = $(bench_SRCFILES)
bench_nots_lvl_notr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \ fp_bench_nots_lvl_notr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=0 -DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_BACKTRACE=0 -DPINELOG_SHOW_DATE=0 -DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_BACKTRACE=0
bench_nots_lvl_notr_LDFLAGS = $(WARN_LDFLAGS) fp_bench_nots_lvl_notr_LDFLAGS = $(WARN_LDFLAGS)
bench_nots_nolvl_tr_SOURCES = $(bench_SRCFILES) fp_bench_nots_nolvl_tr_SOURCES = $(bench_SRCFILES)
bench_nots_nolvl_tr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \ fp_bench_nots_nolvl_tr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=0 -DPINELOG_SHOW_LEVEL=0 -DPINELOG_SHOW_BACKTRACE=1 -DPINELOG_SHOW_DATE=0 -DPINELOG_SHOW_LEVEL=0 -DPINELOG_SHOW_BACKTRACE=1
bench_nots_nolvl_tr_LDFLAGS = $(WARN_LDFLAGS) fp_bench_nots_nolvl_tr_LDFLAGS = $(WARN_LDFLAGS)
bench_nots_nolvl_notr_SOURCES = $(bench_SRCFILES) fp_bench_nots_nolvl_notr_SOURCES = $(bench_SRCFILES)
bench_nots_nolvl_notr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \ fp_bench_nots_nolvl_notr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=0 -DPINELOG_SHOW_LEVEL=0 -DPINELOG_SHOW_BACKTRACE=0 -DPINELOG_SHOW_DATE=0 -DPINELOG_SHOW_LEVEL=0 -DPINELOG_SHOW_BACKTRACE=0
bench_nots_nolvl_notr_LDFLAGS = $(WARN_LDFLAGS) fp_bench_nots_nolvl_notr_LDFLAGS = $(WARN_LDFLAGS)
test_CFLAGS += -DPINELOG_BUFFER_SZ=4096
str_test_ts_lvl_tr_SOURCES = $(test_SRCFILES)
str_test_ts_lvl_tr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=1 -DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_BACKTRACE=1
str_test_ts_lvl_tr_LDFLAGS = $(WARN_LDFLAGS)
str_test_ts_lvl_notr_SOURCES = $(test_SRCFILES)
str_test_ts_lvl_notr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=1 -DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_BACKTRACE=0
str_test_ts_lvl_notr_LDFLAGS = $(WARN_LDFLAGS)
str_test_ts_nolvl_tr_SOURCES = $(test_SRCFILES)
str_test_ts_nolvl_tr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=1 -DPINELOG_SHOW_LEVEL=0 -DPINELOG_SHOW_BACKTRACE=1
str_test_ts_nolvl_tr_LDFLAGS = $(WARN_LDFLAGS)
str_test_ts_nolvl_notr_SOURCES = $(test_SRCFILES)
str_test_ts_nolvl_notr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=1 -DPINELOG_SHOW_LEVEL=0 -DPINELOG_SHOW_BACKTRACE=0
str_test_ts_nolvl_notr_LDFLAGS = $(WARN_LDFLAGS)
str_test_nots_lvl_tr_SOURCES = $(test_SRCFILES)
str_test_nots_lvl_tr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=0 -DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_BACKTRACE=1
str_test_nots_lvl_tr_LDFLAGS = $(WARN_LDFLAGS)
str_test_nots_lvl_notr_SOURCES = $(test_SRCFILES)
str_test_nots_lvl_notr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=0 -DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_BACKTRACE=0
str_test_nots_lvl_notr_LDFLAGS = $(WARN_LDFLAGS)
str_test_nots_nolvl_tr_SOURCES = $(test_SRCFILES)
str_test_nots_nolvl_tr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=0 -DPINELOG_SHOW_LEVEL=0 -DPINELOG_SHOW_BACKTRACE=1
str_test_nots_nolvl_tr_LDFLAGS = $(WARN_LDFLAGS)
str_test_nots_nolvl_notr_SOURCES = $(test_SRCFILES)
str_test_nots_nolvl_notr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=0 -DPINELOG_SHOW_LEVEL=0 -DPINELOG_SHOW_BACKTRACE=0
str_test_nots_nolvl_notr_LDFLAGS = $(WARN_LDFLAGS)
str_bench_ts_lvl_tr_SOURCES = $(bench_SRCFILES)
str_bench_ts_lvl_tr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=1 -DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_BACKTRACE=1
str_bench_ts_lvl_tr_LDFLAGS = $(WARN_LDFLAGS)
str_bench_ts_lvl_notr_SOURCES = $(bench_SRCFILES)
str_bench_ts_lvl_notr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=1 -DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_BACKTRACE=0
str_bench_ts_lvl_notr_LDFLAGS = $(WARN_LDFLAGS)
str_bench_ts_nolvl_tr_SOURCES = $(bench_SRCFILES)
str_bench_ts_nolvl_tr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=1 -DPINELOG_SHOW_LEVEL=0 -DPINELOG_SHOW_BACKTRACE=1
str_bench_ts_nolvl_tr_LDFLAGS = $(WARN_LDFLAGS)
str_bench_ts_nolvl_notr_SOURCES = $(bench_SRCFILES)
str_bench_ts_nolvl_notr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=1 -DPINELOG_SHOW_LEVEL=0 -DPINELOG_SHOW_BACKTRACE=0
str_bench_ts_nolvl_notr_LDFLAGS = $(WARN_LDFLAGS)
str_bench_nots_lvl_tr_SOURCES = $(bench_SRCFILES)
str_bench_nots_lvl_tr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=0 -DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_BACKTRACE=1
str_bench_nots_lvl_tr_LDFLAGS = $(WARN_LDFLAGS)
str_bench_nots_lvl_notr_SOURCES = $(bench_SRCFILES)
str_bench_nots_lvl_notr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=0 -DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_BACKTRACE=0
str_bench_nots_lvl_notr_LDFLAGS = $(WARN_LDFLAGS)
str_bench_nots_nolvl_tr_SOURCES = $(bench_SRCFILES)
str_bench_nots_nolvl_tr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=0 -DPINELOG_SHOW_LEVEL=0 -DPINELOG_SHOW_BACKTRACE=1
str_bench_nots_nolvl_tr_LDFLAGS = $(WARN_LDFLAGS)
str_bench_nots_nolvl_notr_SOURCES = $(bench_SRCFILES)
str_bench_nots_nolvl_notr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \
-DPINELOG_SHOW_DATE=0 -DPINELOG_SHOW_LEVEL=0 -DPINELOG_SHOW_BACKTRACE=0
str_bench_nots_nolvl_notr_LDFLAGS = $(WARN_LDFLAGS)

155
pinelog.c
View File

@ -8,6 +8,8 @@
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h> #include <time.h>
#include <errno.h> #include <errno.h>
@ -24,6 +26,15 @@
#define PINELOG_DEFAULT_LEVEL PINELOG_LVL_ERROR #define PINELOG_DEFAULT_LEVEL PINELOG_LVL_ERROR
#endif #endif
/*
* Buffer size is used to create an automatic buffer. Set to 0 to disable,
* and write directly to the output stream. The drawback is that log messages
* from multiple threads may be interleaved without a buffer.
*/
#ifndef PINELOG_BUFFER_SZ
#define PINELOG_BUFFER_SZ 0
#endif
/********************************************************************** /**********************************************************************
* Configure logging parameters * Configure logging parameters
*********************************************************************/ *********************************************************************/
@ -76,6 +87,15 @@ static FILE *output_stream = NULL;
/** Default logging level */ /** Default logging level */
static int log_level = PINELOG_DEFAULT_LEVEL; static int log_level = PINELOG_DEFAULT_LEVEL;
/** Number of modules */
static int num_modules = 0;
/** Per module logging levels */
static int *module_level = NULL;
/** Module names */
static const char **module_name = NULL;
/* Initialize defaults */ /* Initialize defaults */
#if defined __has_attribute #if defined __has_attribute
# if __has_attribute(constructor) # if __has_attribute(constructor)
@ -88,6 +108,42 @@ void pinelog_set_defaults(void)
log_level = PINELOG_DEFAULT_LEVEL; log_level = PINELOG_DEFAULT_LEVEL;
} }
int pinelog_init(int count) {
int rc = 0;
int i;
if (count <= 0) {
return EINVAL;
}
num_modules = count;
free(module_level);
free(module_name);
module_level = calloc(sizeof(*module_level), count);
if (module_level == NULL) {
rc = errno;
goto cleanup;
}
module_name = calloc(sizeof(*module_name), count);
if (module_name == NULL) {
rc = errno;
goto cleanup;
}
for (i = 0; i < count; i++) {
module_level[i] = PINELOG_LVL_NOTSET;
}
return 0;
cleanup:
num_modules = 0;
free(module_level);
free(module_name);
return rc;
}
#if defined __has_attribute #if defined __has_attribute
# if __has_attribute(destructor) # if __has_attribute(destructor)
__attribute__((destructor)) __attribute__((destructor))
@ -153,15 +209,73 @@ int pinelog_set_level(int level)
return 0; return 0;
} }
int pinelog_get_module_level(int module)
{
int global_level = pinelog_get_level();
int level = global_level;
if (module >= 0 && module < num_modules) {
level = module_level[module];
if (level == PINELOG_LVL_NOTSET) {
level = global_level;
}
}
return level;
}
int pinelog_set_module_level(int module, int level)
{
if (module < 0 || module > num_modules) {
if (module == PINELOG_MODULE_GLOBAL) {
return pinelog_set_level(level);
}
return ERANGE;
}
if (level < PINELOG_LVL_NOTSET || level > PINELOG_LVL_TRACE) {
return EINVAL;
}
module_level[module] = level;
return 0;
}
int pinelog_setup_module(int module, const char *name)
{
if (module < 0 || module > num_modules) {
return ERANGE;
}
if (name == NULL) {
return EINVAL;
}
module_name[module] = name;
return 0;
}
/********************************************************************** /**********************************************************************
* Log the message to the output stream * Log the message to the output stream
*********************************************************************/ *********************************************************************/
void pinelog_log_message(int level, const char *file, int line, const char *fmt, ...) void pinelog_log_message(int module, int level, const char *file, int line, const char *fmt, ...)
{ {
#if PINELOG_BUFFER_SZ
char output_buffer[PINELOG_BUFFER_SZ];
size_t buf_pos = 0;
#endif
va_list ap; va_list ap;
/* Break out if the module is not in the acceptable range */
if ((module < 0 || module >= num_modules ) && module != PINELOG_MODULE_GLOBAL) {
return;
}
/* Reset the level if we are in a module and the level is NOTSET */
/* Don't log anything if the level is not severe enough */ /* Don't log anything if the level is not severe enough */
if (level > log_level || level < 0) { if (level > pinelog_get_module_level(module) || level < 0) {
return; return;
} }
@ -187,12 +301,17 @@ void pinelog_log_message(int level, const char *file, int line, const char *fmt,
time_t t; time_t t;
struct tm tm1; struct tm tm1;
struct tm *tmp; struct tm *tmp;
char date_string[30];
t = time(NULL); t = time(NULL);
tmp = localtime_r(&t, &tm1); tmp = localtime_r(&t, &tm1);
if (tmp != NULL) { if (tmp != NULL) {
#if PINELOG_BUFFER_SZ
buf_pos += strftime(output_buffer + buf_pos, sizeof(output_buffer) - buf_pos,
"%F %T ", tmp);
#else
char date_string[30];
strftime(date_string, sizeof(date_string), "%F %T ", tmp); strftime(date_string, sizeof(date_string), "%F %T ", tmp);
fputs(date_string, output_stream); fputs(date_string, output_stream);
#endif
} }
} while (0); } while (0);
#endif #endif
@ -208,18 +327,46 @@ void pinelog_log_message(int level, const char *file, int line, const char *fmt,
PINELOG_TRACE_STR, PINELOG_TRACE_STR,
}; };
#if PINELOG_BUFFER_SZ
buf_pos += snprintf(output_buffer + buf_pos, sizeof(output_buffer) - buf_pos,
"%s: ", level_strings[level]);
#else
fputs(level_strings[level], output_stream); fputs(level_strings[level], output_stream);
fputs(": ", output_stream); fputs(": ", output_stream);
#endif
} while (0); } while (0);
#endif #endif
#if PINELOG_SHOW_BACKTRACE #if PINELOG_SHOW_BACKTRACE
#if PINELOG_BUFFER_SZ
buf_pos += snprintf(output_buffer + buf_pos, sizeof(output_buffer) - buf_pos,
"%s:%d ", file, line);
#else
fprintf(output_stream, "%s:%d ", file, line); fprintf(output_stream, "%s:%d ", file, line);
#endif
#endif #endif
/* Set the module name if it is not the root */
if (module != PINELOG_MODULE_GLOBAL) {
#if PINELOG_BUFFER_SZ
buf_pos += snprintf(output_buffer + buf_pos, sizeof(output_buffer) - buf_pos,
"%s: ", module_name[module]);
#else
fprintf(output_stream, "%s: ", module_name[module]);
#endif
}
va_start(ap, fmt); va_start(ap, fmt);
#if PINELOG_BUFFER_SZ
buf_pos += vsnprintf(output_buffer + buf_pos, sizeof(output_buffer) - buf_pos,
fmt, ap);
// Append a trailing newline to flush the log message
buf_pos += snprintf(output_buffer + buf_pos, sizeof(output_buffer) - buf_pos, "\n");
fputs(output_buffer, output_stream);
#else
vfprintf(output_stream, fmt, ap); vfprintf(output_stream, fmt, ap);
va_end(ap);
// Append a trailing newline to flush the log message // Append a trailing newline to flush the log message
fputs("\n", output_stream); fputs("\n", output_stream);
#endif
va_end(ap);
} }

View File

@ -34,6 +34,12 @@ extern "C" {
* logged to the logging framework. * logged to the logging framework.
*/ */
enum { enum {
/**
* In modules, it will defer to the global level.
* Equivalent to \ref PINELOG_LVL_NONE for the global level
*/
PINELOG_LVL_NOTSET = -2,
/** No messages will be logged */ /** No messages will be logged */
PINELOG_LVL_NONE = -1, PINELOG_LVL_NONE = -1,
@ -61,6 +67,25 @@ enum {
*/ */
void pinelog_set_defaults(void); void pinelog_set_defaults(void);
/**
* @brief Initialize pinelog to have these many modules
*
* @param[in] num_modules Maximum number of modules
*
* @returns 0 on success, errno on failure.
*/
int pinelog_init(int num_modules);
/**
* @brief Save the current module name
*
* @param[in] module Module identifier
* @param[in] name Module name - displayed in logs
*
* @returns 0 on success, errno on failure.
*/
int pinelog_setup_module(int module, const char *name);
/** /**
* @brief Close the output stream and terminate the logs * @brief Close the output stream and terminate the logs
*/ */
@ -95,7 +120,7 @@ int pinelog_set_output_stream(FILE *stream);
int pinelog_set_output_file(const char *file); int pinelog_set_output_file(const char *file);
/** /**
* @brief Set the logging level * @brief Set the global logging level
* *
* @param[in] level Level to filter * @param[in] level Level to filter
* *
@ -104,12 +129,32 @@ int pinelog_set_output_file(const char *file);
int pinelog_set_level(int level); int pinelog_set_level(int level);
/** /**
* @brief Get the logging level * @brief Get the global logging level
* *
* @returns the configured logging level * @returns the configured global logging level
*/ */
int pinelog_get_level(void); int pinelog_get_level(void);
/**
* @brief Set the per-module logging level
*
* @param[in] module Module identifier
* @param[in] level Level to filter
*
* @returns 0 on success, EINVAL if the level or module identifier is not valid
*/
int pinelog_set_module_level(int module, int level);
/**
* @brief Get the per-module logging level
*
* @param[in] module Module identifier
*
* @returns the configured per-module logging level, or the global logging level
* if the module identifier is outside the configured range.
*/
int pinelog_get_module_level(int module);
/** /**
* @brief Log a message to the logger * @brief Log a message to the logger
* *
@ -117,6 +162,7 @@ int pinelog_get_level(void);
* never need to call this directly, but instead, should always use the * never need to call this directly, but instead, should always use the
* \code PINELOG_* macros. * \code PINELOG_* macros.
* *
* @param[in] module Module identifier
* @param[in] level Level to log the message at * @param[in] level Level to log the message at
* @param[in] fmt Format string * @param[in] fmt Format string
* *
@ -124,10 +170,10 @@ int pinelog_get_level(void);
*/ */
#if defined __has_attribute #if defined __has_attribute
# if __has_attribute(format) # if __has_attribute(format)
__attribute__((format(printf, 4, 5))) __attribute__((format(printf, 5, 6)))
# endif # endif
#endif #endif
void pinelog_log_message(int level, const char *file, int line, const char *fmt, ...); void pinelog_log_message(int module, int level, const char *file, int line, const char *fmt, ...);
// Test harness will redefine pinelog_exit // Test harness will redefine pinelog_exit
#ifndef PINELOG_TEST #ifndef PINELOG_TEST
@ -144,42 +190,49 @@ void pinelog_log_message(int level, const char *file, int line, const char *fmt,
# define PINELOG_FILE __FILE__ # define PINELOG_FILE __FILE__
#endif #endif
// Global module - used for generic logging
#define PINELOG_MODULE_GLOBAL -1
#ifndef PINELOG_MODULE
#define PINELOG_MODULE PINELOG_MODULE_GLOBAL
#endif
#define PINELOG_FATAL(fmt, ...) do { \ #define PINELOG_FATAL(fmt, ...) do { \
if (PINELOG_LVL_FATAL <= pinelog_get_level()) { \ if (PINELOG_LVL_FATAL <= pinelog_get_module_level(PINELOG_MODULE)) { \
pinelog_log_message(PINELOG_LVL_FATAL, PINELOG_FILE, __LINE__, fmt, ##__VA_ARGS__); \ pinelog_log_message(PINELOG_MODULE, PINELOG_LVL_FATAL, PINELOG_FILE, __LINE__, fmt, ##__VA_ARGS__); \
} \ } \
pinelog_exit(1); \ pinelog_exit(1); \
} while (0) } while (0)
#define PINELOG_ERROR(fmt, ...) do { \ #define PINELOG_ERROR(fmt, ...) do { \
if (PINELOG_LVL_ERROR <= pinelog_get_level()) { \ if (PINELOG_LVL_ERROR <= pinelog_get_module_level(PINELOG_MODULE)) { \
pinelog_log_message(PINELOG_LVL_ERROR, PINELOG_FILE, __LINE__, fmt, ##__VA_ARGS__); \ pinelog_log_message(PINELOG_MODULE, PINELOG_LVL_ERROR, PINELOG_FILE, __LINE__, fmt, ##__VA_ARGS__); \
} \ } \
} while (0) } while (0)
#define PINELOG_WARN(fmt, ...) do { \ #define PINELOG_WARN(fmt, ...) do { \
if (PINELOG_LVL_WARNING <= pinelog_get_level()) { \ if (PINELOG_LVL_WARNING <= pinelog_get_module_level(PINELOG_MODULE)) { \
pinelog_log_message(PINELOG_LVL_WARNING, PINELOG_FILE, __LINE__, fmt, ##__VA_ARGS__); \ pinelog_log_message(PINELOG_MODULE, PINELOG_LVL_WARNING, PINELOG_FILE, __LINE__, fmt, ##__VA_ARGS__); \
} \ } \
} while(0) } while(0)
#define PINELOG_INFO(fmt, ...) do { \ #define PINELOG_INFO(fmt, ...) do { \
if (PINELOG_LVL_INFO <= pinelog_get_level()) { \ if (PINELOG_LVL_INFO <= pinelog_get_module_level(PINELOG_MODULE)) { \
pinelog_log_message(PINELOG_LVL_INFO, PINELOG_FILE, __LINE__, fmt, ##__VA_ARGS__); \ pinelog_log_message(PINELOG_MODULE, PINELOG_LVL_INFO, PINELOG_FILE, __LINE__, fmt, ##__VA_ARGS__); \
} \ } \
} while(0) } while(0)
#define PINELOG_DEBUG(fmt, ...) do { \ #define PINELOG_DEBUG(fmt, ...) do { \
if (PINELOG_LVL_DEBUG <= pinelog_get_level()) { \ if (PINELOG_LVL_DEBUG <= pinelog_get_module_level(PINELOG_MODULE)) { \
pinelog_log_message(PINELOG_LVL_DEBUG, PINELOG_FILE, __LINE__, fmt, ##__VA_ARGS__); \ pinelog_log_message(PINELOG_MODULE, PINELOG_LVL_DEBUG, PINELOG_FILE, __LINE__, fmt, ##__VA_ARGS__); \
} \ } \
} while(0) } while(0)
/* PINELOG_DISABLE_TRACE allows all traces to be compiled out */ /* PINELOG_DISABLE_TRACE allows all traces to be compiled out */
#ifndef PINELOG_DISABLE_TRACE #ifndef PINELOG_DISABLE_TRACE
#define PINELOG_TRACE(fmt, ...) do { \ #define PINELOG_TRACE(fmt, ...) do { \
if (PINELOG_LVL_TRACE <= pinelog_get_level()) { \ if (PINELOG_LVL_TRACE <= pinelog_get_module_level(PINELOG_MODULE)) { \
pinelog_log_message(PINELOG_LVL_TRACE, PINELOG_FILE, __LINE__, fmt, ##__VA_ARGS__); \ pinelog_log_message(PINELOG_MODULE, PINELOG_LVL_TRACE, PINELOG_FILE, __LINE__, fmt, ##__VA_ARGS__); \
} \ } \
} while(0) } while(0)
#else #else

View File

@ -64,7 +64,7 @@ static void dump_data(const char *type, size_t len, char *data)
printf("\n"); printf("\n");
} }
static int test_setup(int level, int filter, const char *file, int line) static int test_setup(int module, int level, int filter, const char *file, int line)
{ {
expected_len = 0; expected_len = 0;
memset(expected_output, 0, sizeof(expected_output)); memset(expected_output, 0, sizeof(expected_output));
@ -114,6 +114,12 @@ static int test_setup(int level, int filter, const char *file, int line)
"%s:%d ", basename, line); "%s:%d ", basename, line);
} }
if (module >= 0) {
static const char * modules[] = {"foo", "bar"};
expected_len += snprintf(&expected_output[expected_len],
sizeof(expected_output) - expected_len,
"%s: ", modules[module]);
}
return 1; return 1;
} }
@ -148,24 +154,29 @@ static void verify_defaults(void)
#define PINELOG_WARNING PINELOG_WARN #define PINELOG_WARNING PINELOG_WARN
#define TEST_LOG(lvl, filter, fmt, ...) do { \ #define TEST_LOG(module, lvl, filter, fmt, ...) do { \
if (test_setup(PINELOG_LVL_ ## lvl, PINELOG_LVL_ ## filter, \ if (test_setup(module, PINELOG_LVL_ ## lvl, PINELOG_LVL_ ## filter, \
__FILE__, __LINE__)) \ __FILE__, __LINE__)) \
expected_len += snprintf(&expected_output[expected_len], \ expected_len += snprintf(&expected_output[expected_len], \
sizeof(expected_output) - expected_len, \ sizeof(expected_output) - expected_len, \
fmt "\n", ##__VA_ARGS__); \ fmt "\n", ##__VA_ARGS__); \
PINELOG_ ## lvl (fmt, ##__VA_ARGS__); \ PINELOG_ ## lvl (fmt, ##__VA_ARGS__); \
test_teardown("Log " #lvl " filter " #filter); \ switch (module) { \
case -1: test_teardown("Global Log " #lvl " filter " #filter); break; \
case 0: test_teardown("Module foo Log " #lvl " filter " #filter); break; \
case 1: test_teardown("Module bar Log " #lvl " filter " #filter); break; \
default: test_teardown("Module ??? Log " #lvl " filter " #filter); break; \
} \
} while(0) } while(0)
#define TEST(filter, fmt, ...) do { \ #define TEST(module, filter, fmt, ...) do { \
pinelog_set_level(PINELOG_LVL_ ## filter); \ pinelog_set_level(PINELOG_LVL_ ## filter); \
TEST_LOG(TRACE, filter, fmt, ##__VA_ARGS__); \ TEST_LOG(module, TRACE, filter, fmt, ##__VA_ARGS__); \
TEST_LOG(DEBUG, filter, fmt, ##__VA_ARGS__); \ TEST_LOG(module, DEBUG, filter, fmt, ##__VA_ARGS__); \
TEST_LOG(INFO, filter, fmt, ##__VA_ARGS__); \ TEST_LOG(module, INFO, filter, fmt, ##__VA_ARGS__); \
TEST_LOG(WARNING, filter, fmt, ##__VA_ARGS__); \ TEST_LOG(module, WARNING, filter, fmt, ##__VA_ARGS__); \
TEST_LOG(ERROR, filter, fmt, ##__VA_ARGS__); \ TEST_LOG(module, ERROR, filter, fmt, ##__VA_ARGS__); \
TEST_LOG(FATAL, filter, fmt, ##__VA_ARGS__); \ TEST_LOG(module, FATAL, filter, fmt, ##__VA_ARGS__); \
} while (0) } while (0)
#if defined __has_attribute #if defined __has_attribute
@ -210,14 +221,24 @@ int main(int argc, char **argv)
verify_defaults(); verify_defaults();
pinelog_init(2);
pinelog_setup_module(0, "foo");
pinelog_setup_module(1, "bar");
pinelog_set_output_stream(observed_stream_w); pinelog_set_output_stream(observed_stream_w);
TEST(TRACE, "testing %s... %d, %f, %u", "testing", -1, 0.0, 1); for (int i = -1; i < 2; i++) {
TEST(DEBUG, "testing %s... %d, %f, %u", "testing", -1, 0.0, 1); #ifdef PINELOG_MODULE
TEST(INFO, "testing %s... %d, %f, %u", "testing", -1, 0.0, 1); #undef PINELOG_MODULE
TEST(WARNING, "testing %s... %d, %f, %u", "testing", -1, 0.0, 1); #define PINELOG_MODULE i
TEST(ERROR, "testing %s... %d, %f, %u", "testing", -1, 0.0, 1); #endif
TEST(FATAL, "testing %s... %d, %f, %u", "testing", -1, 0.0, 1); TEST(i, TRACE, "testing %s... %d, %f, %u", "testing", -1, 0.0, 1);
TEST(NONE, "testing %s... %d, %f, %u", "testing", -1, 0.0, 1); TEST(i, DEBUG, "testing %s... %d, %f, %u", "testing", -1, 0.0, 1);
TEST(i, INFO, "testing %s... %d, %f, %u", "testing", -1, 0.0, 1);
TEST(i, WARNING, "testing %s... %d, %f, %u", "testing", -1, 0.0, 1);
TEST(i, ERROR, "testing %s... %d, %f, %u", "testing", -1, 0.0, 1);
TEST(i, FATAL, "testing %s... %d, %f, %u", "testing", -1, 0.0, 1);
TEST(i, NONE, "testing %s... %d, %f, %u", "testing", -1, 0.0, 1);
}
printf("1..%u\n", test_id); printf("1..%u\n", test_id);