You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
185 lines
6.5 KiB
C
185 lines
6.5 KiB
C
4 years ago
|
/**
|
||
|
* @file logger.h
|
||
|
*
|
||
|
* Functions to do logging.
|
||
|
* The macros check whether the logsev is active before evaluating the
|
||
|
* parameters. Use them instead of the functions.
|
||
|
*
|
||
|
* If a log statement ends in a newline, the current log is ended.
|
||
|
* When the log severity changes, an implicit newline is inserted.
|
||
|
*
|
||
|
* @author Ben Gardner
|
||
|
* @license GPL v2+
|
||
|
*/
|
||
|
|
||
|
#ifndef LOGGER_H_INCLUDED
|
||
|
#define LOGGER_H_INCLUDED
|
||
|
|
||
|
#include "logmask.h"
|
||
4 years ago
|
|
||
4 years ago
|
#include <cstdio> // FILE
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Initializes the log subsystem - call this first.
|
||
|
* This function sets the log stream and enables the top 3 sevs (0-2).
|
||
|
*
|
||
|
* @param log_file nullptr for stderr or the FILE stream for logs.
|
||
|
*/
|
||
|
void log_init(FILE *log_file);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Show or hide the severity prefix "<1>"
|
||
|
*
|
||
|
* @param show true=show, false=hide
|
||
|
*/
|
||
|
void log_show_sev(bool show);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Returns whether a log severity is active.
|
||
|
*
|
||
|
* @param sev severity log level
|
||
|
*
|
||
|
* @return true/false
|
||
|
*/
|
||
|
bool log_sev_on(log_sev_t sev);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Sets a log sev on or off
|
||
|
*
|
||
|
* @param sev severity log level to modify
|
||
|
* @param val new value for severity log level
|
||
|
*
|
||
|
* @return true/false
|
||
|
*/
|
||
|
void log_set_sev(log_sev_t sev, bool value);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Sets the log mask
|
||
|
*
|
||
|
* @param mask The mask to copy
|
||
|
*/
|
||
|
void log_set_mask(const log_mask_t &mask);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Gets the log mask
|
||
|
*
|
||
|
* @param mask Where to copy the mask
|
||
|
*/
|
||
|
void log_get_mask(log_mask_t &mask);
|
||
|
|
||
|
|
||
|
#ifdef __MINGW_PRINTF_FORMAT
|
||
|
// On MinGW, the printf functions can be provided by a number of different
|
||
|
// implementations, with different format string support. Annontate log_fmt
|
||
|
// below with the same format attribute as the currently chosen default printf
|
||
|
// function.
|
||
|
#define PRINTF_FORMAT __MINGW_PRINTF_FORMAT
|
||
|
#else
|
||
|
#define PRINTF_FORMAT printf
|
||
|
#endif
|
||
|
|
||
|
/**
|
||
|
* Logs a formatted string -- similar to printf()
|
||
|
*
|
||
|
* @param sev The severity
|
||
|
* @param fmt The format string
|
||
|
* @param ... Additional arguments
|
||
|
*/
|
||
|
void log_fmt(log_sev_t sev, const char *fmt, ...) __attribute__((format(PRINTF_FORMAT, 2, 3)));
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Flushes the cached log text to the stream
|
||
|
*
|
||
|
* @param force_nl Append NL if not present
|
||
|
*/
|
||
|
void log_flush(bool force_nl);
|
||
|
|
||
|
|
||
|
// it is necessary to make at least one time pro change a check of all the
|
||
|
// uses of the MACRO LOG_FMT under Linux. This to detect all the used pointers,
|
||
|
// which might be nullptr.
|
||
|
// uncomment the define to do that.
|
||
|
// #define NO_MACRO_VARARG
|
||
|
|
||
|
#ifdef NO_MACRO_VARARG
|
||
|
#define LOG_FMT log_fmt
|
||
|
// TODO during debugging add source file and line number
|
||
|
#else
|
||
3 years ago
|
#define LOG_FMT(sev, ...) \
|
||
|
if (log_sev_on(sev)) { log_fmt(sev, __VA_ARGS__); }
|
||
4 years ago
|
#endif
|
||
|
|
||
|
|
||
4 years ago
|
#define __unqualified_func__ get_unqualified_func_name(__func__)
|
||
|
|
||
|
|
||
2 years ago
|
#define LOG_CHUNK(sev, pc_current) \
|
||
|
if (pc_current->Is(CT_NEWLINE)) \
|
||
|
{ \
|
||
|
LOG_FMT(sev, "%s(%d): orig line is %zu, orig col is %zu, <Newline>, PRE is %s\n", \
|
||
|
__func__, __LINE__, pc_current->GetOrigLine(), pc_current->GetOrigCol(), pc_current->IsPreproc() ? "true" : "false"); \
|
||
|
} \
|
||
|
else if (pc_current->Is(CT_NL_CONT)) \
|
||
|
{ \
|
||
|
LOG_FMT(sev, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s', type is %s, PRE is %s\n", \
|
||
|
__func__, __LINE__, pc_current->GetOrigLine(), pc_current->GetOrigCol(), pc_current->Text(), get_token_name(pc_current->GetType()), pc_current->IsPreproc() ? "true" : "false"); \
|
||
|
} \
|
||
|
else \
|
||
|
{ \
|
||
|
LOG_FMT(sev, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s', type is %s, PRE is %s\n", \
|
||
|
__func__, __LINE__, pc_current->GetOrigLine(), pc_current->GetOrigCol(), pc_current->Text(), get_token_name(pc_current->GetType()), pc_current->IsPreproc() ? "true" : "false"); \
|
||
|
}
|
||
|
|
||
|
|
||
4 years ago
|
#ifdef DEBUG
|
||
|
/**
|
||
|
* This should be called as the first thing in a function.
|
||
|
* It uses the log_func class to add an entry to the function log stack.
|
||
|
* It is automatically removed when the function returns.
|
||
|
*/
|
||
4 years ago
|
#define LOG_FUNC_ENTRY() log_func log_fe = log_func(__unqualified_func__, __LINE__)
|
||
4 years ago
|
|
||
|
|
||
|
#else
|
||
|
#define LOG_FUNC_ENTRY()
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/**
|
||
|
* This class just adds a entry to the top of the stack on construction and
|
||
|
* removes it on destruction.
|
||
|
* RAII for the win.
|
||
|
*/
|
||
|
class log_func
|
||
|
{
|
||
|
public:
|
||
|
log_func(const char *name, int line);
|
||
|
|
||
|
|
||
|
~log_func();
|
||
|
};
|
||
|
|
||
|
|
||
|
void log_func_stack(log_sev_t sev, const char *prefix = 0, const char *suffix = "\n", size_t skip_cnt = 0);
|
||
|
|
||
|
|
||
4 years ago
|
/**
|
||
|
* Return the unqualified function name from the input argument
|
||
|
* @param the qualified function name, usually provided by __func__ macro
|
||
|
* @return the corresponding unqualified name
|
||
|
*/
|
||
|
const char *get_unqualified_func_name(const char *func);
|
||
|
|
||
|
|
||
4 years ago
|
#define log_func_stack_inline(_sev) log_func_stack((_sev), " [CallStack:", "]\n", 0)
|
||
|
|
||
|
|
||
|
#endif /* LOGGER_H_INCLUDED */
|