1095 lines
39 KiB
C
1095 lines
39 KiB
C
#ifndef LOGMOD_H
|
|
#define LOGMOD_H
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif /* __cplusplus */
|
|
|
|
/**
|
|
* @brief Define symbol visibility for LogMod API
|
|
*
|
|
* Define LOGMOD_STATIC to make all symbols static (for single-file inclusion)
|
|
*/
|
|
#ifdef LOGMOD_STATIC
|
|
#define LOGMOD_API static
|
|
#else
|
|
#define LOGMOD_API extern
|
|
#endif /* LOGMOD_STATIC */
|
|
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <time.h>
|
|
|
|
/**
|
|
* @brief Format string checking attribute for printf-like functions
|
|
*
|
|
* This macro adds format string checking when supported by the compiler,
|
|
* helping catch format string errors at compile time.
|
|
*
|
|
* @param a Format string parameter position
|
|
* @param b First variadic argument position
|
|
*/
|
|
#if defined(__MINGW32__) \
|
|
|| (defined(__GNUC__) && __GNUC__ > 4 ? true : __GNUC_PATCHLEVEL__ >= 4) \
|
|
|| defined(__USE_MINGW_ANSI_STDIO)
|
|
#define LOGMOD_PRINTF_LIKE(a, b) __attribute__((format(gnu_printf, a, b)))
|
|
#else
|
|
#define LOGMOD_PRINTF_LIKE(a, b)
|
|
#endif
|
|
|
|
/**
|
|
* @brief Default application ID for the fallback logger
|
|
*
|
|
* Can be overridden by defining this macro before including logmod.h
|
|
*/
|
|
#ifndef LOGMOD_FALLBACK_APPLICATION_ID
|
|
#define LOGMOD_FALLBACK_APPLICATION_ID "APPLICATION"
|
|
#endif /* LOGMOD_FALLBACK_APPLICATION_ID */
|
|
|
|
/**
|
|
* @brief Default context ID for the fallback logger
|
|
*
|
|
* Can be overridden by defining this macro before including logmod.h
|
|
*/
|
|
#ifndef LOGMOD_FALLBACK_CONTEXT_ID
|
|
#define LOGMOD_FALLBACK_CONTEXT_ID "GLOBAL"
|
|
#endif /* LOGMOD_FALLBACK_CONTEXT_ID */
|
|
|
|
/**
|
|
* @brief Log levels supported by LogMod
|
|
*
|
|
* Built-in log levels ordered by severity (lowest to highest)
|
|
* Custom log levels should start at LOGMOD_LEVEL_CUSTOM
|
|
*/
|
|
enum logmod_levels {
|
|
LOGMOD_LEVEL_TRACE = 0, /**< Most detailed logging for tracing execution */
|
|
LOGMOD_LEVEL_DEBUG, /**< Debug information */
|
|
LOGMOD_LEVEL_INFO, /**< Informational messages */
|
|
LOGMOD_LEVEL_WARN, /**< Warning messages */
|
|
LOGMOD_LEVEL_ERROR, /**< Error messages */
|
|
LOGMOD_LEVEL_FATAL, /**< Fatal errors that cause termination */
|
|
__LOGMOD_LEVEL_MAX, /**< Internal marker for built-in level count */
|
|
/** user defined log level must start with this value */
|
|
LOGMOD_LEVEL_CUSTOM = __LOGMOD_LEVEL_MAX
|
|
};
|
|
|
|
/**
|
|
* @brief Error codes returned by LogMod functions
|
|
*/
|
|
typedef enum {
|
|
LOGMOD_ERRNO = -2, /**< System error, check errno */
|
|
LOGMOD_BAD_PARAMETER = -1, /**< Invalid parameter passed to function */
|
|
LOGMOD_OK = 0, /**< Success */
|
|
LOGMOD_OK_CONTINUE, /**< Success, continue with default behavior */
|
|
LOGMOD_OK_SKIPPED /**< Success, logger has been skipped from logging due to
|
|
being disabled by user */
|
|
} logmod_err;
|
|
|
|
/**
|
|
* @brief Configuration options for a logger
|
|
*/
|
|
struct logmod_options {
|
|
FILE *logfile; /**< File to write logs to, or NULL for no file output */
|
|
int quiet; /**< If 1, suppress console output */
|
|
int color; /**< If 1, enable ANSI colors on console output */
|
|
int hide_context_id; /**< If 1, suppress context ID in log messages */
|
|
int show_application_id; /**< If 1, show application ID in log messages */
|
|
unsigned level; /**< Minimum level to log (suppress messages below this) */
|
|
int suppress_time; /**< If 1, suppress time in log messages */
|
|
int hide_counter; /**< If 1, hide message counter in log messages */
|
|
};
|
|
|
|
/**
|
|
* @brief Label properties for a log level
|
|
*
|
|
* @see @ref LOGMOD_LABEL_COLOR
|
|
*/
|
|
struct logmod_label {
|
|
const char *const name; /**< Display name of the log level */
|
|
const char *const style; /**< ANSI style code for this label */
|
|
const char *const visibility; /**< ANSI visibility code for this label */
|
|
const char *const color; /**< ANSI color code for this label */
|
|
const int output; /**< Output stream: 0 = stdout, 1 = stderr */
|
|
};
|
|
|
|
/**
|
|
* @brief Helper macro to define label color, style, and visibility at once
|
|
*
|
|
* @param _style Style name (e.g., BOLD, REGULAR)
|
|
* @param _visibility Visibility name (e.g., FOREGROUND, BACKGROUND)
|
|
* @param _color Color name (e.g., RED, GREEN)
|
|
*/
|
|
#define LOGMOD_LABEL_COLOR(_style, _visibility, _color) \
|
|
LOGMOD_STYLE_##_style, LOGMOD_VISIBILITY_##_visibility, \
|
|
LOGMOD_COLOR_##_color
|
|
|
|
/**
|
|
* @brief Information about a log entry
|
|
*/
|
|
struct logmod_info {
|
|
const unsigned line; /**< Source line number */
|
|
const char *const filename; /**< Source filename */
|
|
const unsigned level; /**< Log level */
|
|
const struct logmod_label *const label; /**< Label for this log level */
|
|
const struct tm time; /**< Time for when entry has been triggered */
|
|
};
|
|
|
|
/* forward declaration */
|
|
struct logmod_logger;
|
|
struct tm;
|
|
/**/
|
|
|
|
/**
|
|
* @brief Lock function type for thread safety
|
|
*
|
|
* @param logger The logger instance
|
|
* @param should_lock 1 to acquire lock, 0 to release
|
|
*/
|
|
typedef void (*logmod_lock)(const struct logmod_logger *logger,
|
|
int should_lock);
|
|
|
|
/**
|
|
* @brief Callback function type for custom log handling
|
|
*
|
|
* @param logger The logger instance
|
|
* @param info Information about the log entry
|
|
* @param fmt Format string
|
|
* @param args Variable arguments list
|
|
* @return LOGMOD_OK to skip default handling, LOGMOD_OK_CONTINUE to also
|
|
* perform default handling
|
|
*/
|
|
typedef logmod_err (*logmod_callback)(const struct logmod_logger *logger,
|
|
const struct logmod_info *info,
|
|
const char *fmt,
|
|
va_list args);
|
|
|
|
/**
|
|
* @brief ANSI text style values
|
|
*/
|
|
#define LOGMOD_STYLE_REGULAR "0" /**< Regular text style */
|
|
#define LOGMOD_STYLE_BOLD "1" /**< Bold text style */
|
|
#define LOGMOD_STYLE_UNDERLINE "4" /**< Underlined text style */
|
|
#define LOGMOD_STYLE_STRIKETHROUGH "9" /**< Strikethrough text style */
|
|
|
|
/**
|
|
* @brief ANSI text visibility mode values
|
|
*/
|
|
#define LOGMOD_VISIBILITY_FOREGROUND "3" /**< Foreground color */
|
|
#define LOGMOD_VISIBILITY_BACKGROUND "4" /**< Background color */
|
|
#define LOGMOD_VISIBILITY_INTENSITY "9" /**< Intensity (bright) foreground */
|
|
#define LOGMOD_VISIBILITY_BACKGROUND_INTENSITY \
|
|
"10" /**< Intensity (bright) background */
|
|
|
|
/**
|
|
* @brief ANSI color values
|
|
*/
|
|
#define LOGMOD_COLOR_BLACK "0" /**< Black color */
|
|
#define LOGMOD_COLOR_RED "1" /**< Red color */
|
|
#define LOGMOD_COLOR_GREEN "2" /**< Green color */
|
|
#define LOGMOD_COLOR_YELLOW "3" /**< Yellow color */
|
|
#define LOGMOD_COLOR_BLUE "4" /**< Blue color */
|
|
#define LOGMOD_COLOR_MAGENTA "5" /**< Magenta color */
|
|
#define LOGMOD_COLOR_CYAN "6" /**< Cyan color */
|
|
#define LOGMOD_COLOR_WHITE "7" /**< White color */
|
|
|
|
/**
|
|
* @brief Internal macro for defining logger attributes
|
|
*
|
|
* Used to define both const and non-const versions of the logger structure
|
|
* with the same fields.
|
|
*
|
|
* @param _qualifier Qualifier to apply to mutable fields (const or empty)
|
|
*/
|
|
#define __LOGMOD_LOGGER_ATTRS(_qualifier) \
|
|
const char *context_id; \
|
|
_qualifier struct logmod_options options; \
|
|
const long *counter; \
|
|
_qualifier logmod_callback callback; \
|
|
void *user_data; \
|
|
const struct logmod_label *_qualifier custom_labels; \
|
|
_qualifier size_t num_custom_labels; \
|
|
_qualifier int disabled
|
|
|
|
#define __BLANK
|
|
/**
|
|
* @brief Mutable version of the logger structure
|
|
*
|
|
* This version allows modification of the logger properties
|
|
*/
|
|
struct logmod_mut_logger {
|
|
__LOGMOD_LOGGER_ATTRS(__BLANK);
|
|
};
|
|
#undef __BLANK
|
|
|
|
/**
|
|
* @brief Immutable logger structure
|
|
*
|
|
* This is the public-facing version of the logger with const-qualified fields
|
|
*/
|
|
struct logmod_logger {
|
|
__LOGMOD_LOGGER_ATTRS(const);
|
|
};
|
|
|
|
#undef __LOGMOD_LOGGER_ATTRS
|
|
|
|
/**
|
|
* @brief Main logging context structure
|
|
*
|
|
* Contains the global state for a logging context
|
|
*/
|
|
struct logmod {
|
|
const char *application_id; /**< Application identifier */
|
|
const struct logmod_logger *loggers; /**< Array of loggers */
|
|
const size_t length; /**< Current number of loggers */
|
|
const size_t real_length; /**< Maximum capacity of loggers array */
|
|
long counter; /**< Global log message counter */
|
|
const struct logmod_options
|
|
default_options; /**< Default options for new loggers */
|
|
logmod_lock lock; /**< Lock function for thread safety */
|
|
};
|
|
|
|
/**
|
|
* @brief Initialize the logging context
|
|
*
|
|
* @param logmod Pointer to the logging context structure
|
|
* @param application_id Application identifier string
|
|
* @param table Array to store loggers (must be pre-allocated)
|
|
* @param length Capacity of the table array
|
|
* @return LOGMOD_OK on success, error code on failure
|
|
*/
|
|
LOGMOD_API logmod_err logmod_init(struct logmod *logmod,
|
|
const char *const application_id,
|
|
struct logmod_logger table[],
|
|
unsigned length);
|
|
|
|
/**
|
|
* @brief Clean up the logging context
|
|
*
|
|
* @param logmod Pointer to the logging context structure
|
|
* @return LOGMOD_OK on success
|
|
*/
|
|
LOGMOD_API logmod_err logmod_cleanup(struct logmod *logmod);
|
|
|
|
/**
|
|
* @brief Set the lock function for thread safety
|
|
*
|
|
* @param logmod Pointer to the logging context structure
|
|
* @param lock Lock function to use
|
|
* @return LOGMOD_OK on success, error code on failure
|
|
*/
|
|
LOGMOD_API logmod_err logmod_set_lock(struct logmod *logmod, logmod_lock lock);
|
|
|
|
/**
|
|
* @brief Set default options for all new loggers
|
|
*
|
|
* @param logmod Pointer to the logging context structure
|
|
* @param options Default options to use for new loggers
|
|
* @return LOGMOD_OK on success, error code on failure
|
|
*/
|
|
LOGMOD_API logmod_err logmod_set_options(struct logmod *logmod,
|
|
struct logmod_options options);
|
|
|
|
/**
|
|
* @brief Toggle a specific logger from logging (default is true)
|
|
*
|
|
* @param logmod Pointer to the logging context structure
|
|
* @param context_id The context id of the logger to be enabled or disabled
|
|
* @return LOGMOD_OK on success, error code on failure
|
|
*/
|
|
LOGMOD_API logmod_err logmod_toggle_logger(struct logmod *logmod,
|
|
const char *const context_id);
|
|
|
|
/**
|
|
* @brief Set user data for a logger
|
|
*
|
|
* @param logger Pointer to the logger
|
|
* @param user_data Pointer to user-defined data
|
|
* @return LOGMOD_OK on success, error code on failure
|
|
*/
|
|
LOGMOD_API logmod_err logmod_logger_set_data(struct logmod_logger *logger,
|
|
void *user_data);
|
|
|
|
/**
|
|
* @brief Set callback function and custom labels for a logger
|
|
*
|
|
* @param logger Pointer to the logger
|
|
* @param custom_labels Array of custom log level labels or NULL
|
|
* @param num_custom_labels Number of custom labels in the array
|
|
* @param callback Callback function for log processing
|
|
* @return LOGMOD_OK on success, error code on failure
|
|
*/
|
|
LOGMOD_API logmod_err
|
|
logmod_logger_set_callback(struct logmod_logger *logger,
|
|
const struct logmod_label *const custom_labels,
|
|
const size_t num_custom_labels,
|
|
logmod_callback callback);
|
|
|
|
/**
|
|
* @brief Set all options for a logger at once
|
|
*
|
|
* @param logger Pointer to the logger
|
|
* @param options Options structure
|
|
* @return LOGMOD_OK on success, error code on failure
|
|
*/
|
|
LOGMOD_API logmod_err logmod_logger_set_options(struct logmod_logger *logger,
|
|
struct logmod_options options);
|
|
|
|
/**
|
|
* @brief Set visibility of application ID and context ID in log messages
|
|
*
|
|
* @param logger Pointer to the logger
|
|
* @param show_app_id 1 to show application ID, 0 to hide
|
|
* @param show_context_id 1 to show context ID, 0 to hide
|
|
* @return LOGMOD_OK on success, error code on failure
|
|
*/
|
|
LOGMOD_API logmod_err logmod_logger_set_id_visibility(
|
|
struct logmod_logger *logger, int show_app_id, int show_context_id);
|
|
|
|
/**
|
|
* @brief Set quiet mode for a logger
|
|
*
|
|
* @param logger Pointer to the logger
|
|
* @param quiet 1 to enable quiet mode (suppress console output), 0 to disable
|
|
* @return LOGMOD_OK on success, error code on failure
|
|
*/
|
|
LOGMOD_API logmod_err logmod_logger_set_quiet(struct logmod_logger *logger,
|
|
int quiet);
|
|
|
|
/**
|
|
* @brief Set color mode for a logger
|
|
*
|
|
* @param logger Pointer to the logger
|
|
* @param color 1 to enable colored output, 0 to disable
|
|
* @return LOGMOD_OK on success, error code on failure
|
|
*/
|
|
LOGMOD_API logmod_err logmod_logger_set_color(struct logmod_logger *logger,
|
|
int color);
|
|
|
|
/**
|
|
* @brief Set minimum log level for a logger
|
|
*
|
|
* @param logger Pointer to the logger
|
|
* @param level Minimum level to log (messages below this will be suppressed)
|
|
* @return LOGMOD_OK on success, error code on failure
|
|
*/
|
|
LOGMOD_API logmod_err logmod_logger_set_level(struct logmod_logger *logger,
|
|
unsigned level);
|
|
|
|
/**
|
|
* @brief Set logfile for a logger
|
|
*
|
|
* @param logger Pointer to the logger
|
|
* @param logfile File pointer to write logs to, or NULL to disable
|
|
* @return LOGMOD_OK on success, error code on failure
|
|
*/
|
|
LOGMOD_API logmod_err logmod_logger_set_logfile(struct logmod_logger *logger,
|
|
FILE *logfile);
|
|
|
|
/**
|
|
* @brief Set time display for a logger
|
|
*
|
|
* @param logger Pointer to the logger
|
|
* @param show_time 0 to suppress time in log messages, 1 to show it
|
|
* @return LOGMOD_OK on success, error code on failure
|
|
*/
|
|
LOGMOD_API logmod_err logmod_logger_set_time(struct logmod_logger *logger,
|
|
int show_time);
|
|
|
|
/**
|
|
* @brief Set counter display for a logger
|
|
*
|
|
* @param logger Pointer to the logger
|
|
* @param show_counter 0 to hide counter in log messages, 1 to show it
|
|
* @return LOGMOD_OK on success, error code on failure
|
|
*/
|
|
LOGMOD_API logmod_err logmod_logger_set_counter(struct logmod_logger *logger,
|
|
int show_counter);
|
|
|
|
/**
|
|
* @brief Get or create a logger by context ID
|
|
*
|
|
* @param logmod Pointer to the logging context
|
|
* @param context_id Context identifier string
|
|
* @return Pointer to the logger, or NULL if the table is full
|
|
*/
|
|
LOGMOD_API struct logmod_logger *logmod_get_logger(
|
|
struct logmod *logmod, const char *const context_id);
|
|
|
|
/**
|
|
* @brief Get the label for a specific log level
|
|
*
|
|
* @param logger Pointer to the logger
|
|
* @param level Log level to get the label for
|
|
* @return Pointer to the label structure, or NULL if invalid
|
|
*/
|
|
LOGMOD_API const struct logmod_label *logmod_logger_get_label(
|
|
const struct logmod_logger *logger, const unsigned level);
|
|
|
|
/**
|
|
* @brief Get the level value for a label name
|
|
*
|
|
* @param logger Pointer to the logger
|
|
* @param label Label name to look up
|
|
* @return Level value, or LOGMOD_BAD_PARAMETER if invalid
|
|
*/
|
|
LOGMOD_API long logmod_logger_get_level(const struct logmod_logger *logger,
|
|
const char *const label);
|
|
|
|
/**
|
|
* @brief Get the global message counter for a logger
|
|
*
|
|
* @param logger Pointer to the logger
|
|
* @return Current counter value, or -1 if logger is NULL
|
|
*/
|
|
LOGMOD_API long logmod_logger_get_counter(const struct logmod_logger *logger);
|
|
|
|
/**
|
|
* @brief Log a message (C89 compatible version)
|
|
*
|
|
* @param _level Log level (without LOGMOD_LEVEL_ prefix)
|
|
* @param _logger Logger to use, or NULL for default
|
|
* @param _parenthesized_params Format and arguments in parentheses
|
|
* @param num_params Number of arguments in the format string
|
|
*/
|
|
#define logmod_nlog(_level, _logger, _parenthesized_params, num_params) \
|
|
_logmod_log(_logger, __LINE__, __FILE__, LOGMOD_LEVEL_##_level, \
|
|
LOGMOD_SPREAD_TUPLE_##num_params _parenthesized_params)
|
|
|
|
#if __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
|
|
/**
|
|
* @brief Internal helper macro for C99 variable arguments processing
|
|
*
|
|
* @param _level The log level
|
|
* @param _logger The logger instance
|
|
* @param _line Source line number
|
|
* @param _file Source file path
|
|
* @param _fmt Format string
|
|
* @param ... Additional format arguments
|
|
*/
|
|
#define _logmod_log_permissive(_level, _logger, _line, _file, _fmt, ...) \
|
|
_logmod_log(_logger, _line, _file, _level, _fmt "%s", __VA_ARGS__)
|
|
|
|
/**
|
|
* @brief Log a message with specified level (C99 version with variadic macro
|
|
* support)
|
|
*
|
|
* @param _level Log level (e.g., INFO, DEBUG, ERROR)
|
|
* @param _logger The logger instance or NULL for default logger
|
|
* @param ... Format string followed by format arguments
|
|
*/
|
|
#define logmod_log(_level, _logger, ...) \
|
|
_logmod_log_permissive(LOGMOD_LEVEL_##_level, _logger, __LINE__, \
|
|
__FILE__, __VA_ARGS__, "")
|
|
#else
|
|
/**
|
|
* @brief Alias to logmod_nlog for C89 compatibility
|
|
*/
|
|
#define logmod_log logmod_nlog
|
|
#endif /* __STDC_VERSION__ */
|
|
|
|
/**
|
|
* @brief Internal logging implementation function
|
|
*
|
|
* @param logger The logger instance
|
|
* @param line Source line number
|
|
* @param filename Source file path
|
|
* @param level Log level
|
|
* @param fmt Format string
|
|
* @param ... Format arguments
|
|
* @return logmod_err LOGMOD_OK on success, or error code on failure
|
|
*/
|
|
LOGMOD_API logmod_err _logmod_log(const struct logmod_logger *logger,
|
|
const unsigned line,
|
|
const char *const filename,
|
|
const unsigned level,
|
|
const char *fmt,
|
|
...) LOGMOD_PRINTF_LIKE(5, 6);
|
|
|
|
/**
|
|
* @brief Encodes text with ANSI colors and styles
|
|
*
|
|
* @param _style Style code (LOGMOD_STYLE_* macros)
|
|
* @param _visibility Visibility code (LOGMOD_VISIBILITY_* macros)
|
|
* @param _color Color code (LOGMOD_COLOR_* macros)
|
|
* @param buf Text buffer to encode
|
|
*/
|
|
#define LOGMOD_ENCODE(_style, _visibility, _color, buf) \
|
|
"\x1b[" _style ";" _visibility _color "m" buf "\x1b[0m"
|
|
|
|
/**
|
|
* @brief Static encoding of text with ANSI colors (compile-time)
|
|
*
|
|
* @param _style Style name (e.g., BOLD, REGULAR)
|
|
* @param _visibility Visibility name (e.g., FOREGROUND, BACKGROUND)
|
|
* @param _color Color name (e.g., RED, GREEN)
|
|
* @param buf The text to encode
|
|
*/
|
|
#define LOGMOD_ENCODE_STATIC(_style, _visibility, _color, buf) \
|
|
LOGMOD_ENCODE(LOGMOD_STYLE_##_style, LOGMOD_VISIBILITY_##_visibility, \
|
|
LOGMOD_COLOR_##_color, buf)
|
|
|
|
/**
|
|
* @brief Dynamic encoding of text with ANSI colors (respects toggle)
|
|
*
|
|
* @param _toggle Toggle to enable or disable color encoding
|
|
* @param _style Style name (e.g., BOLD, REGULAR)
|
|
* @param _visibility Visibility name (e.g., FOREGROUND, BACKGROUND)
|
|
* @param _color Color name (e.g., RED, GREEN)
|
|
* @param buf The text to encode
|
|
* @return Colored text if toggle is enabled, or original text otherwise
|
|
*/
|
|
#define LOGMOD_ENCODE_TOGGLE(_toggle, _style, _visibility, _color, buf) \
|
|
((_toggle) ? LOGMOD_ENCODE_STATIC(_style, _visibility, _color, buf) : buf)
|
|
|
|
/**
|
|
* @brief Dynamic encoding of text with ANSI colors (respects logger color
|
|
* setting)
|
|
*
|
|
* @param _logger The logger instance to check for color enabled setting
|
|
* @param _style Style name (e.g., BOLD, REGULAR)
|
|
* @param _visibility Visibility name (e.g., FOREGROUND, BACKGROUND)
|
|
* @param _color Color name (e.g., RED, GREEN)
|
|
* @param buf The text to encode
|
|
* @return Colored text if colors enabled, or original text otherwise
|
|
*/
|
|
#define LOGMOD_ENCODE_LOGGER(_logger, _style, _visibility, _color, buf) \
|
|
LOGMOD_ENCODE_TOGGLE((_logger)->options.color, _style, _visibility, \
|
|
_color, buf)
|
|
|
|
/** @brief Shorthand for LOGMOD_ENCODE_STATIC */
|
|
#define LMS LOGMOD_ENCODE_STATIC
|
|
/** @brief Shorthand for LOGMOD_ENCODE_TOGGLE */
|
|
#define LMT LOGMOD_ENCODE_TOGGLE
|
|
/** @brief Shorthand for LOGMOD_ENCODE_LOGGER */
|
|
#define LML LOGMOD_ENCODE_LOGGER
|
|
/** @brief Shorthand for LOGMOD_ENCODE */
|
|
#define LME LOGMOD_ENCODE
|
|
|
|
#define LOGMOD_SPREAD_TUPLE_0(_fmt) _fmt
|
|
#define LOGMOD_SPREAD_TUPLE_1(_fmt, _1) _fmt, _1
|
|
#define LOGMOD_SPREAD_TUPLE_2(_fmt, _1, _2) _fmt, _1, _2
|
|
#define LOGMOD_SPREAD_TUPLE_3(_fmt, _1, _2, _3) _fmt, _1, _2, _3
|
|
#define LOGMOD_SPREAD_TUPLE_4(_fmt, _1, _2, _3, _4) _fmt, _2, _3, _4
|
|
#define LOGMOD_SPREAD_TUPLE_5(_fmt, _1, _2, _3, _4, _5) \
|
|
_fmt, _1, _2, _3, _4, _5
|
|
#define LOGMOD_SPREAD_TUPLE_6(_fmt, _1, _2, _3, _4, _5, _6) \
|
|
_fmt, _1, _2, _3, _4, _6
|
|
#define LOGMOD_SPREAD_TUPLE_7(_fmt, _1, _2, _3, _4, _5, _6, _7) \
|
|
_fmt, _1, _2, _3, _4, _5, _6, _7
|
|
#define LOGMOD_SPREAD_TUPLE_8(_fmt, _1, _2, _3, _4, _5, _6, _7, _8) \
|
|
_fmt, _1, _2, _3, _4, _5, _6, _7, _8
|
|
#define LOGMOD_SPREAD_TUPLE_9(_fmt, _1, _2, _3, _4, _5, _6, _7, _8, _9) \
|
|
_fmt, _1, _2, _3, _4, _5, _6, _7, _8, _9
|
|
#define LOGMOD_SPREAD_TUPLE_10(_fmt, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \
|
|
_fmt, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10
|
|
#define LOGMOD_SPREAD_TUPLE_11(_fmt, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \
|
|
_11) \
|
|
_fmt, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11
|
|
#define LOGMOD_SPREAD_TUPLE_12(_fmt, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \
|
|
_11, _12) \
|
|
_fmt, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12
|
|
#define LOGMOD_SPREAD_TUPLE_13(_fmt, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \
|
|
_11, _12, _13) \
|
|
_fmt, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13
|
|
#define LOGMOD_SPREAD_TUPLE_14(_fmt, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \
|
|
_11, _12, _13, _14) \
|
|
_fmt, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14
|
|
#define LOGMOD_SPREAD_TUPLE_15(_fmt, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \
|
|
_11, _12, _13, _14, _15) \
|
|
_fmt, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15
|
|
#define LOGMOD_SPREAD_TUPLE_16(_fmt, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \
|
|
_11, _12, _13, _14, _15, _16) \
|
|
_fmt, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16
|
|
|
|
#ifndef LOGMOD_HEADER
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
|
|
#include "logmod.h"
|
|
|
|
static const struct logmod_label default_labels[__LOGMOD_LEVEL_MAX] = {
|
|
/*[LOGMOD_LEVEL_TRACE]:*/
|
|
{ "TRACE", LOGMOD_LABEL_COLOR(REGULAR, BACKGROUND_INTENSITY, BLUE), 0 },
|
|
/*[LOGMOD_LEVEL_DEBUG]:*/
|
|
{ "DEBUG", LOGMOD_LABEL_COLOR(REGULAR, BACKGROUND, CYAN), 0 },
|
|
/*[LOGMOD_LEVEL_INFO]: */
|
|
{ "INFO", LOGMOD_LABEL_COLOR(REGULAR, BACKGROUND, GREEN), 0 },
|
|
/*[LOGMOD_LEVEL_WARN]: */
|
|
{ "WARN", LOGMOD_LABEL_COLOR(REGULAR, BACKGROUND, YELLOW), 1 },
|
|
/*[LOGMOD_LEVEL_ERROR]:*/
|
|
{ "ERROR", LOGMOD_LABEL_COLOR(REGULAR, BACKGROUND, RED), 1 },
|
|
/*[LOGMOD_LEVEL_FATAL]:*/
|
|
{ "FATAL", LOGMOD_LABEL_COLOR(REGULAR, BACKGROUND, MAGENTA), 1 },
|
|
};
|
|
|
|
/** @brief Get @ref logmod from any @ref logmod_logger */
|
|
#define LOGMOD_FROM_LOGGER(_ctx) \
|
|
((struct logmod *)((char *)(_ctx)->counter \
|
|
- offsetof(struct logmod, counter)))
|
|
|
|
#define _LOGMOD_EXPECT(_cond, _error, _return) \
|
|
do { \
|
|
if (!(_cond)) { \
|
|
switch ((_error)) { \
|
|
case LOGMOD_BAD_PARAMETER: \
|
|
logmod_nlog(ERROR, NULL, ("Bad parameter: %s", #_cond), 1); \
|
|
break; \
|
|
case LOGMOD_ERRNO: \
|
|
logmod_nlog(ERROR, NULL, \
|
|
("System error (check errno): %s", #_cond), 1); \
|
|
break; \
|
|
default: \
|
|
logmod_nlog(ERROR, NULL, ("Unknown error: %s", #_cond), 1); \
|
|
break; \
|
|
} \
|
|
return (_return); \
|
|
} \
|
|
} while (0)
|
|
|
|
/**
|
|
* @brief Check if a condition is met and log an error message if not
|
|
*
|
|
* @param _cond Condition to check
|
|
* @param _error Error code to return if the condition is false
|
|
*/
|
|
#define LOGMOD_EXPECT(_cond, _error) _LOGMOD_EXPECT(_cond, _error, _error)
|
|
|
|
static void
|
|
_logmod_lock_noop(const struct logmod_logger *_, int __)
|
|
{
|
|
(void)_;
|
|
(void)__;
|
|
}
|
|
|
|
LOGMOD_API logmod_err
|
|
logmod_init(struct logmod *logmod,
|
|
const char *const application_id,
|
|
struct logmod_logger table[],
|
|
unsigned length)
|
|
{
|
|
size_t *mut_real_length = (size_t *)&logmod->real_length;
|
|
LOGMOD_EXPECT(logmod != NULL, LOGMOD_BAD_PARAMETER);
|
|
LOGMOD_EXPECT(application_id && *application_id, LOGMOD_BAD_PARAMETER);
|
|
LOGMOD_EXPECT(table != NULL, LOGMOD_BAD_PARAMETER);
|
|
LOGMOD_EXPECT(length > 0, LOGMOD_BAD_PARAMETER);
|
|
memset(logmod, 0, sizeof *logmod);
|
|
memset(table, 0, length * sizeof *table);
|
|
logmod->application_id = application_id;
|
|
logmod->loggers = table;
|
|
*mut_real_length = length;
|
|
logmod->lock = _logmod_lock_noop;
|
|
return LOGMOD_OK;
|
|
}
|
|
|
|
LOGMOD_API logmod_err
|
|
logmod_cleanup(struct logmod *logmod)
|
|
{
|
|
memset((void *)logmod->loggers, 0,
|
|
logmod->real_length * sizeof *logmod->loggers);
|
|
memset(logmod, 0, sizeof *logmod);
|
|
return LOGMOD_OK;
|
|
}
|
|
|
|
LOGMOD_API logmod_err
|
|
logmod_set_lock(struct logmod *logmod, logmod_lock lock)
|
|
{
|
|
LOGMOD_EXPECT(logmod != NULL, LOGMOD_BAD_PARAMETER);
|
|
logmod->lock = lock;
|
|
return LOGMOD_OK;
|
|
}
|
|
|
|
LOGMOD_API logmod_err
|
|
logmod_set_options(struct logmod *logmod, struct logmod_options options)
|
|
{
|
|
struct logmod_options *mut_default_options =
|
|
(struct logmod_options *)&logmod->default_options;
|
|
LOGMOD_EXPECT(logmod != NULL, LOGMOD_BAD_PARAMETER);
|
|
*mut_default_options = options;
|
|
return LOGMOD_OK;
|
|
}
|
|
|
|
LOGMOD_API logmod_err
|
|
logmod_toggle_logger(struct logmod *logmod, const char *const context_id)
|
|
{
|
|
struct logmod_mut_logger *mut_logger =
|
|
(struct logmod_mut_logger *)logmod_get_logger(logmod, context_id);
|
|
LOGMOD_EXPECT(mut_logger != NULL, LOGMOD_BAD_PARAMETER);
|
|
mut_logger->disabled = !mut_logger->disabled;
|
|
return LOGMOD_OK;
|
|
}
|
|
|
|
LOGMOD_API logmod_err
|
|
logmod_logger_set_id_visibility(struct logmod_logger *logger,
|
|
int show_app_id,
|
|
int show_context_id)
|
|
{
|
|
struct logmod_mut_logger *mut_logger = (struct logmod_mut_logger *)logger;
|
|
LOGMOD_EXPECT(logger != NULL, LOGMOD_BAD_PARAMETER);
|
|
mut_logger->options.show_application_id = show_app_id;
|
|
mut_logger->options.hide_context_id = !show_context_id;
|
|
return LOGMOD_OK;
|
|
}
|
|
|
|
LOGMOD_API logmod_err
|
|
logmod_logger_set_data(struct logmod_logger *logger, void *user_data)
|
|
{
|
|
struct logmod_mut_logger *mut_logger = (struct logmod_mut_logger *)logger;
|
|
LOGMOD_EXPECT(logger != NULL, LOGMOD_BAD_PARAMETER);
|
|
mut_logger->user_data = user_data;
|
|
return LOGMOD_OK;
|
|
}
|
|
|
|
LOGMOD_API logmod_err
|
|
logmod_logger_set_callback(struct logmod_logger *logger,
|
|
const struct logmod_label *const custom_labels,
|
|
const size_t num_custom_labels,
|
|
logmod_callback callback)
|
|
{
|
|
struct logmod_mut_logger *mut_logger = (struct logmod_mut_logger *)logger;
|
|
LOGMOD_EXPECT(logger != NULL, LOGMOD_BAD_PARAMETER);
|
|
mut_logger->callback = callback;
|
|
if (custom_labels != NULL) {
|
|
LOGMOD_EXPECT(num_custom_labels > 0, LOGMOD_BAD_PARAMETER);
|
|
mut_logger->custom_labels = custom_labels;
|
|
mut_logger->num_custom_labels = num_custom_labels;
|
|
}
|
|
return LOGMOD_OK;
|
|
}
|
|
|
|
LOGMOD_API logmod_err
|
|
logmod_logger_set_options(struct logmod_logger *logger,
|
|
struct logmod_options options)
|
|
{
|
|
struct logmod_mut_logger *mut_logger = (struct logmod_mut_logger *)logger;
|
|
LOGMOD_EXPECT(logger != NULL, LOGMOD_BAD_PARAMETER);
|
|
mut_logger->options = options;
|
|
return LOGMOD_OK;
|
|
}
|
|
|
|
LOGMOD_API logmod_err
|
|
logmod_logger_set_quiet(struct logmod_logger *logger, int quiet)
|
|
{
|
|
struct logmod_mut_logger *mut_logger = (struct logmod_mut_logger *)logger;
|
|
LOGMOD_EXPECT(logger != NULL, LOGMOD_BAD_PARAMETER);
|
|
mut_logger->options.quiet = quiet;
|
|
return LOGMOD_OK;
|
|
}
|
|
|
|
LOGMOD_API logmod_err
|
|
logmod_logger_set_color(struct logmod_logger *logger, int color)
|
|
{
|
|
struct logmod_mut_logger *mut_logger = (struct logmod_mut_logger *)logger;
|
|
LOGMOD_EXPECT(logger != NULL, LOGMOD_BAD_PARAMETER);
|
|
mut_logger->options.color = color;
|
|
return LOGMOD_OK;
|
|
}
|
|
|
|
LOGMOD_API logmod_err
|
|
logmod_logger_set_level(struct logmod_logger *logger, unsigned level)
|
|
{
|
|
struct logmod_mut_logger *mut_logger = (struct logmod_mut_logger *)logger;
|
|
LOGMOD_EXPECT(logger != NULL, LOGMOD_BAD_PARAMETER);
|
|
mut_logger->options.level = level;
|
|
return LOGMOD_OK;
|
|
}
|
|
|
|
LOGMOD_API logmod_err
|
|
logmod_logger_set_logfile(struct logmod_logger *logger, FILE *logfile)
|
|
{
|
|
struct logmod_mut_logger *mut_logger = (struct logmod_mut_logger *)logger;
|
|
LOGMOD_EXPECT(logger != NULL, LOGMOD_BAD_PARAMETER);
|
|
mut_logger->options.logfile = logfile;
|
|
return LOGMOD_OK;
|
|
}
|
|
|
|
LOGMOD_API logmod_err
|
|
logmod_logger_set_time(struct logmod_logger *logger, int show_time)
|
|
{
|
|
struct logmod_mut_logger *mut_logger = (struct logmod_mut_logger *)logger;
|
|
LOGMOD_EXPECT(logger != NULL, LOGMOD_BAD_PARAMETER);
|
|
mut_logger->options.suppress_time = !show_time;
|
|
return LOGMOD_OK;
|
|
}
|
|
|
|
LOGMOD_API logmod_err
|
|
logmod_logger_set_counter(struct logmod_logger *logger, int show_counter)
|
|
{
|
|
struct logmod_mut_logger *mut_logger = (struct logmod_mut_logger *)logger;
|
|
LOGMOD_EXPECT(logger != NULL, LOGMOD_BAD_PARAMETER);
|
|
mut_logger->options.hide_counter = !show_counter;
|
|
return LOGMOD_OK;
|
|
}
|
|
|
|
LOGMOD_API const struct logmod_label *
|
|
logmod_logger_get_label(const struct logmod_logger *logger,
|
|
const unsigned level)
|
|
{
|
|
static const struct logmod_label unknown_label = {
|
|
"#UNKNOWN LABEL!!",
|
|
LOGMOD_LABEL_COLOR(STRIKETHROUGH, BACKGROUND_INTENSITY, YELLOW), 1
|
|
};
|
|
if (level < LOGMOD_LEVEL_CUSTOM) {
|
|
return &default_labels[level];
|
|
}
|
|
if (logger && level >= LOGMOD_LEVEL_CUSTOM
|
|
&& level < (LOGMOD_LEVEL_CUSTOM + logger->num_custom_labels))
|
|
{
|
|
return &logger->custom_labels[level - LOGMOD_LEVEL_CUSTOM];
|
|
}
|
|
logmod_nlog(ERROR, NULL,
|
|
("Invalid log level %u for logger %s", level,
|
|
logger ? logger->context_id : "NULL"),
|
|
2);
|
|
return &unknown_label;
|
|
}
|
|
|
|
LOGMOD_API long
|
|
logmod_logger_get_level(const struct logmod_logger *logger,
|
|
const char *const label)
|
|
{
|
|
size_t i;
|
|
LOGMOD_EXPECT(logger != NULL, LOGMOD_BAD_PARAMETER);
|
|
LOGMOD_EXPECT(label != NULL, LOGMOD_BAD_PARAMETER);
|
|
for (i = 0; i < __LOGMOD_LEVEL_MAX; ++i) {
|
|
if (strcmp(label, default_labels[i].name) == 0) {
|
|
return (long)i;
|
|
}
|
|
}
|
|
for (i = 0; i < logger->num_custom_labels; ++i) {
|
|
if (strcmp(label, logger->custom_labels[i].name) == 0) {
|
|
return (long)(i + LOGMOD_LEVEL_CUSTOM);
|
|
}
|
|
}
|
|
return LOGMOD_BAD_PARAMETER;
|
|
}
|
|
|
|
LOGMOD_API long
|
|
logmod_logger_get_counter(const struct logmod_logger *logger)
|
|
{
|
|
struct logmod *logmod = LOGMOD_FROM_LOGGER(logger);
|
|
long counter;
|
|
LOGMOD_EXPECT(logmod != NULL, LOGMOD_BAD_PARAMETER);
|
|
logmod->lock(logger, 1);
|
|
counter = logmod->counter;
|
|
logmod->lock(logger, 0);
|
|
return counter;
|
|
}
|
|
|
|
LOGMOD_API struct logmod_logger *
|
|
logmod_get_logger(struct logmod *logmod, const char *const context_id)
|
|
{
|
|
size_t i;
|
|
_LOGMOD_EXPECT(logmod != NULL, LOGMOD_BAD_PARAMETER, NULL);
|
|
_LOGMOD_EXPECT(logmod->loggers != NULL, LOGMOD_BAD_PARAMETER, NULL);
|
|
_LOGMOD_EXPECT(context_id != NULL, LOGMOD_BAD_PARAMETER, NULL);
|
|
logmod->lock(NULL, 1);
|
|
for (i = 0; i < logmod->length; ++i) {
|
|
if (0 == strcmp(logmod->loggers[i].context_id, context_id)) {
|
|
struct logmod_logger *logger =
|
|
(struct logmod_logger *)&logmod->loggers[i];
|
|
logmod->lock(logger, 0);
|
|
return logger;
|
|
}
|
|
}
|
|
if (logmod->length < logmod->real_length) {
|
|
size_t *mut_length = (size_t *)&logmod->length;
|
|
struct logmod_mut_logger *mut_logger =
|
|
(struct logmod_mut_logger *)&logmod->loggers[logmod->length];
|
|
memset(mut_logger, 0, sizeof *mut_logger);
|
|
mut_logger->context_id = context_id;
|
|
mut_logger->counter = &logmod->counter;
|
|
mut_logger->options = logmod->default_options;
|
|
++*mut_length;
|
|
logmod->lock((struct logmod_logger *)mut_logger, 0);
|
|
return (struct logmod_logger *)mut_logger;
|
|
}
|
|
logmod->lock(NULL, 0);
|
|
return NULL;
|
|
}
|
|
|
|
static logmod_err
|
|
_logmod_print(const struct logmod_logger *logger,
|
|
const struct logmod_info *info,
|
|
const char *fmt,
|
|
va_list args,
|
|
const int color,
|
|
FILE *output)
|
|
{
|
|
if (!logger->options.hide_counter) {
|
|
LOGMOD_EXPECT(fprintf(output,
|
|
LMT(color, BOLD, FOREGROUND, WHITE, "%-3ld "),
|
|
logmod_logger_get_counter(logger))
|
|
>= 0,
|
|
LOGMOD_ERRNO);
|
|
}
|
|
if (!logger->options.suppress_time) {
|
|
LOGMOD_EXPECT(
|
|
fprintf(output,
|
|
LMT(color, UNDERLINE, FOREGROUND, WHITE, "%02d:%02d:%02d"),
|
|
info->time.tm_hour, info->time.tm_min, info->time.tm_sec)
|
|
>= 0,
|
|
LOGMOD_ERRNO);
|
|
LOGMOD_EXPECT(putc(' ', output) != EOF, LOGMOD_ERRNO);
|
|
}
|
|
if (logger->options.show_application_id) {
|
|
const struct logmod *logmod = LOGMOD_FROM_LOGGER(logger);
|
|
LOGMOD_EXPECT(fprintf(output,
|
|
LMT(color, BOLD, FOREGROUND, BLACK, "%s"),
|
|
logmod->application_id)
|
|
>= 0,
|
|
LOGMOD_ERRNO);
|
|
LOGMOD_EXPECT(fputs(LMT(color, BOLD, FOREGROUND, BLACK, " » "), output)
|
|
!= EOF,
|
|
LOGMOD_ERRNO);
|
|
}
|
|
if (!logger->options.hide_context_id) {
|
|
LOGMOD_EXPECT(fprintf(output,
|
|
LMT(color, BOLD, FOREGROUND, WHITE, "%s"),
|
|
logger->context_id)
|
|
>= 0,
|
|
LOGMOD_ERRNO);
|
|
LOGMOD_EXPECT(fputs(LMT(color, BOLD, FOREGROUND, WHITE, " » "), output)
|
|
!= EOF,
|
|
LOGMOD_ERRNO);
|
|
}
|
|
if (color) {
|
|
LOGMOD_EXPECT(fprintf(output,
|
|
LME("%s", "%s", "%s", "%s") " " LMS(
|
|
REGULAR, FOREGROUND, YELLOW,
|
|
"%s") LMS(BOLD, FOREGROUND, WHITE, ":")
|
|
LMS(REGULAR, FOREGROUND, WHITE, "%d") ": ",
|
|
info->label->style, info->label->visibility,
|
|
info->label->color, info->label->name,
|
|
info->filename, info->line)
|
|
>= 0,
|
|
LOGMOD_ERRNO);
|
|
}
|
|
else {
|
|
LOGMOD_EXPECT(fprintf(output, "%s %s:%d: ", info->label->name,
|
|
info->filename, info->line)
|
|
>= 0,
|
|
LOGMOD_ERRNO);
|
|
}
|
|
LOGMOD_EXPECT(vfprintf(output, fmt, args) >= 0, LOGMOD_ERRNO);
|
|
LOGMOD_EXPECT(putc('\n', output) != EOF, LOGMOD_ERRNO);
|
|
LOGMOD_EXPECT(fflush(output) != EOF, LOGMOD_ERRNO);
|
|
return LOGMOD_OK;
|
|
}
|
|
|
|
static struct logmod g_logmod;
|
|
|
|
/** global logger used as a fallback */
|
|
static struct logmod_logger g_loggers[] = {
|
|
{
|
|
LOGMOD_FALLBACK_CONTEXT_ID,
|
|
{ NULL, 0, 1 },
|
|
&g_logmod.counter,
|
|
NULL,
|
|
NULL,
|
|
default_labels,
|
|
0,
|
|
},
|
|
};
|
|
/** global logmod used as a fallback */
|
|
static struct logmod g_logmod = {
|
|
LOGMOD_FALLBACK_APPLICATION_ID,
|
|
g_loggers,
|
|
sizeof(g_loggers) / sizeof *g_loggers,
|
|
sizeof(g_loggers) / sizeof *g_loggers,
|
|
0,
|
|
{ NULL, 0, 1 },
|
|
_logmod_lock_noop,
|
|
};
|
|
|
|
static struct logmod_info
|
|
_logmod_info_populate(const struct logmod_logger *logger,
|
|
const unsigned line,
|
|
const char *const filename,
|
|
const unsigned level)
|
|
{
|
|
const struct logmod *logmod = LOGMOD_FROM_LOGGER(logger);
|
|
const time_t time_raw = time(NULL);
|
|
struct logmod_info info;
|
|
unsigned *mut_line = (unsigned *)&info.line;
|
|
const char **mut_filename = (const char **)&info.filename;
|
|
unsigned *mut_level = (unsigned *)&info.level;
|
|
const struct logmod_label **mut_label =
|
|
(const struct logmod_label **)&info.label;
|
|
struct tm *mut_time = (struct tm *)&info.time;
|
|
*mut_line = line;
|
|
*mut_filename = filename;
|
|
*mut_level = level;
|
|
*mut_label = logmod_logger_get_label(logger, level);
|
|
logmod->lock(logger, 1);
|
|
*mut_time = *localtime(&time_raw);
|
|
logmod->lock(logger, 0);
|
|
return info;
|
|
}
|
|
|
|
LOGMOD_API logmod_err
|
|
_logmod_log(const struct logmod_logger *logger,
|
|
const unsigned line,
|
|
const char *const filename,
|
|
const unsigned level,
|
|
const char *fmt,
|
|
...)
|
|
{
|
|
struct logmod *logmod =
|
|
LOGMOD_FROM_LOGGER(!logger ? (logger = &g_loggers[0]) : logger);
|
|
logmod_err code = LOGMOD_OK_SKIPPED;
|
|
if (!logger->disabled) {
|
|
const struct logmod_info info =
|
|
_logmod_info_populate(logger, line, filename, level);
|
|
va_list args;
|
|
code = LOGMOD_OK_CONTINUE;
|
|
if (logger->callback) {
|
|
va_start(args, fmt);
|
|
if ((code = logger->callback(logger, &info, fmt, args))
|
|
< LOGMOD_OK)
|
|
{
|
|
goto _end;
|
|
}
|
|
va_end(args);
|
|
}
|
|
if (level >= logger->options.level && code == LOGMOD_OK_CONTINUE) {
|
|
if (!logger->options.quiet || level == LOGMOD_LEVEL_FATAL) {
|
|
va_start(args, fmt);
|
|
if ((code = _logmod_print(
|
|
logger, &info, fmt, args, logger->options.color,
|
|
info.label->output == 0 ? stdout : stderr))
|
|
!= LOGMOD_OK)
|
|
{
|
|
goto _end;
|
|
}
|
|
va_end(args);
|
|
}
|
|
if (logger->options.logfile) {
|
|
va_start(args, fmt);
|
|
code = _logmod_print(logger, &info, fmt, args, 0,
|
|
logger->options.logfile);
|
|
}
|
|
}
|
|
_end:
|
|
logmod->lock(logger, 1);
|
|
++logmod->counter;
|
|
logmod->lock(logger, 0);
|
|
va_end(args);
|
|
}
|
|
return code;
|
|
}
|
|
|
|
#undef LOGMOD_EXPECT
|
|
|
|
#endif /* LOGMOD_HEADER */
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif /* __cplusplus */
|
|
|
|
#endif /* LOGMOD_H */
|