// Trace messages #include #include #include #include #include #include #include static _Atomic enum trace_level _t_level = _TRACE_LEVEL_DEFAULT; const char* const _TRACE_CONTROL_ENV_NAME = "LOG_LEVEL"; const struct {const char* const name; const enum trace_level level; } _trace_level_names[] = { #define X(name) { #name, TRACE_LEVEL_ ## name } #define Y(name, val) { #name, TRACE_LEVEL_ ## val } X(DEBUG), Y(TRACE, DEBUG), X(INFO), X(WARN), X(ERROR), X(FATAL), #undef Y #undef X }; #define _trace_level_names_n (sizeof(_trace_level_names) / sizeof(_trace_level_names[0])) const char* const _trace_level_descriptions[_TRACE_LEVEL_NUM] = { "All trace messages regarding internals, only useful for debugging", "Information messages regarding processes, recommended level", "Only show warnings", "Only show errors", "Only show fatal (aborting) errors", }; static bool _trace_lookup(const char*pIN name, enum trace_level *pOUT olevel) { debug_assert(name); for(usize i=0;i<_trace_level_names_n;i++) { let level = &_trace_level_names[i]; debug_assert(level && level->name); if(strcmp(name, level->name) == 0) { *olevel =level->level; return true; } } return false; } static bool _trace_reverse_lookup(enum trace_level level, const char* *pOUT name) { for(usize i=0;i<_trace_level_names_n;i++) { let lv = &_trace_level_names[i]; debug_assert(lv && lv->name); if(lv->level == level) { *name = lv->name; return true; } } return false; } const char* trace_name_of(enum trace_level lv) { const char* ret; if(!_trace_reverse_lookup(lv, &ret)) return NULL; else return ret; } inline enum trace_level trace_max_level() { return _t_level; } inline static bool _trace_hidden(enum trace_level l) { return l < trace_max_level(); } int _t_fprintf(enum trace_level l, FILE* output, const char* msg, ...) { if(_trace_hidden(l)) return 0; va_list ap; va_start(ap, msg); register int r = vfprintf(output, msg, ap); va_end(ap); return r; } void trace_init_with(enum trace_level max_level) { _t_level = max_level; } static inline bool _try_get_env(const char* name, const char* *pOUT value) { return !!(*value = (const char*)getenv(name)); } int trace_init() { const char* eval; if(!_try_get_env(_TRACE_CONTROL_ENV_NAME, &eval)) return 1; else { assert(eval); if(*eval == 0) return 1; // Count empty string as default. enum trace_level level; if(!_trace_lookup(eval, &level)) return 0; else { trace_init_with(level); } } return 1; }