usb_moded  0.86.0+mer57
usb_moded-log.c
Go to the documentation of this file.
1 
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 
48 static char *log_strip (char *str);
49 static void log_gettime (struct timeval *tv);
50 void log_emit_va (const char *file, const char *func, int line, int lev, const char *fmt, va_list va);
51 void log_emit_real (const char *file, const char *func, int line, int lev, const char *fmt, ...);
52 void log_debugf (const char *fmt, ...);
53 int log_get_level (void);
54 void log_set_level (int lev);
55 bool log_p (int lev);
56 int log_get_type (void);
57 void log_set_type (int type);
58 const char *log_get_name (void);
59 void log_set_name (const char *name);
60 void log_set_lineinfo(bool lineinfo);
61 bool log_get_lineinfo(void);
62 void log_init (void);
63 
64 /* ========================================================================= *
65  * Data
66  * ========================================================================= */
67 
68 static const char *log_name = "<unset>";
69 static int log_level = LOG_WARNING;
70 static int log_type = LOG_TO_STDERR;
71 static bool log_lineinfo = false;
72 static struct timeval log_begtime = { 0, 0 };
73 
74 /* ========================================================================= *
75  * CONTEXT STACK
76  * ========================================================================= */
77 
78 #if LOG_ENABLE_CONTEXT
79 typedef struct context_entry_t
80 {
81  const char *func;
82  bool done;
83 } context_entry_t;
84 
85 typedef struct context_stack_t
86 {
87  context_entry_t stk[256];
88  int sp;
89  int id;
90 } context_stack_t;
91 
92 static int context_count = 0;
93 static __thread context_stack_t *context_stack = 0;
94 
95 static bool log_entry = false;
96 static bool log_leave = false;
97 
98 static void
99 context_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 
121 static void
122 context_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 
139 const char *
140 context_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 
157 void
158 context_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 
177 static 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 
195 static void log_gettime(struct timeval *tv)
196 {
197  gettimeofday(tv, 0);
198  timersub(tv, &log_begtime, tv);
199 }
200 
210 void 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 
303 void 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 
311 void 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 
327 int log_get_level(void)
328 {
329  return log_level;
330 }
331 
336 void log_set_level(int lev)
337 {
338  log_level = lev;
339 }
340 
347 bool log_p(int lev)
348 {
349  return lev <= log_level;
350 }
351 
356 int log_get_type(void)
357 {
358  return log_type;
359 }
360 
361 /* Set the logging type
362  *
363  * @param type The wanted logging type
364  */
365 void log_set_type(int type)
366 {
367  log_type = type;
368 }
369 
374 const char *log_get_name(void)
375 {
376  return log_name;
377 }
378 
383 void log_set_name(const char *name)
384 {
385  log_name = name;
386 }
387 
392 void log_set_lineinfo(bool lineinfo)
393 {
394  log_lineinfo = lineinfo;
395 }
396 
402 {
403  return log_lineinfo;
404 }
405 
407 void log_init(void)
408 {
409  /* Get reference time used for verbose logging */
410  if( !timerisset(&log_begtime) )
411  gettimeofday(&log_begtime, 0);
412 }
log_get_name
const char * log_get_name(void)
Definition: usb_moded-log.c:374
log_init
void log_init(void)
Definition: usb_moded-log.c:407
log_get_type
int log_get_type(void)
Definition: usb_moded-log.c:356
log_set_level
void log_set_level(int lev)
Definition: usb_moded-log.c:336
log_get_lineinfo
bool log_get_lineinfo(void)
Definition: usb_moded-log.c:401
usb_moded-log.h
log_set_name
void log_set_name(const char *name)
Definition: usb_moded-log.c:383
log_emit_real
void log_emit_real(const char *file, const char *func, int line, int lev, const char *fmt,...)
Definition: usb_moded-log.c:303
log_p
bool log_p(int lev)
Definition: usb_moded-log.c:347
log_get_level
int log_get_level(void)
Definition: usb_moded-log.c:327
log_emit_va
void log_emit_va(const char *file, const char *func, int line, int lev, const char *fmt, va_list va)
Definition: usb_moded-log.c:210
log_set_lineinfo
void log_set_lineinfo(bool lineinfo)
Definition: usb_moded-log.c:392