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