1 /* 2 * This program is free software; you can redistribute it and/or 3 * modify it under the terms of the GNU General Public License 4 * as published by the Free Software Foundation; either version 2 5 * of the License, or (at your option) any later version. 6 * 7 * This program is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * GNU General Public License for more details. 11 * 12 * You should have received a copy of the GNU General Public License 13 * along with this program; if not, write to the Free Software Foundation, 14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 15 */ 16 17 #ifndef __CLG_LOG_H__ 18 #define __CLG_LOG_H__ 19 20 /** \file 21 * \ingroup clog 22 * 23 * C Logging Library (clog) 24 * ======================== 25 * 26 * Usage 27 * ----- 28 * 29 * - `CLG_LOGREF_DECLARE_GLOBAL` macro to declare #CLG_LogRef pointers. 30 * - `CLOG_` prefixed macros for logging. 31 * 32 * Identifiers 33 * ----------- 34 * 35 * #CLG_LogRef holds an identifier which defines the category of the logger. 36 * 37 * You can define and use identifiers as needed, logging will lazily initialize them. 38 * 39 * By convention lower case dot separated identifiers are used, eg: 40 * `module.sub_module`, this allows filtering by `module.*`, 41 * see #CLG_type_filter_include, #CLG_type_filter_exclude 42 * 43 * There is currently no functionality to remove a category once it's created. 44 * 45 * Severity 46 * -------- 47 * 48 * - `INFO`: Simply log events, uses verbosity levels to control how much information to show. 49 * - `WARN`: General warnings (which aren't necessary to show to users). 50 * - `ERROR`: An error we can recover from, should not happen. 51 * - `FATAL`: Similar to assert. This logs the message, then a stack trace and abort. 52 * Verbosity Level 53 * --------------- 54 * 55 * Usage: 56 * 57 * - 0: Always show (used for warnings, errors). 58 * Should never get in the way or become annoying. 59 * 60 * - 1: Top level module actions (eg: load a file, create a new window .. etc). 61 * 62 * - 2: Actions within a module (steps which compose an action, but don't flood output). 63 * Running a tool, full data recalculation. 64 * 65 * - 3: Detailed actions which may be of interest when debugging internal logic of a module 66 * These *may* flood the log with details. 67 * 68 * - 4+: May be used for more details than 3, should be avoided but not prevented. 69 */ 70 71 #ifdef __cplusplus 72 extern "C" { 73 #endif /* __cplusplus */ 74 75 #ifdef __GNUC__ 76 # define _CLOG_ATTR_NONNULL(args...) __attribute__((nonnull(args))) 77 #else 78 # define _CLOG_ATTR_NONNULL(...) 79 #endif 80 81 #ifdef __GNUC__ 82 # define _CLOG_ATTR_PRINTF_FORMAT(format_param, dots_param) \ 83 __attribute__((format(printf, format_param, dots_param))) 84 #else 85 # define _CLOG_ATTR_PRINTF_FORMAT(format_param, dots_param) 86 #endif 87 88 #define STRINGIFY_ARG(x) "" #x 89 #define STRINGIFY_APPEND(a, b) "" a #b 90 #define STRINGIFY(x) STRINGIFY_APPEND("", x) 91 92 struct CLogContext; 93 94 /* Don't typedef enums. */ 95 enum CLG_LogFlag { 96 CLG_FLAG_USE = (1 << 0), 97 }; 98 99 enum CLG_Severity { 100 CLG_SEVERITY_INFO = 0, 101 CLG_SEVERITY_WARN, 102 CLG_SEVERITY_ERROR, 103 CLG_SEVERITY_FATAL, 104 }; 105 #define CLG_SEVERITY_LEN (CLG_SEVERITY_FATAL + 1) 106 107 /* Each logger ID has one of these. */ 108 typedef struct CLG_LogType { 109 struct CLG_LogType *next; 110 char identifier[64]; 111 /** FILE output. */ 112 struct CLogContext *ctx; 113 /** Control behavior. */ 114 int level; 115 enum CLG_LogFlag flag; 116 } CLG_LogType; 117 118 typedef struct CLG_LogRef { 119 const char *identifier; 120 CLG_LogType *type; 121 } CLG_LogRef; 122 123 void CLG_log_str(CLG_LogType *lg, 124 enum CLG_Severity severity, 125 const char *file_line, 126 const char *fn, 127 const char *message) _CLOG_ATTR_NONNULL(1, 3, 4, 5); 128 void CLG_logf(CLG_LogType *lg, 129 enum CLG_Severity severity, 130 const char *file_line, 131 const char *fn, 132 const char *format, 133 ...) _CLOG_ATTR_NONNULL(1, 3, 4, 5) _CLOG_ATTR_PRINTF_FORMAT(5, 6); 134 135 /* Main initializer and destructor (per session, not logger). */ 136 void CLG_init(void); 137 void CLG_exit(void); 138 139 void CLG_output_set(void *file_handle); 140 void CLG_output_use_basename_set(int value); 141 void CLG_output_use_timestamp_set(int value); 142 void CLG_error_fn_set(void (*error_fn)(void *file_handle)); 143 void CLG_fatal_fn_set(void (*fatal_fn)(void *file_handle)); 144 void CLG_backtrace_fn_set(void (*fatal_fn)(void *file_handle)); 145 146 void CLG_type_filter_include(const char *type_filter, int type_filter_len); 147 void CLG_type_filter_exclude(const char *type_filter, int type_filter_len); 148 149 void CLG_level_set(int level); 150 151 void CLG_logref_init(CLG_LogRef *clg_ref); 152 153 int CLG_color_support_get(CLG_LogRef *clg_ref); 154 155 /** Declare outside function, declare as extern in header. */ 156 #define CLG_LOGREF_DECLARE_GLOBAL(var, id) \ 157 static CLG_LogRef _static_##var = {id}; \ 158 CLG_LogRef *var = &_static_##var 159 160 /** Initialize struct once. */ 161 #define CLOG_ENSURE(clg_ref) \ 162 ((clg_ref)->type ? (clg_ref)->type : (CLG_logref_init(clg_ref), (clg_ref)->type)) 163 164 #define CLOG_CHECK(clg_ref, verbose_level, ...) \ 165 ((void)CLOG_ENSURE(clg_ref), \ 166 ((clg_ref)->type->flag & CLG_FLAG_USE) && ((clg_ref)->type->level >= verbose_level)) 167 168 #define CLOG_AT_SEVERITY(clg_ref, severity, verbose_level, ...) \ 169 { \ 170 CLG_LogType *_lg_ty = CLOG_ENSURE(clg_ref); \ 171 if (((_lg_ty->flag & CLG_FLAG_USE) && (_lg_ty->level >= verbose_level)) || \ 172 (severity >= CLG_SEVERITY_WARN)) { \ 173 CLG_logf(_lg_ty, severity, __FILE__ ":" STRINGIFY(__LINE__), __func__, __VA_ARGS__); \ 174 } \ 175 } \ 176 ((void)0) 177 178 #define CLOG_STR_AT_SEVERITY(clg_ref, severity, verbose_level, str) \ 179 { \ 180 CLG_LogType *_lg_ty = CLOG_ENSURE(clg_ref); \ 181 if (((_lg_ty->flag & CLG_FLAG_USE) && (_lg_ty->level >= verbose_level)) || \ 182 (severity >= CLG_SEVERITY_WARN)) { \ 183 CLG_log_str(_lg_ty, severity, __FILE__ ":" STRINGIFY(__LINE__), __func__, str); \ 184 } \ 185 } \ 186 ((void)0) 187 188 #define CLOG_STR_AT_SEVERITY_N(clg_ref, severity, verbose_level, str) \ 189 { \ 190 CLG_LogType *_lg_ty = CLOG_ENSURE(clg_ref); \ 191 if (((_lg_ty->flag & CLG_FLAG_USE) && (_lg_ty->level >= verbose_level)) || \ 192 (severity >= CLG_SEVERITY_WARN)) { \ 193 const char *_str = str; \ 194 CLG_log_str(_lg_ty, severity, __FILE__ ":" STRINGIFY(__LINE__), __func__, _str); \ 195 MEM_freeN((void *)_str); \ 196 } \ 197 } \ 198 ((void)0) 199 200 #define CLOG_INFO(clg_ref, level, ...) \ 201 CLOG_AT_SEVERITY(clg_ref, CLG_SEVERITY_INFO, level, __VA_ARGS__) 202 #define CLOG_WARN(clg_ref, ...) CLOG_AT_SEVERITY(clg_ref, CLG_SEVERITY_WARN, 0, __VA_ARGS__) 203 #define CLOG_ERROR(clg_ref, ...) CLOG_AT_SEVERITY(clg_ref, CLG_SEVERITY_ERROR, 0, __VA_ARGS__) 204 #define CLOG_FATAL(clg_ref, ...) CLOG_AT_SEVERITY(clg_ref, CLG_SEVERITY_FATAL, 0, __VA_ARGS__) 205 206 #define CLOG_STR_INFO(clg_ref, level, str) \ 207 CLOG_STR_AT_SEVERITY(clg_ref, CLG_SEVERITY_INFO, level, str) 208 #define CLOG_STR_WARN(clg_ref, str) CLOG_STR_AT_SEVERITY(clg_ref, CLG_SEVERITY_WARN, 0, str) 209 #define CLOG_STR_ERROR(clg_ref, str) CLOG_STR_AT_SEVERITY(clg_ref, CLG_SEVERITY_ERROR, 0, str) 210 #define CLOG_STR_FATAL(clg_ref, str) CLOG_STR_AT_SEVERITY(clg_ref, CLG_SEVERITY_FATAL, 0, str) 211 212 /* Allocated string which is immediately freed. */ 213 #define CLOG_STR_INFO_N(clg_ref, level, str) \ 214 CLOG_STR_AT_SEVERITY_N(clg_ref, CLG_SEVERITY_INFO, level, str) 215 #define CLOG_STR_WARN_N(clg_ref, str) CLOG_STR_AT_SEVERITY_N(clg_ref, CLG_SEVERITY_WARN, 0, str) 216 #define CLOG_STR_ERROR_N(clg_ref, str) CLOG_STR_AT_SEVERITY_N(clg_ref, CLG_SEVERITY_ERROR, 0, str) 217 #define CLOG_STR_FATAL_N(clg_ref, str) CLOG_STR_AT_SEVERITY_N(clg_ref, CLG_SEVERITY_FATAL, 0, str) 218 219 #ifdef __cplusplus 220 } 221 #endif 222 223 #endif /* __CLG_LOG_H__ */ 224