#include #include #include #include #include #include #include #include #include #include "logerr.h" #include "trace.h" static pthread_key_t LEVEL_KEY; static pthread_key_t STREAM_KEY; static pthread_once_t ONCE = PTHREAD_ONCE_INIT; static void init(void) { assert(pthread_key_create(&LEVEL_KEY, NULL) == 0); assert(pthread_key_create(&STREAM_KEY, NULL) == 0); assert(pthread_setspecific(LEVEL_KEY, (void *)TraceLevel_INFO) == 0); assert(pthread_setspecific(LEVEL_KEY, stderr) == 0); } void vftracef( const char *const file, const char *const function, const int lineno, FILE *restrict stream, const enum TraceLevel level, const char *restrict format, va_list args ) { assert(pthread_once(&ONCE, init) == 0); const enum TraceLevel current_level = (enum TraceLevel)(intptr_t)pthread_getspecific(LEVEL_KEY); if (level > current_level) { return; } if (fprintf(stream, "%s:%s:%d: ", file, function, lineno) < 0) { logerr("fprintf() < 0: %s", strerror(errno)); } if (vfprintf(stream, format, args) < 0) { perror(__FILE__ ":vtrace(): vfprintf() < 0"); } if (fprintf(stream, "\n") < 0) { perror(__FILE__ ":vtrace(): fprintf() < 0"); } } void ftracef( const char *const file, const char *const function, const int lineno, FILE *restrict stream, const enum TraceLevel level, const char *restrict format, ... ) { va_list args; va_start(args, format); vftracef(file, function, lineno, stream, level, format, args); va_end(args); } void tracef( const char *const file, const char *const function, const int lineno, const enum TraceLevel level, const char *restrict format, ... ) { assert(pthread_once(&ONCE, init) == 0); va_list args; va_start(args, format); vftracef(file, function, lineno, pthread_getspecific(STREAM_KEY), level, format, args); va_end(args); } int trace_set_stream(FILE *stream) { return pthread_setspecific(STREAM_KEY, stream); } int trace_set_level(const enum TraceLevel level) { assert(level >= TraceLevel_NONE); assert(level <= TraceLevel_DEBUG); return pthread_setspecific(LEVEL_KEY, (void *)(intptr_t)level); }