usb_moded 0.86.0+mer64
usb_moded-log.c
Go to the documentation of this file.
1
28
29#include "usb_moded-log.h"
30
31#include <sys/time.h>
32
33#include <stdio.h>
34#include <errno.h>
35
36#if LOG_ENABLE_CONTEXT
37# include <assert.h> // NOTRIM
38#endif
39
40/* ========================================================================= *
41 * Prototypes
42 * ========================================================================= */
43
44/* ------------------------------------------------------------------------- *
45 * LOG
46 * ------------------------------------------------------------------------- */
47
48static char *log_strip (char *str);
49static void log_gettime (struct timeval *tv);
50void log_emit_va (const char *file, const char *func, int line, int lev, const char *fmt, va_list va);
51void log_emit_real (const char *file, const char *func, int line, int lev, const char *fmt, ...);
52void log_debugf (const char *fmt, ...);
53int log_get_level (void);
54void log_set_level (int lev);
55bool log_p (int lev);
56int log_get_type (void);
57void log_set_type (int type);
58const char *log_get_name (void);
59void log_set_name (const char *name);
60void log_set_lineinfo(bool lineinfo);
61bool log_get_lineinfo(void);
62void log_init (void);
63
64/* ========================================================================= *
65 * Data
66 * ========================================================================= */
67
68static const char *log_name = "<unset>";
69static int log_level = LOG_WARNING;
70static int log_type = LOG_TO_STDERR;
71static bool log_lineinfo = false;
72static struct timeval log_begtime = { 0, 0 };
73
74/* ========================================================================= *
75 * CONTEXT STACK
76 * ========================================================================= */
77
78#if LOG_ENABLE_CONTEXT
79typedef struct context_entry_t
80{
81 const char *func;
82 bool done;
83} context_entry_t;
84
85typedef struct context_stack_t
86{
87 context_entry_t stk[256];
88 int sp;
89 int id;
90} context_stack_t;
91
92static int context_count = 0;
93static __thread context_stack_t *context_stack = 0;
94
95static bool log_entry = false;
96static bool log_leave = false;
97
98static void
99context_write(int tab, const char *msg)
100{
101 int tag = 0;
102 if( context_stack ) {
103 tag = context_stack->id;
104 if( tab < 0 && context_stack->sp > 0 )
105 tab = context_stack->sp;
106 }
107 tab = (tab <= 0) ? 0 : (tab * 4);
108 char *txt = 0;
109 int len = asprintf(&txt, "T%d %*s%s\n",
110 tag,
111 tab, "",
112 msg);
113 if( len > 0 ) {
114 if( write(STDERR_FILENO, txt, len) == - 1 ) {
115 // this is debug logging - do not really care
116 }
117 free(txt);
118 }
119}
120
121static void
122context_flush(void)
123{
124 for( int i = 0; i < context_stack->sp; ++i ) {
125 char msg[256];
126 if( context_stack->stk[i].done )
127 continue;
128 context_stack->stk[i].done = true;
129 if( log_leave )
130 snprintf(msg, sizeof msg, "%s() { ...",
131 context_stack->stk[i].func);
132 else
133 snprintf(msg, sizeof msg, "%s()",
134 context_stack->stk[i].func);
135 context_write(i, msg);
136 }
137}
138
139const char *
140context_enter(const char *func)
141{
142 if( !context_stack ) {
143 context_stack = calloc(1, sizeof *context_stack);
144 context_stack->id = ++context_count;
145 }
146
147 context_stack->stk[context_stack->sp].func = func;
148 context_stack->stk[context_stack->sp].done = false;
149 context_stack->sp += 1;
150
151 if( log_entry )
152 context_flush();
153
154 return func;
155}
156
157void
158context_leave(void *aptr)
159{
160 const char *func = *(const char **)aptr;
161 assert( context_stack->sp > 0 );
162 context_stack->sp -= 1;
163
164 if( log_leave && context_stack->stk[context_stack->sp].done ) {
165 char msg[256];
166 snprintf(msg, sizeof msg, "} %s()", func);
167 context_write(-1, msg);
168 }
169 assert( context_stack->stk[context_stack->sp].func == func );
170}
171#endif // LOG_ENABLE_CONTEXT
172
173/* ========================================================================= *
174 * Functions
175 * ========================================================================= */
176
177static char *log_strip(char *str)
178{
179 unsigned char *src = (unsigned char *)str;
180 unsigned char *dst = (unsigned char *)str;
181
182 while( *src > 0 && *src <= 32 ) ++src;
183
184 for( ;; )
185 {
186 while( *src > 32 ) *dst++ = *src++;
187 while( *src > 0 && *src <= 32 ) ++src;
188 if( *src == 0 ) break;
189 *dst++ = ' ';
190 }
191 *dst = 0;
192 return str;
193}
194
195static void log_gettime(struct timeval *tv)
196{
197 gettimeofday(tv, 0);
198 timersub(tv, &log_begtime, tv);
199}
200
210void log_emit_va(const char *file, const char *func, int line, int lev, const char *fmt, va_list va)
211{
212 int saved = errno;
213 char lineinfo[128] = "";
214 char timeinfo[32] = "";
215 char levelinfo[8] = "";
216 if( log_p(lev) )
217 {
218 switch( log_type )
219 {
220 case LOG_TO_SYSLOG:
221
222 vsyslog(lev, fmt, va);
223 break;
224
225 case LOG_TO_STDERR:
226
227 if( log_get_lineinfo() ) {
228 /* Use gcc error like prefix for logging so
229 * that logs can be analyzed with jump to
230 * line parsing available in editors. */
231 snprintf(lineinfo, sizeof lineinfo,
232 "%s:%d: %s(): ", file, line, func);
233 }
234 else {
235 snprintf(lineinfo, sizeof lineinfo,
236 "%s: ", log_get_name());
237 }
238
239#if LOG_ENABLE_TIMESTAMPS
240 {
241 struct timeval tv;
242 log_gettime(&tv);
243 snprintf(timeinfo, sizeof timeinfo,
244 "%3ld.%03ld ",
245 (long)tv.tv_sec,
246 (long)tv.tv_usec/1000);
247 }
248#endif
249
250#if LOG_ENABLE_LEVELTAGS
251 {
252 static const char *tag = "U:";
253 switch( lev )
254 {
255 case LOG_CRIT: tag = "C:"; break;
256 case LOG_ERR: tag = "E:"; break;
257 case LOG_WARNING: tag = "W:"; break;
258 case LOG_NOTICE: tag = "N:"; break;
259 case LOG_INFO: tag = "I:"; break;
260 case LOG_DEBUG: tag = "D:"; break;
261 }
262 snprintf(levelinfo, sizeof levelinfo,
263 "%s ", tag);
264 }
265#endif
266 {
267 // squeeze whitespace like syslog does
268 char msg[512];
269 errno = saved;
270 vsnprintf(msg, sizeof msg, fmt, va);
271 log_strip(msg);
272#if LOG_ENABLE_CONTEXT
273 char buf[1024];
274 snprintf(buf, sizeof buf, "%s%s%s%s",
275 lineinfo, timeinfo, levelinfo, msg);
276 context_flush();
277 context_write(-1, buf);
278#else
279 fprintf(stderr, "%s%s%s%s\n",
280 lineinfo, timeinfo, levelinfo, msg);
281#endif
282 }
283 fflush(stderr);
284 break;
285
286 default:
287 // no logging
288 break;
289 }
290 }
291 errno = saved;
292}
293
303void log_emit_real(const char *file, const char *func, int line, int lev, const char *fmt, ...)
304{
305 va_list va;
306 va_start(va, fmt);
307 log_emit_va(file, func, line, lev, fmt, va);
308 va_end(va);
309}
310
311void log_debugf(const char *fmt, ...)
312{
313 /* This goes always to stderr */
314 if( log_type == LOG_TO_STDERR && log_p(LOG_DEBUG) )
315 {
316 va_list va;
317 va_start(va, fmt);
318 vfprintf(stderr, fmt, va);
319 va_end(va);
320 }
321}
322
328{
329 return log_level;
330}
331
336void log_set_level(int lev)
337{
338 log_level = lev;
339}
340
347bool log_p(int lev)
348{
349 return lev <= log_level;
350}
351
357{
358 return log_type;
359}
360
361/* Set the logging type
362 *
363 * @param type The wanted logging type
364 */
365void log_set_type(int type)
366{
367 log_type = type;
368}
369
374const char *log_get_name(void)
375{
376 return log_name;
377}
378
383void log_set_name(const char *name)
384{
385 log_name = name;
386}
387
392void log_set_lineinfo(bool lineinfo)
393{
394 log_lineinfo = lineinfo;
395}
396
402{
403 return log_lineinfo;
404}
405
407void log_init(void)
408{
409 /* Get reference time used for verbose logging */
410 if( !timerisset(&log_begtime) )
411 gettimeofday(&log_begtime, 0);
412}
void log_emit_va(const char *file, const char *func, int line, int lev, const char *fmt, va_list va)
int log_get_type(void)
void log_init(void)
bool log_get_lineinfo(void)
void log_emit_real(const char *file, const char *func, int line, int lev, const char *fmt,...)
void log_set_level(int lev)
void log_set_name(const char *name)
int log_get_level(void)
void log_set_lineinfo(bool lineinfo)
const char * log_get_name(void)
bool log_p(int lev)