mirror of https://github.com/nirenjan/libx52.git
247 lines
6.2 KiB
C
247 lines
6.2 KiB
C
/*
|
|
* 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>
|
|
#ifndef PINELOG_TEST
|
|
#include <stdlib.h>
|
|
#endif
|
|
|
|
#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 {
|
|
/**
|
|
* 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 */
|
|
PINELOG_LVL_NONE = -1,
|
|
|
|
/** Only fatal messages will be logged */
|
|
PINELOG_LVL_FATAL,
|
|
|
|
/** Error messages. This is the default log level */
|
|
PINELOG_LVL_ERROR,
|
|
|
|
/** Warning messages */
|
|
PINELOG_LVL_WARNING,
|
|
|
|
/** Informational messages */
|
|
PINELOG_LVL_INFO,
|
|
|
|
/** Debug messages */
|
|
PINELOG_LVL_DEBUG,
|
|
|
|
/** Trace messages */
|
|
PINELOG_LVL_TRACE,
|
|
};
|
|
|
|
/**
|
|
* @brief Set the default log level and output stream
|
|
*/
|
|
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
|
|
*/
|
|
void pinelog_close_output_stream(void);
|
|
|
|
#ifdef PINELOG_TEST
|
|
/**
|
|
* @brief Get the pointer to the output stream. Only used in test harness.
|
|
*
|
|
* @returns FILE pointer to output stream
|
|
*/
|
|
FILE * pinelog_get_output_stream(void);
|
|
#endif
|
|
|
|
/**
|
|
* @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 pinelog_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 pinelog_set_output_file(const char *file);
|
|
|
|
/**
|
|
* @brief Set the global logging level
|
|
*
|
|
* @param[in] level Level to filter
|
|
*
|
|
* @returns 0 on success, EINVAL if the level is not valid
|
|
*/
|
|
int pinelog_set_level(int level);
|
|
|
|
/**
|
|
* @brief Get the global logging level
|
|
*
|
|
* @returns the configured global logging level
|
|
*/
|
|
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
|
|
*
|
|
* 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 PINELOG_* macros.
|
|
*
|
|
* @param[in] module Module identifier
|
|
* @param[in] level Level to log the message at
|
|
* @param[in] fmt Format string
|
|
*
|
|
* @returns None
|
|
*/
|
|
#if defined __has_attribute
|
|
# if __has_attribute(format)
|
|
__attribute__((format(printf, 5, 6)))
|
|
# endif
|
|
#endif
|
|
void pinelog_log_message(int module, int level, const char *file, int line, const char *fmt, ...);
|
|
|
|
// Test harness will redefine pinelog_exit
|
|
#ifndef PINELOG_TEST
|
|
#define pinelog_exit exit
|
|
#endif
|
|
|
|
// Base filename
|
|
#if defined __has_builtin
|
|
# if __has_builtin(__builtin_strrchr)
|
|
# define PINELOG_FILE __builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : __FILE__
|
|
# endif
|
|
#endif
|
|
#ifndef PINELOG_FILE
|
|
# define PINELOG_FILE __FILE__
|
|
#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 { \
|
|
if (PINELOG_LVL_FATAL <= pinelog_get_module_level(PINELOG_MODULE)) { \
|
|
pinelog_log_message(PINELOG_MODULE, PINELOG_LVL_FATAL, PINELOG_FILE, __LINE__, fmt, ##__VA_ARGS__); \
|
|
} \
|
|
pinelog_exit(1); \
|
|
} while (0)
|
|
|
|
#define PINELOG_ERROR(fmt, ...) do { \
|
|
if (PINELOG_LVL_ERROR <= pinelog_get_module_level(PINELOG_MODULE)) { \
|
|
pinelog_log_message(PINELOG_MODULE, PINELOG_LVL_ERROR, PINELOG_FILE, __LINE__, fmt, ##__VA_ARGS__); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define PINELOG_WARN(fmt, ...) do { \
|
|
if (PINELOG_LVL_WARNING <= pinelog_get_module_level(PINELOG_MODULE)) { \
|
|
pinelog_log_message(PINELOG_MODULE, PINELOG_LVL_WARNING, PINELOG_FILE, __LINE__, fmt, ##__VA_ARGS__); \
|
|
} \
|
|
} while(0)
|
|
|
|
#define PINELOG_INFO(fmt, ...) do { \
|
|
if (PINELOG_LVL_INFO <= pinelog_get_module_level(PINELOG_MODULE)) { \
|
|
pinelog_log_message(PINELOG_MODULE, PINELOG_LVL_INFO, PINELOG_FILE, __LINE__, fmt, ##__VA_ARGS__); \
|
|
} \
|
|
} while(0)
|
|
|
|
#define PINELOG_DEBUG(fmt, ...) do { \
|
|
if (PINELOG_LVL_DEBUG <= pinelog_get_module_level(PINELOG_MODULE)) { \
|
|
pinelog_log_message(PINELOG_MODULE, PINELOG_LVL_DEBUG, PINELOG_FILE, __LINE__, fmt, ##__VA_ARGS__); \
|
|
} \
|
|
} while(0)
|
|
|
|
/* PINELOG_DISABLE_TRACE allows all traces to be compiled out */
|
|
#ifndef PINELOG_DISABLE_TRACE
|
|
#define PINELOG_TRACE(fmt, ...) do { \
|
|
if (PINELOG_LVL_TRACE <= pinelog_get_module_level(PINELOG_MODULE)) { \
|
|
pinelog_log_message(PINELOG_MODULE, PINELOG_LVL_TRACE, PINELOG_FILE, __LINE__, fmt, ##__VA_ARGS__); \
|
|
} \
|
|
} while(0)
|
|
#else
|
|
#define PINELOG_TRACE(fmt, ...) do { } while(0)
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif // !defined LOGGING_H
|