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, ...);
57void log_set_type (
int type);
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 };
79typedef struct context_entry_t
85typedef struct context_stack_t
87 context_entry_t stk[256];
92static int context_count = 0;
93static __thread context_stack_t *context_stack = 0;
95static bool log_entry =
false;
96static bool log_leave =
false;
99context_write(
int tab,
const char *msg)
102 if( context_stack ) {
103 tag = context_stack->id;
104 if( tab < 0 && context_stack->sp > 0 )
105 tab = context_stack->sp;
107 tab = (tab <= 0) ? 0 : (tab * 4);
109 int len = asprintf(&txt,
"T%d %*s%s\n",
114 if( write(STDERR_FILENO, txt, len) == - 1 ) {
124 for(
int i = 0; i < context_stack->sp; ++i ) {
126 if( context_stack->stk[i].done )
128 context_stack->stk[i].done =
true;
130 snprintf(msg,
sizeof msg,
"%s() { ...",
131 context_stack->stk[i].func);
133 snprintf(msg,
sizeof msg,
"%s()",
134 context_stack->stk[i].func);
135 context_write(i, msg);
140context_enter(
const char *func)
142 if( !context_stack ) {
143 context_stack = calloc(1,
sizeof *context_stack);
144 context_stack->id = ++context_count;
147 context_stack->stk[context_stack->sp].func = func;
148 context_stack->stk[context_stack->sp].done =
false;
149 context_stack->sp += 1;
158context_leave(
void *aptr)
160 const char *func = *(
const char **)aptr;
161 assert( context_stack->sp > 0 );
162 context_stack->sp -= 1;
164 if( log_leave && context_stack->stk[context_stack->sp].done ) {
166 snprintf(msg,
sizeof msg,
"} %s()", func);
167 context_write(-1, msg);
169 assert( context_stack->stk[context_stack->sp].func == func );
177static char *log_strip(
char *str)
179 unsigned char *src = (
unsigned char *)str;
180 unsigned char *dst = (
unsigned char *)str;
182 while( *src > 0 && *src <= 32 ) ++src;
186 while( *src > 32 ) *dst++ = *src++;
187 while( *src > 0 && *src <= 32 ) ++src;
188 if( *src == 0 )
break;
195static void log_gettime(
struct timeval *tv)
198 timersub(tv, &log_begtime, tv);
210void log_emit_va(
const char *file,
const char *func,
int line,
int lev,
const char *fmt, va_list va)
213 char lineinfo[128] =
"";
214 char timeinfo[32] =
"";
215 char levelinfo[8] =
"";
222 vsyslog(lev, fmt, va);
231 snprintf(lineinfo,
sizeof lineinfo,
232 "%s:%d: %s(): ", file, line, func);
235 snprintf(lineinfo,
sizeof lineinfo,
239#if LOG_ENABLE_TIMESTAMPS
243 snprintf(timeinfo,
sizeof timeinfo,
246 (
long)tv.tv_usec/1000);
250#if LOG_ENABLE_LEVELTAGS
252 static const char *tag =
"U:";
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;
262 snprintf(levelinfo,
sizeof levelinfo,
270 vsnprintf(msg,
sizeof msg, fmt, va);
272#if LOG_ENABLE_CONTEXT
274 snprintf(buf,
sizeof buf,
"%s%s%s%s",
275 lineinfo, timeinfo, levelinfo, msg);
277 context_write(-1, buf);
279 fprintf(stderr,
"%s%s%s%s\n",
280 lineinfo, timeinfo, levelinfo, msg);
303void log_emit_real(
const char *file,
const char *func,
int line,
int lev,
const char *fmt, ...)
311void log_debugf(
const char *fmt, ...)
314 if( log_type == LOG_TO_STDERR &&
log_p(LOG_DEBUG) )
318 vfprintf(stderr, fmt, va);
349 return lev <= log_level;
365void log_set_type(
int type)
394 log_lineinfo = lineinfo;
410 if( !timerisset(&log_begtime) )
411 gettimeofday(&log_begtime, 0);
void log_emit_va(const char *file, const char *func, int line, int lev, const char *fmt, va_list va)
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)
void log_set_lineinfo(bool lineinfo)
const char * log_get_name(void)