The numeric levels have no obvious meaning. This removes the distinction between severity and levels, instead there is a single list of named levels with defined meaning. Debug means information that's mainly useful for developers, and trace is for very verbose code execution tracing. Pull Request: https://projects.blender.org/blender/blender/pulls/140244
198 lines
6.8 KiB
C
198 lines
6.8 KiB
C
/* SPDX-FileCopyrightText: 2018-2023 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup intern_clog
|
|
*
|
|
* C Logging Library (clog)
|
|
* ========================
|
|
*
|
|
* Usage
|
|
* -----
|
|
*
|
|
* - `CLG_LOGREF_DECLARE_GLOBAL` macro to declare #CLG_LogRef pointers.
|
|
* - `CLOG_` prefixed macros for logging.
|
|
*
|
|
* Identifiers
|
|
* -----------
|
|
*
|
|
* #CLG_LogRef holds an identifier which defines the category of the logger.
|
|
*
|
|
* You can define and use identifiers as needed, logging will lazily initialize them.
|
|
*
|
|
* By convention lower case dot separated identifiers are used, eg:
|
|
* `module.sub_module`, this allows filtering by `module.*`,
|
|
* see #CLG_type_filter_include, #CLG_type_filter_exclude
|
|
*
|
|
* There is currently no functionality to remove a category once it's created.
|
|
*
|
|
* Severity
|
|
* --------
|
|
*
|
|
* - `INFO`: Simply log events, uses verbosity levels to control how much information to show.
|
|
* - `WARN`: General warnings (which aren't necessary to show to users).
|
|
* - `ERROR`: An error we can recover from, should not happen.
|
|
* - `FATAL`: Similar to assert. This logs the message, then a stack trace and abort.
|
|
* Verbosity Level
|
|
* ---------------
|
|
*
|
|
* Usage:
|
|
*
|
|
* - 0: Always show (used for warnings, errors).
|
|
* Should never get in the way or become annoying.
|
|
*
|
|
* - 1: Top level module actions (eg: load a file, create a new window .. etc).
|
|
*
|
|
* - 2: Actions within a module (steps which compose an action, but don't flood output).
|
|
* Running a tool, full data recalculation.
|
|
*
|
|
* - 3: Detailed actions which may be of interest when debugging internal logic of a module
|
|
* These *may* flood the log with details.
|
|
*
|
|
* - 4+: May be used for more details than 3, should be avoided but not prevented.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#ifdef __GNUC__
|
|
# define _CLOG_ATTR_NONNULL(args...) __attribute__((nonnull(args)))
|
|
#else
|
|
# define _CLOG_ATTR_NONNULL(...)
|
|
#endif
|
|
|
|
#ifdef __GNUC__
|
|
# define _CLOG_ATTR_PRINTF_FORMAT(format_param, dots_param) \
|
|
__attribute__((format(printf, format_param, dots_param)))
|
|
#else
|
|
# define _CLOG_ATTR_PRINTF_FORMAT(format_param, dots_param)
|
|
#endif
|
|
|
|
#define STRINGIFY_ARG(x) "" #x
|
|
#define STRINGIFY_APPEND(a, b) "" a #b
|
|
#define STRINGIFY(x) STRINGIFY_APPEND("", x)
|
|
|
|
struct CLogContext;
|
|
|
|
enum CLG_Level {
|
|
CLG_LEVEL_FATAL = 0, /* Fatal errors */
|
|
CLG_LEVEL_ERROR = 1, /* Errors */
|
|
CLG_LEVEL_WARN = 2, /* Warnings */
|
|
CLG_LEVEL_INFO = 3, /* Information about devices, files, configuration, user operations */
|
|
CLG_LEVEL_DEBUG = 4, /* Debugging information for developers */
|
|
CLG_LEVEL_TRACE = 5, /* Very verbose code execution tracing */
|
|
};
|
|
#define CLG_LEVEL_LEN (CLG_LEVEL_TRACE + 1)
|
|
|
|
/* Each logger ID has one of these. */
|
|
struct CLG_LogType {
|
|
struct CLG_LogType *next;
|
|
char identifier[64];
|
|
/** FILE output. */
|
|
struct CLogContext *ctx;
|
|
/** Control behavior. */
|
|
CLG_Level level;
|
|
};
|
|
|
|
struct CLG_LogRef {
|
|
const char *identifier;
|
|
CLG_LogType *type;
|
|
struct CLG_LogRef *next;
|
|
};
|
|
|
|
void CLG_log_str(const CLG_LogType *lg,
|
|
enum CLG_Level level,
|
|
const char *file_line,
|
|
const char *fn,
|
|
const char *message) _CLOG_ATTR_NONNULL(1, 3, 4, 5);
|
|
void CLG_logf(const CLG_LogType *lg,
|
|
enum CLG_Level level,
|
|
const char *file_line,
|
|
const char *fn,
|
|
const char *format,
|
|
...) _CLOG_ATTR_NONNULL(1, 3, 4, 5) _CLOG_ATTR_PRINTF_FORMAT(5, 6);
|
|
|
|
/* Main initializer and destructor (per session, not logger). */
|
|
void CLG_init();
|
|
void CLG_exit();
|
|
|
|
void CLG_output_set(void *file_handle);
|
|
void CLG_output_use_source_set(int value);
|
|
void CLG_output_use_basename_set(int value);
|
|
void CLG_output_use_timestamp_set(int value);
|
|
void CLG_output_use_memory_set(int value);
|
|
void CLG_error_fn_set(void (*error_fn)(void *file_handle));
|
|
void CLG_fatal_fn_set(void (*fatal_fn)(void *file_handle));
|
|
void CLG_backtrace_fn_set(void (*fatal_fn)(void *file_handle));
|
|
|
|
void CLG_type_filter_include(const char *type_match, int type_match_len);
|
|
void CLG_type_filter_exclude(const char *type_match, int type_match_len);
|
|
|
|
void CLG_level_set(CLG_Level level);
|
|
|
|
void CLG_logref_init(CLG_LogRef *clg_ref);
|
|
|
|
int CLG_color_support_get(CLG_LogRef *clg_ref);
|
|
|
|
/** Declare outside function, declare as extern in header. */
|
|
#define CLG_LOGREF_DECLARE_GLOBAL(var, id) \
|
|
static CLG_LogRef _static_##var = {id}; \
|
|
CLG_LogRef *var = &_static_##var
|
|
|
|
/** Initialize struct once. */
|
|
#define CLOG_ENSURE(clg_ref) \
|
|
((clg_ref)->type ? (clg_ref)->type : (CLG_logref_init(clg_ref), (clg_ref)->type))
|
|
|
|
#define CLOG_CHECK(clg_ref, verbose_level, ...) \
|
|
((void)CLOG_ENSURE(clg_ref), ((clg_ref)->type->level >= verbose_level))
|
|
|
|
#define CLOG_AT_LEVEL(clg_ref, verbose_level, ...) \
|
|
{ \
|
|
const CLG_LogType *_lg_ty = CLOG_ENSURE(clg_ref); \
|
|
if (_lg_ty->level >= verbose_level) { \
|
|
CLG_logf(_lg_ty, verbose_level, __FILE__ ":" STRINGIFY(__LINE__), __func__, __VA_ARGS__); \
|
|
} \
|
|
} \
|
|
((void)0)
|
|
|
|
#define CLOG_AT_LEVEL_NOCHECK(clg_ref, verbose_level, ...) \
|
|
{ \
|
|
const CLG_LogType *_lg_ty = CLOG_ENSURE(clg_ref); \
|
|
CLG_logf(_lg_ty, verbose_level, __FILE__ ":" STRINGIFY(__LINE__), __func__, __VA_ARGS__); \
|
|
} \
|
|
((void)0)
|
|
|
|
#define CLOG_STR_AT_LEVEL(clg_ref, verbose_level, str) \
|
|
{ \
|
|
const CLG_LogType *_lg_ty = CLOG_ENSURE(clg_ref); \
|
|
if (_lg_ty->level >= verbose_level) { \
|
|
CLG_log_str(_lg_ty, verbose_level, __FILE__ ":" STRINGIFY(__LINE__), __func__, str); \
|
|
} \
|
|
} \
|
|
((void)0)
|
|
|
|
#define CLOG_STR_AT_LEVEL_NOCHECK(clg_ref, verbose_level, str) \
|
|
{ \
|
|
const CLG_LogType *_lg_ty = CLOG_ENSURE(clg_ref); \
|
|
CLG_log_str(_lg_ty, verbose_level, __FILE__ ":" STRINGIFY(__LINE__), __func__, str); \
|
|
} \
|
|
((void)0)
|
|
|
|
#define CLOG_FATAL(clg_ref, ...) CLOG_AT_LEVEL(clg_ref, CLG_LEVEL_FATAL, __VA_ARGS__)
|
|
#define CLOG_ERROR(clg_ref, ...) CLOG_AT_LEVEL(clg_ref, CLG_LEVEL_ERROR, __VA_ARGS__)
|
|
#define CLOG_WARN(clg_ref, ...) CLOG_AT_LEVEL(clg_ref, CLG_LEVEL_WARN, __VA_ARGS__)
|
|
#define CLOG_INFO(clg_ref, ...) CLOG_AT_LEVEL(clg_ref, CLG_LEVEL_INFO, __VA_ARGS__)
|
|
#define CLOG_DEBUG(clg_ref, ...) CLOG_AT_LEVEL(clg_ref, CLG_LEVEL_DEBUG, __VA_ARGS__)
|
|
#define CLOG_TRACE(clg_ref, ...) CLOG_AT_LEVEL(clg_ref, CLG_LEVEL_TRACE, __VA_ARGS__)
|
|
|
|
#define CLOG_STR_FATAL(clg_ref, str) CLOG_STR_AT_LEVEL(clg_ref, CLG_LEVEL_FATAL, str)
|
|
#define CLOG_STR_ERROR(clg_ref, str) CLOG_STR_AT_LEVEL(clg_ref, CLG_LEVEL_ERROR, str)
|
|
#define CLOG_STR_WARN(clg_ref, str) CLOG_STR_AT_LEVEL(clg_ref, CLG_LEVEL_WARN, str)
|
|
#define CLOG_STR_INFO(clg_ref, str) CLOG_STR_AT_LEVEL(clg_ref, CLG_LEVEL_INFO, str)
|
|
#define CLOG_STR_DEBUG(clg_ref, str) CLOG_STR_AT_LEVEL(clg_ref, CLG_LEVEL_DEBUG, str)
|
|
#define CLOG_STR_TRACE(clg_ref, str) CLOG_STR_AT_LEVEL(clg_ref, CLG_LEVEL_TRACE, str)
|
|
|
|
#define CLOG_INFO_NOCHECK(clg_ref, format, ...) \
|
|
CLOG_AT_LEVEL_NOCHECK(clg_ref, CLG_LEVEL_INFO, format, __VA_ARGS__)
|
|
#define CLOG_STR_INFO_NOCHECK(clg_ref, str) CLOG_STR_AT_LEVEL_NOCHECK(clg_ref, CLG_LEVEL_INFO, str)
|