/** @file * * Copyright 2021, João Valverde * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef __WSLOG_H__ #define __WSLOG_H__ #include #include #include #include #include #include #include #include #include #ifdef WS_LOG_DOMAIN #define _LOG_DOMAIN WS_LOG_DOMAIN #else #define _LOG_DOMAIN "" #endif #ifdef WS_DISABLE_DEBUG #define _LOG_DEBUG_ENABLED false #else #define _LOG_DEBUG_ENABLED true #endif /* * Define the macro WS_LOG_DOMAIN *before* including this header, * for example: * #define WS_LOG_DOMAIN LOG_DOMAIN_MAIN */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** Callback for registering a log writer. */ typedef void (ws_log_writer_cb)(const char *domain, enum ws_log_level level, struct timespec timestamp, const char *file, long line, const char *func, const char *user_format, va_list user_ap, void *user_data); /** Callback for freeing a user data pointer. */ typedef void (ws_log_writer_free_data_cb)(void *user_data); WS_DLL_PUBLIC void ws_log_file_writer(FILE *fp, const char *domain, enum ws_log_level level, struct timespec timestamp, const char *file, long line, const char *func, const char *user_format, va_list user_ap); WS_DLL_PUBLIC void ws_log_console_writer(const char *domain, enum ws_log_level level, struct timespec timestamp, const char *file, long line, const char *func, const char *user_format, va_list user_ap); /** Configure log levels "info" and below to use stdout. * * Normally all log messages are written to stderr. For backward compatibility * with GLib calling this function with TRUE configures log levels "info", * "debug" and "noisy" to be written to stdout. */ WS_DLL_PUBLIC void ws_log_console_writer_set_use_stdout(bool use_stdout); /** Convert a numerical level to its string representation. */ WS_DLL_PUBLIC WS_RETNONNULL const char *ws_log_level_to_string(enum ws_log_level level); /** Checks if a domain and level combination generate output. * * Returns TRUE if a message will be printed for the domain/level combo. */ WS_DLL_PUBLIC bool ws_log_msg_is_active(const char *domain, enum ws_log_level level); /** Return the currently active log level. */ WS_DLL_PUBLIC enum ws_log_level ws_log_get_level(void); /** Set the active log level. Returns the active level or LOG_LEVEL_NONE * if level is invalid. */ WS_DLL_PUBLIC enum ws_log_level ws_log_set_level(enum ws_log_level level); /** Set the active log level from a string. * * String levels are "error", "critical", "warning", "message", "info", * "debug" and "noisy" (case insensitive). * Returns the new log level or LOG_LEVEL NONE if the string representation * is invalid. */ WS_DLL_PUBLIC enum ws_log_level ws_log_set_level_str(const char *str_level); /** Set a domain filter from a string. * * Domain filter is a case insensitive list separated by ',' or ';'. Only * the domains in the filter will generate output; the others will be muted. * Filter expressions can be preceded by '!' to invert the sense of the match. * In this case only non-matching domains will generate output. */ WS_DLL_PUBLIC void ws_log_set_domain_filter(const char *domain_filter); /** Set a debug filter from a string. * * A debug filter lists all domains that should have debug level output turned * on, regardless of the global log level and domain filter. If negated * then debug (and below) will be disabled and the others unaffected by * the filter. */ WS_DLL_PUBLIC void ws_log_set_debug_filter(const char *str_filter); /** Set a noisy filter from a string. * * Same as ws_log_set_debug_filter() for "noisy" level. */ WS_DLL_PUBLIC void ws_log_set_noisy_filter(const char *str_filter); /** Set the fatal log level. * * Sets the log level at which calls to ws_log() will abort the program. The * argument can be LOG_LEVEL_ERROR, LOG_LEVEL_CRITICAL or LOG_LEVEL_WARNING. * Level LOG_LEVEL_ERROR is always fatal. */ WS_DLL_PUBLIC void ws_log_set_fatal(enum ws_log_level level); /** Set the fatal log level from a string. * * Same as ws_log_set_fatal(), but accepts the strings "error", critical" or * "warning" instead as arguments. */ WS_DLL_PUBLIC enum ws_log_level ws_log_set_fatal_str(const char *str_level); /** Set the active log writer. * * The parameter 'writer' can be NULL to use the default writer. */ WS_DLL_PUBLIC void ws_log_set_writer(ws_log_writer_cb *writer); /** Set the active log writer. * * The parameter 'writer' can be NULL to use the default writer. * Accepts an extra user_data parameter that will be passed to * the log writer. */ WS_DLL_PUBLIC void ws_log_set_writer_with_data(ws_log_writer_cb *writer, void *user_data, ws_log_writer_free_data_cb *free_user_data); #define LOG_ARGS_NOEXIT -1 /** Parses the command line arguments for log options. * * Returns zero for no error, non-zero for one or more invalid options. */ WS_DLL_PUBLIC int ws_log_parse_args(int *argc_ptr, char *argv[], void (*vcmdarg_err)(const char *, va_list ap), int exit_failure); /** Initializes the logging code. * * Must be called at startup before using the log API. If provided * vcmdarg_err is used to print initialization errors. This usually means * a misconfigured environment variable. */ WS_DLL_PUBLIC void ws_log_init(const char *progname, void (*vcmdarg_err)(const char *, va_list ap)); /** Initializes the logging code. * * Can be used instead of wslog_init(). Takes an extra writer argument. * If provided this callback will be used instead of the default writer. */ WS_DLL_PUBLIC void ws_log_init_with_writer(const char *progname, ws_log_writer_cb *writer, void (*vcmdarg_err)(const char *, va_list ap)); /** Initializes the logging code. * * Accepts a user data pointer in addition to the writer. This pointer will * be provided to the writer with every invocation. If provided * free_user_data will be called during cleanup. */ WS_DLL_PUBLIC void ws_log_init_with_writer_and_data(const char *progname, ws_log_writer_cb *writer, void *user_data, ws_log_writer_free_data_cb *free_user_data, void (*vcmdarg_err)(const char *, va_list ap)); /** This function is called to output a message to the log. * * Takes a format string and a variable number of arguments. */ WS_DLL_PUBLIC void ws_log(const char *domain, enum ws_log_level level, const char *format, ...) G_GNUC_PRINTF(3,4); /** This function is called to output a message to the log. * * Takes a format string and a 'va_list'. */ WS_DLL_PUBLIC void ws_logv(const char *domain, enum ws_log_level level, const char *format, va_list ap); /** This function is called to output a message to the log. * * In addition to the message this function accepts file/line/function * information. */ WS_DLL_PUBLIC void ws_log_full(const char *domain, enum ws_log_level level, const char *file, long line, const char *func, const char *format, ...) G_GNUC_PRINTF(6,7); /** This function is called to output a message to the log. * * In addition to the message this function accepts file/line/function * information. */ WS_DLL_PUBLIC void ws_logv_full(const char *domain, enum ws_log_level level, const char *file, long line, const char *func, const char *format, va_list ap); WS_DLL_PUBLIC WS_NORETURN void ws_log_fatal_full(const char *domain, enum ws_log_level level, const char *file, long line, const char *func, const char *format, ...) G_GNUC_PRINTF(6,7); /* * The if condition avoids -Wunused warnings for variables used only with * !WS_DISABLE_DEBUG, typically inside a ws_debug() call. The compiler will * optimize away the dead execution branch. */ #define _LOG_IF_ACTIVE(active, level, file, line, func, ...) \ do { \ if (active) { \ ws_log_full(_LOG_DOMAIN, level, \ file, line, func, \ __VA_ARGS__); \ } \ } while (0) #define _LOG_FULL(active, level, ...) \ _LOG_IF_ACTIVE(active, level, __FILE__, __LINE__, __func__, __VA_ARGS__) #define _LOG_SIMPLE(active, level, ...) \ _LOG_IF_ACTIVE(active, level, NULL, -1, NULL, __VA_ARGS__) /** Logs with "error" level. * * Accepts a format string and includes the file and function name. * * "error" is always fatal and terminates the program with a coredump. */ #define ws_error(...) \ ws_log_fatal_full(_LOG_DOMAIN, LOG_LEVEL_ERROR, \ __FILE__, __LINE__, __func__, __VA_ARGS__) /** Logs with "critical" level. * * Accepts a format string and includes the file and function name. */ #define ws_critical(...) \ _LOG_FULL(true, LOG_LEVEL_CRITICAL, __VA_ARGS__) /** Logs with "warning" level. * * Accepts a format string and includes the file and function name. */ #define ws_warning(...) \ _LOG_FULL(true, LOG_LEVEL_WARNING, __VA_ARGS__) /** Logs with "message" level. * * Accepts a format string and *does not* include the file and function * name. This is the default log level. */ #define ws_message(...) \ _LOG_SIMPLE(true, LOG_LEVEL_MESSAGE, __VA_ARGS__) /** Logs with "info" level. * * Accepts a format string and includes the file and function name. */ #define ws_info(...) \ _LOG_FULL(true, LOG_LEVEL_INFO, __VA_ARGS__) /** Logs with "debug" level. * * Accepts a format string and includes the file and function name. */ #define ws_debug(...) \ _LOG_FULL(_LOG_DEBUG_ENABLED, LOG_LEVEL_DEBUG, __VA_ARGS__) /** Logs with "noisy" level. * * Accepts a format string and includes the file and function name. */ #define ws_noisy(...) \ _LOG_FULL(_LOG_DEBUG_ENABLED, LOG_LEVEL_NOISY, __VA_ARGS__) /** Used for temporary debug print outs, always active. */ #define WS_DEBUG_HERE(...) \ _LOG_FULL(true, LOG_LEVEL_ECHO, __VA_ARGS__) /** This function is called to log a buffer (bytes array). * * Accepts an optional 'msg' argument to provide a description. */ WS_DLL_PUBLIC void ws_log_buffer_full(const char *domain, enum ws_log_level level, const char *file, long line, const char *func, const uint8_t *buffer, size_t size, size_t max_bytes_len, const char *msg); #define ws_log_buffer(buf, size) \ do { \ if (_LOG_DEBUG_ENABLED) { \ ws_log_buffer_full(_LOG_DOMAIN, LOG_LEVEL_DEBUG, \ __FILE__, __LINE__, __func__, \ buf, size, 36, #buf); \ } \ } while (0) /** Auxiliary function to write custom logging functions. * * This function is the same as ws_log_full() but does not perform any * domain/level filtering to avoid a useless double activation check. * It should only be used in conjunction with a pre-check using * ws_log_msg_is_active(). */ WS_DLL_PUBLIC void ws_log_write_always_full(const char *domain, enum ws_log_level level, const char *file, long line, const char *func, const char *format, ...) G_GNUC_PRINTF(6,7); /** Define an auxiliary file pointer where messages should be written. * * This file, if set, functions in addition to the registered or * default log writer. */ WS_DLL_PUBLIC void ws_log_add_custom_file(FILE *fp); WS_DLL_PUBLIC void ws_log_print_usage(FILE *fp); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* __WSLOG_H__ */