forked from iptube/SPUDlib
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ls_log.h
225 lines (205 loc) · 7.72 KB
/
ls_log.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
/**
* \file
* \brief
* Functions for simplified logging
*
* Copyright (c) 2015 SPUDlib authors. See LICENSE file.
*/
#pragma once
#include <stdarg.h>
#include <stdio.h>
#include <sys/errno.h>
#include "ls_mem.h"
/** Convenience macro for tracing a function entry where no arguments need to be
* logged */
#define LS_LOG_TRACE_FUNCTION_NO_ARGS \
ls_log(LS_LOG_TRACE, "entering: %s", __func__)
/** Convenience macro for tracing a function entry with logged arguments.
* The space after __func__ but before the comma is intentional as recommended
* at http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html for compatibility
*/
#define LS_LOG_TRACE_FUNCTION(fmt, ...) \
ls_log(LS_LOG_TRACE, "entering: %s; args=("fmt")", \
__func__ , __VA_ARGS__)
/**
* Enumeration of defined log levels
*/
typedef enum
{
/** Log level that indicates no messages should be output */
LS_LOG_NONE = 0,
/** Logging error-level messages */
LS_LOG_ERROR,
/** Logging warn-level messages */
LS_LOG_WARN,
/** Logging info-level messages */
LS_LOG_INFO,
/** Logging verbose-level messages */
LS_LOG_VERBOSE,
/** Logging debug-level messages */
LS_LOG_DEBUG,
/** Logging trace-level messages */
LS_LOG_TRACE,
/** Logging memory allocation-level messages */
LS_LOG_MEMTRACE
} ls_loglevel;
/**
* Signature of the log text generator function passed to ls_log_chunked(). No
* log message functions should be called from this function to avoid garbled
* output or infinite loops.
*
* \invariant chunk != NULL
* \invariant len != NULL
* \invariant free_fn != NULL
* \param[out] chunk A pointer to the fragment to append to the in-progress log
* message. The function will be called repeatedly until *chunk is set to
* NULL. If *len is not set or explicitly set to 0, *chunk is assumed to
* be a NULL-terminated string.
* \param[out] len A pointer to the length of the fragment pointed to by chunk.
* If *chunk is NULL-terminated, this variable does not need to be set.
* \param[out] free_fn A pointer to the function that will be called to free
* *chunk. If *chunk does not need freeing, *free_fn does not need to be
* set.
* \param[in] arg The user-supplied pointer passed to ls_log_chunked().
*/
typedef void (*ls_log_generator_fn)(
const char **chunk, size_t *len, ls_data_free_func *free_fn, void *arg);
#ifdef __cplusplus
extern "C"
{
#endif
/**
* Retrieve the string version of the ls_loglevel enum.
*
* \param level The log level to lookup
* \retval const char * The message for {level}
*/
LS_API const char *ls_log_level_name(ls_loglevel level);
/**
* Function like vfprintf to be used for logging.
*
* Note: Supplied function will be called three times for each log
* message; once for date/time/level preamble, once for the message and
* once for a trailing newline.
*
* \param stream Output stream, always stderr.
* \param format Format string like vfprintf.
* \param ap Additional parameters to interpolate into {fmt}.
* \retval Number of bytes written.
*/
typedef int (*ls_log_vararg_function)(
FILE *stream, const char *format, va_list ap);
/**
* Set the logging function.
*
* Log function defaults to vfprintf. A null parameter resets the
* log function to its default.
*
* Note: Not thread-safe.
*
* \param fn The vfprintf-like function to use.
*/
LS_API void ls_log_set_function(ls_log_vararg_function fn);
/**
* Set the current log level, defaults to LS_LOG_INFO.
*
* Everything at this level or less verbose than this level will be printed.
*
* Note: Not thread-safe.
*
* \param level The new log level.
*/
LS_API void ls_log_set_level(ls_loglevel level);
/**
* Get the current log level.
*
* \retval The current log level.
*/
LS_API ls_loglevel ls_log_get_level(void);
/**
* Enables or disables printing the NDC prefix for log messages. By default,
* the NDC prefix is enabled.
*
* \param[in] enabled true if the NDC should be output; otherwise false.
*/
LS_API void ls_log_set_ndc_enabled(bool enabled);
/**
* Pushes a nested diagnostic context onto the NDC stack. The given message
* will be prefixed to all subsequent messages until a corresponding call to
* ls_log_pop_ndc() is made.
*
* \invariant fmt != NULL
* \param[in] fmt The printf-style format string
* \param[in] ... Extra parameters to interpolate into {fmt}.
* @return The depth of the NDC stack after the given push. This must later
* be passed to ls_log_pop_ndc() to verify the consistency of the NDC stack. If
* this function fails to push (due, for example, to a low memory condition or
* a malformed format string), an appropriate warning will be printed and 0
* will be returned.
*/
LS_API int ls_log_push_ndc(const char *fmt, ...)
__attribute__ ((__format__ (__printf__, 1, 2)));
/**
* Pops a nested diagnostic context from the NDC stack.
*
* @param ndc_depth The value returned from ls_log_push_ndc(). If this value
* does not match the current NDC stack depth, a warning will be logged and
* the stack will be reduced to the expected depth. If 0 is passed in, this
* function is a noop.
*/
LS_API void ls_log_pop_ndc(int ndc_depth);
/**
* Log at the given level to stderr.
*
* All errors while logging are ignored (so this routine is not
* guaranteed to log). Extra parameters are injected into {fmt}
* using the rules from vfprintf.
*
* Log messages are prepended with date/time and log level and
* appended with a newline; YYYY-MM-DDTHH-MM-SS[level]: {fmt}\n
*
* Note: Not thread-safe with respect to the current log level.
*
* \invariant fmt != NULL
* \param[in] level The log level for this message. Note that LS_LOG_NONE is
* not a valid log level to pass to this function.
* \param[in] fmt The printf-style format to log
* \param[in] ... Extra parameters to interpolate into {fmt}.
*/
LS_API void ls_log(ls_loglevel level, const char *fmt, ...)
__attribute__ ((__format__ (__printf__, 2, 3)));
/**
* Log an error, with extra information. If the error is NULL,
* just use the extra information.
*
* Note: Not thread-safe with respect to the current log level.
*
* \invariant fmt != NULL
* \param[in] level The log level for this message. Note that LS_LOG_NONE is
* not a valid log level to pass to this function.
* \param[in] err The error to be printed (if not NULL).
* \param[in] fmt The printf-style format to log
* \param[in] ... Extra parameters to interpolate into {fmt}.
*/
LS_API void ls_log_err(ls_loglevel level, ls_err *err,
const char *fmt, ...) __attribute__ ((__format__ (__printf__, 3, 4)));
/**
* Log a message with content provided by a generator function. The content
* from the generator function will appear immediately after the specified fmt,
* i.e.: "fmt<generator fn output>\n"
*
* Note: Not thread-safe with respect to the current log level.
*
* \param[in] level The log level for this message. Note that LS_LOG_NONE is
* not a valid log level to pass to this function.
* \param[in] generator_fn The generator function that will provide the log
* message content.
* \param[in] arg The opaque pointer passed to the generator function.
* \param[in] fmt The printf-style format to log. If NULL, equivalent to "".
* \param[in] ... Extra parameters to interpolate into {fmt}.
*/
LS_API void ls_log_chunked(ls_loglevel level,
ls_log_generator_fn generator_fn, void *arg,
const char *fmt, ...) __attribute__ ((__format__ (__printf__, 4, 5)));
#define LS_LOG_ERR(err, what) ls_log(LS_LOG_ERROR, "%s:%d (%s) %d, %s", __FILE__, __LINE__, (what), (err).code, (err).message)
#define LS_LOG_PERROR(what) ls_log(LS_LOG_ERROR, "%s:%d (%s) %d, %s", __FILE__, __LINE__, (what), errno, strerror(errno))