blob: 52e7e67af7f86a5d88e0a8a1d765592c53edb279 [file] [log] [blame]
James Kuszmaul82f6c042021-01-17 11:30:16 -08001/**
2 * @file dbg.c Debug printing
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6#include <stdio.h>
7#ifdef HAVE_UNISTD_H
8#include <unistd.h>
9#endif
10#ifdef HAVE_PTHREAD
11#include <stdlib.h>
12#include <pthread.h>
13#endif
14#include <time.h>
15#include <re_types.h>
16#include <re_fmt.h>
17#include <re_list.h>
18#include <re_tmr.h>
19
20
21#define DEBUG_MODULE "dbg"
22#define DEBUG_LEVEL 0
23#include <re_dbg.h>
24
25
26/** Debug configuration */
27static struct {
28 uint64_t tick; /**< Init ticks */
29 int level; /**< Current debug level */
30 enum dbg_flags flags; /**< Debug flags */
31 dbg_print_h *ph; /**< Optional print handler */
32 void *arg; /**< Handler argument */
33 FILE *f; /**< Logfile */
34#ifdef HAVE_PTHREAD
35 pthread_mutex_t mutex; /**< Thread locking */
36#endif
37} dbg = {
38 0,
39 DBG_INFO,
40 DBG_ANSI,
41 NULL,
42 NULL,
43 NULL,
44#ifdef HAVE_PTHREAD
45 PTHREAD_MUTEX_INITIALIZER,
46#endif
47};
48
49
50#ifdef HAVE_PTHREAD
51static inline void dbg_lock(void)
52{
53 pthread_mutex_lock(&dbg.mutex);
54}
55
56
57static inline void dbg_unlock(void)
58{
59 pthread_mutex_unlock(&dbg.mutex);
60}
61#else
62#define dbg_lock() /**< Stub */
63#define dbg_unlock() /**< Stub */
64#endif
65
66
67/**
68 * Initialise debug printing
69 *
70 * @param level Debug level
71 * @param flags Debug flags
72 */
73void dbg_init(int level, enum dbg_flags flags)
74{
75 dbg.tick = tmr_jiffies();
76 dbg.level = level;
77 dbg.flags = flags;
78}
79
80
81/**
82 * Close debugging
83 */
84void dbg_close(void)
85{
86 if (dbg.f) {
87 (void)fclose(dbg.f);
88 dbg.f = NULL;
89 }
90}
91
92
93/**
94 * Set debug logfile
95 *
96 * @param name Name of the logfile, NULL to close
97 *
98 * @return 0 if success, otherwise errorcode
99 */
100int dbg_logfile_set(const char *name)
101{
102 time_t t;
103
104 dbg_close();
105
106 if (!name)
107 return 0;
108
109 dbg.f = fopen(name, "a+");
110 if (!dbg.f)
111 return errno;
112
113 (void)time(&t);
114 (void)re_fprintf(dbg.f, "\n===== Log Started: %s", ctime(&t));
115 (void)fflush(dbg.f);
116
117 return 0;
118}
119
120
121/**
122 * Set optional debug print handler
123 *
124 * @param ph Print handler
125 * @param arg Handler argument
126 */
127void dbg_handler_set(dbg_print_h *ph, void *arg)
128{
129 dbg.ph = ph;
130 dbg.arg = arg;
131}
132
133
134/* NOTE: This function should not allocate memory */
135static void dbg_vprintf(int level, const char *fmt, va_list ap)
136{
137 if (level > dbg.level)
138 return;
139
140 /* Print handler? */
141 if (dbg.ph)
142 return;
143
144 dbg_lock();
145
146 if (dbg.flags & DBG_ANSI) {
147
148 switch (level) {
149
150 case DBG_WARNING:
151 (void)re_fprintf(stderr, "\x1b[31m"); /* Red */
152 break;
153
154 case DBG_NOTICE:
155 (void)re_fprintf(stderr, "\x1b[33m"); /* Yellow */
156 break;
157
158 case DBG_INFO:
159 (void)re_fprintf(stderr, "\x1b[32m"); /* Green */
160 break;
161
162 default:
163 break;
164 }
165 }
166
167 if (dbg.flags & DBG_TIME) {
168 const uint64_t ticks = tmr_jiffies();
169
170 if (0 == dbg.tick)
171 dbg.tick = tmr_jiffies();
172
173 (void)re_fprintf(stderr, "[%09llu] ", ticks - dbg.tick);
174 }
175
176 (void)re_vfprintf(stderr, fmt, ap);
177
178 if (dbg.flags & DBG_ANSI && level < DBG_DEBUG)
179 (void)re_fprintf(stderr, "\x1b[;m");
180
181 dbg_unlock();
182}
183
184
185/* Formatted output to print handler and/or logfile */
186static void dbg_fmt_vprintf(int level, const char *fmt, va_list ap)
187{
188 char buf[256];
189 int len;
190
191 if (level > dbg.level)
192 return;
193
194 if (!dbg.ph && !dbg.f)
195 return;
196
197 dbg_lock();
198
199 len = re_vsnprintf(buf, sizeof(buf), fmt, ap);
200 if (len <= 0)
201 goto out;
202
203 /* Print handler? */
204 if (dbg.ph) {
205 dbg.ph(level, buf, len, dbg.arg);
206 }
207
208 /* Output to file */
209 if (dbg.f) {
210 if (fwrite(buf, 1, len, dbg.f) > 0)
211 (void)fflush(dbg.f);
212 }
213
214 out:
215 dbg_unlock();
216}
217
218
219/**
220 * Print a formatted debug message
221 *
222 * @param level Debug level
223 * @param fmt Formatted string
224 */
225void dbg_printf(int level, const char *fmt, ...)
226{
227 va_list ap;
228
229 va_start(ap, fmt);
230 dbg_vprintf(level, fmt, ap);
231 va_end(ap);
232
233 va_start(ap, fmt);
234 dbg_fmt_vprintf(level, fmt, ap);
235 va_end(ap);
236}
237
238
239/**
240 * Print a formatted debug message to /dev/null
241 *
242 * @param fmt Formatted string
243 */
244void dbg_noprintf(const char *fmt, ...)
245{
246 (void)fmt;
247}
248
249
250/**
251 * Print a formatted warning message
252 *
253 * @param fmt Formatted string
254 */
255void dbg_warning(const char *fmt, ...)
256{
257 va_list ap;
258
259 va_start(ap, fmt);
260 dbg_vprintf(DBG_WARNING, fmt, ap);
261 va_end(ap);
262
263 va_start(ap, fmt);
264 dbg_fmt_vprintf(DBG_WARNING, fmt, ap);
265 va_end(ap);
266}
267
268
269/**
270 * Print a formatted notice message
271 *
272 * @param fmt Formatted string
273 */
274void dbg_notice(const char *fmt, ...)
275{
276 va_list ap;
277
278 va_start(ap, fmt);
279 dbg_vprintf(DBG_NOTICE, fmt, ap);
280 va_end(ap);
281
282 va_start(ap, fmt);
283 dbg_fmt_vprintf(DBG_NOTICE, fmt, ap);
284 va_end(ap);
285}
286
287
288/**
289 * Print a formatted info message
290 *
291 * @param fmt Formatted string
292 */
293void dbg_info(const char *fmt, ...)
294{
295 va_list ap;
296
297 va_start(ap, fmt);
298 dbg_vprintf(DBG_INFO, fmt, ap);
299 va_end(ap);
300
301 va_start(ap, fmt);
302 dbg_fmt_vprintf(DBG_INFO, fmt, ap);
303 va_end(ap);
304}
305
306
307/**
308 * Get the name of the debug level
309 *
310 * @param level Debug level
311 *
312 * @return String with debug level name
313 */
314const char *dbg_level_str(int level)
315{
316 switch (level) {
317
318 case DBG_EMERG: return "EMERGENCY";
319 case DBG_ALERT: return "ALERT";
320 case DBG_CRIT: return "CRITICAL";
321 case DBG_ERR: return "ERROR";
322 case DBG_WARNING: return "WARNING";
323 case DBG_NOTICE: return "NOTICE";
324 case DBG_INFO: return "INFO";
325 case DBG_DEBUG: return "DEBUG";
326 default: return "???";
327 }
328}