1 /*
2  * Library Log/Debug Interface
3  * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com>
4  * Dedicated to the Public Domain
5  */
6 
7 /*
8  * Library Log/Debug Interface
9  * Libraries should always avoid producing side-effects. This includes writing
10  * log-messages of any kind. However, you often don't want to disable debugging
11  * entirely, therefore, the core objects often contain a pointer to a function
12  * which performs logging. If that pointer is NULL (default), logging is
13  * disabled.
14  *
15  * This header should never be installed into the system! This is _no_ public
16  * header. Instead, copy it into your application if you want and use it there.
17  * Your public library API should include something like this:
18  *
19  *   typedef void (*MYPREFIX_log_t) (void *data,
20  *                                   const char *file,
21  *                                   int line,
22  *                                   const char *func,
23  *                                   const char *subs,
24  *                                   unsigned int sev,
25  *                                   const char *format,
26  *                                   va_list args);
27  *
28  * And then the user can supply such a function when creating a new context
29  * object of your library or simply supply NULL. Internally, you have a field of
30  * type "MYPREFIX_log_t llog" in your main structure. If you pass this to the
31  * convenience helpers like llog_dbg(), llog_warn() etc. it will automatically
32  * use the "llog" field to print the message. If it is NULL, nothing is done.
33  *
34  * The arguments of the log-function are defined as:
35  *   data: User-supplied data field that is passed straight through.
36  *   file: Zero terminated string of the file-name where the log-message
37  *         occurred. Can be NULL.
38  *   line: Line number of @file where the message occurred. Set to 0 or smaller
39  *         if not available.
40  *   func: Function name where the log-message occurred. Can be NULL.
41  *   subs: Subsystem where the message occurred (zero terminated). Can be NULL.
42  *   sev: Severity of log-message. An integer between 0 and 7 as defined below.
43  *        These are identical to the linux-kernel severities so there is no need
44  *        to include these in your public API. Every app can define them
45  *        themselves, if they need it.
46  *   format: Format string. Must not be NULL.
47  *   args: Argument array
48  *
49  * The user should also be able to optionally provide a data field which is
50  * always passed unmodified as first parameter to the log-function. This allows
51  * to add context to the logger.
52  */
53 
54 #ifndef SHL_LLOG_H_INCLUDED
55 #define SHL_LLOG_H_INCLUDED
56 
57 #include <stdarg.h>
58 #include <stdbool.h>
59 #include <stdlib.h>
60 
61 enum llog_severity {
62 	LLOG_FATAL = 0,
63 	LLOG_ALERT = 1,
64 	LLOG_CRITICAL = 2,
65 	LLOG_ERROR = 3,
66 	LLOG_WARNING = 4,
67 	LLOG_NOTICE = 5,
68 	LLOG_INFO = 6,
69 	LLOG_DEBUG = 7,
70 	LLOG_SEV_NUM,
71 };
72 
73 typedef void (*llog_submit_t) (void *data,
74 			       const char *file,
75 			       int line,
76 			       const char *func,
77 			       const char *subs,
78 			       unsigned int sev,
79 			       const char *format,
80 			       va_list args);
81 
82 static inline __attribute__((format(printf, 8, 9)))
llog_format(llog_submit_t llog,void * data,const char * file,int line,const char * func,const char * subs,unsigned int sev,const char * format,...)83 void llog_format(llog_submit_t llog,
84 		 void *data,
85 		 const char *file,
86 		 int line,
87 		 const char *func,
88 		 const char *subs,
89 		 unsigned int sev,
90 		 const char *format,
91 		 ...)
92 {
93 	va_list list;
94 
95 	if (llog) {
96 		va_start(list, format);
97 		llog(data, file, line, func, subs, sev, format, list);
98 		va_end(list);
99 	}
100 }
101 
102 #ifndef LLOG_SUBSYSTEM
103 static const char *LLOG_SUBSYSTEM __attribute__((__unused__));
104 #endif
105 
106 #define LLOG_DEFAULT __FILE__, __LINE__, __func__, LLOG_SUBSYSTEM
107 
108 #define llog_printf(obj, sev, format, ...) \
109 	llog_format((obj)->llog, \
110 		    (obj)->llog_data, \
111 		    LLOG_DEFAULT, \
112 		    (sev), \
113 		    (format), \
114 		    ##__VA_ARGS__)
115 #define llog_dprintf(obj, data, sev, format, ...) \
116 	llog_format((obj), \
117 		    (data), \
118 		    LLOG_DEFAULT, \
119 		    (sev), \
120 		    (format), \
121 		    ##__VA_ARGS__)
122 
123 static inline __attribute__((format(printf, 4, 5)))
llog_dummyf(llog_submit_t llog,void * data,unsigned int sev,const char * format,...)124 void llog_dummyf(llog_submit_t llog, void *data, unsigned int sev,
125 		 const char *format, ...)
126 {
127 }
128 
129 /*
130  * Helpers
131  * They pick-up all the default values and submit the message to the
132  * llog-subsystem. The llog_debug() function produces zero-code if
133  * BUILD_ENABLE_DEBUG is not defined. Therefore, it can be heavily used for
134  * debugging and will not have any side-effects.
135  */
136 
137 #ifdef BUILD_ENABLE_DEBUG
138 	#define llog_ddebug(obj, data, format, ...) \
139 		llog_dprintf((obj), (data), LLOG_DEBUG, (format), ##__VA_ARGS__)
140 	#define llog_debug(obj, format, ...) \
141 		llog_ddebug((obj)->llog, (obj)->llog_data, (format), ##__VA_ARGS__)
142 #else
143 	#define llog_ddebug(obj, data, format, ...) \
144 		llog_dummyf((obj), (data), LLOG_DEBUG, (format), ##__VA_ARGS__)
145 	#define llog_debug(obj, format, ...) \
146 		llog_ddebug((obj)->llog, (obj)->llog_data, (format), ##__VA_ARGS__)
147 #endif
148 
149 #define llog_info(obj, format, ...) \
150 	llog_printf((obj), LLOG_INFO, (format), ##__VA_ARGS__)
151 #define llog_dinfo(obj, data, format, ...) \
152 	llog_dprintf((obj), (data), LLOG_INFO, (format), ##__VA_ARGS__)
153 #define llog_notice(obj, format, ...) \
154 	llog_printf((obj), LLOG_NOTICE, (format), ##__VA_ARGS__)
155 #define llog_dnotice(obj, data, format, ...) \
156 	llog_dprintf((obj), (data), LLOG_NOTICE, (format), ##__VA_ARGS__)
157 #define llog_warning(obj, format, ...) \
158 	llog_printf((obj), LLOG_WARNING, (format), ##__VA_ARGS__)
159 #define llog_dwarning(obj, data, format, ...) \
160 	llog_dprintf((obj), (data), LLOG_WARNING, (format), ##__VA_ARGS__)
161 #define llog_error(obj, format, ...) \
162 	llog_printf((obj), LLOG_ERROR, (format), ##__VA_ARGS__)
163 #define llog_derror(obj, data, format, ...) \
164 	llog_dprintf((obj), (data), LLOG_ERROR, (format), ##__VA_ARGS__)
165 #define llog_critical(obj, format, ...) \
166 	llog_printf((obj), LLOG_CRITICAL, (format), ##__VA_ARGS__)
167 #define llog_dcritical(obj, data, format, ...) \
168 	llog_dprintf((obj), (data), LLOG_CRITICAL, (format), ##__VA_ARGS__)
169 #define llog_alert(obj, format, ...) \
170 	llog_printf((obj), LLOG_ALERT, (format), ##__VA_ARGS__)
171 #define llog_dalert(obj, data, format, ...) \
172 	llog_dprintf((obj), (data), LLOG_ALERT, (format), ##__VA_ARGS__)
173 #define llog_fatal(obj, format, ...) \
174 	llog_printf((obj), LLOG_FATAL, (format), ##__VA_ARGS__)
175 #define llog_dfatal(obj, data, format, ...) \
176 	llog_dprintf((obj), (data), LLOG_FATAL, (format), ##__VA_ARGS__)
177 
178 #define llog_dbg llog_debug
179 #define llog_warn llog_warning
180 #define llog_err llog_error
181 #define llog_crit llog_critical
182 
183 /*
184  * Default log messages
185  * These macros can be used to produce default log messages. You can use them
186  * directly in an "return" statement. The "v" variants automatically cast the
187  * result to void so it can be used in return statements inside of void
188  * functions. The "d" variants use the logging object directly as the parent
189  * might not exist, yet.
190  *
191  * Most of the messages work only if debugging is enabled. This is, because they
192  * are used in debug paths and would slow down normal applications.
193  */
194 
195 #define llog_dEINVAL(obj, data) \
196 	(llog_ddebug((obj), (data), "invalid arguments"), -EINVAL)
197 #define llog_EINVAL(obj) \
198 	(llog_dEINVAL((obj)->llog, (obj)->llog_data))
199 #define llog_vEINVAL(obj) \
200 	((void)llog_EINVAL(obj))
201 #define llog_vdEINVAL(obj, data) \
202 	((void)llog_dEINVAL((obj), (data)))
203 
204 #define llog_dEFAULT(obj, data) \
205 	(llog_ddebug((obj), (data), "operation failed"), -EFAULT)
206 #define llog_EFAULT(obj) \
207 	(llog_dEFAULT((obj)->llog, (obj)->llog_data))
208 #define llog_vEFAULT(obj) \
209 	((void)llog_EFAULT(obj))
210 #define llog_vdEFAULT(obj, data) \
211 	((void)llog_dEFAULT((obj), (data)))
212 
213 #define llog_dENOMEM(obj, data) \
214 	(llog_ddebug((obj), (data), "memory allocation failed"), -ENOMEM)
215 #define llog_ENOMEM(obj) \
216 	(llog_dENOMEM((obj)->llog, (obj)->llog_data))
217 #define llog_vENOMEM(obj) \
218 	((void)llog_ENOMEM(obj))
219 #define llog_vdENOMEM(obj, data) \
220 	((void)llog_dENOMEM((obj), (data)))
221 
222 #endif /* SHL_LLOG_H_INCLUDED */
223