libx52/subprojects/pinelog/pinelog.h

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