#include "log.h" #include #include #include #include #include "util/sorted_str_set.h" static const char* LOG_LEVEL_STRING_TABLE[] = { "ERROR", "WARN", "INFO", "DEBUG", "TRACE" }; // Maybe add __attribute__((constructor)) in the future if available to skip _config_initialized static bool _user_default_config_initialized = false; static struct log_config_s _user_default_config; static sorted_str_set* _module_configs = NULL; static inline struct log_config_s _default_config() { if (_user_default_config_initialized) { return _user_default_config; } return (struct log_config_s) { .loc_error = LOG_LOC_STDS(stderr), .loc_warn = LOG_LOC_STDS(stderr), .loc_info = LOG_LOC_STDS(stdout), .loc_debug = LOG_LOC_NONE(), .loc_trace = LOG_LOC_NONE(), .timestamp = true, }; } void log_set_default_config(struct log_config_s config) { _user_default_config = config; _user_default_config_initialized = true; } struct log_config_s* log_get_config(const char* module_name) { assert(module_name != NULL); if (!_module_configs) { if (!(_module_configs = sorted_str_set_new(sizeof(struct log_config_s)))) { return NULL; } } struct log_config_s default_conf = _default_config(); return sorted_str_set_insert(_module_configs, module_name, &default_conf); } void log_log(const char* module, enum LOG_LEVEL log_level, const char* fmt, ...) { assert(module != NULL); struct log_config_s* config = log_get_config(module); assert(config); struct log_loc* dest_loc; switch (log_level) { case LOG_ERR: dest_loc = &config->loc_error; break; case LOG_WARN: dest_loc = &config->loc_warn; break; case LOG_INFO: dest_loc = &config->loc_info; break; case LOG_DEBUG: dest_loc = &config->loc_debug; break; case LOG_TRACE: dest_loc = &config->loc_trace; break; default: return; } if (dest_loc->type == LOG_LOC_TYPE_DISABLED) { return; } else if (dest_loc->type == LOG_LOC_TYPE_FS) { if (!dest_loc->location) { if (!(dest_loc->location = fopen(dest_loc->file_name, "a"))) { return; } } } else if (dest_loc->type != LOG_LOC_TYPE_STDS) { return; } FILE* dest = dest_loc->location; va_list varargs; va_start(varargs, fmt); if (config->timestamp) { struct timespec utc_time; struct tm local_time; char time_str_buf[10+1+8+1]; timespec_get(&utc_time, TIME_UTC); localtime_r(&(utc_time.tv_sec), &local_time); if(strftime(time_str_buf, sizeof(time_str_buf), "%F %T", &local_time)) { fprintf(dest, "[%s.%9lu] ", time_str_buf, utc_time.tv_nsec); } } fprintf(dest, "[%s] %s: ", LOG_LEVEL_STRING_TABLE[log_level], module); vfprintf(dest, fmt, varargs); fprintf(dest, "\n"); if (dest_loc->type == LOG_LOC_TYPE_FS && !dest_loc->keep_file_open) { fclose(dest_loc->location); dest_loc->location = NULL; } } void log_log_ssl_err(const char* module, enum LOG_LEVEL log_level, const char* fmt, ...) { assert(module != NULL); struct log_config_s* config = log_get_config(module); assert(config); struct log_loc* dest_loc; switch (log_level) { case LOG_ERR: dest_loc = &config->loc_error; break; case LOG_WARN: dest_loc = &config->loc_warn; break; case LOG_INFO: dest_loc = &config->loc_info; break; case LOG_DEBUG: dest_loc = &config->loc_debug; break; case LOG_TRACE: dest_loc = &config->loc_trace; break; default: return; } if (dest_loc->type == LOG_LOC_TYPE_DISABLED) { return; } else if (dest_loc->type == LOG_LOC_TYPE_FS) { if (!dest_loc->location) { if (!(dest_loc->location = fopen(dest_loc->file_name, "a"))) { return; } } } else if (dest_loc->type != LOG_LOC_TYPE_STDS) { return; } FILE* dest = dest_loc->location; va_list varargs; va_start(varargs, fmt); if (config->timestamp) { struct timespec utc_time; struct tm local_time; char time_str_buf[10+1+8+1]; timespec_get(&utc_time, TIME_UTC); localtime_r(&(utc_time.tv_sec), &local_time); if(strftime(time_str_buf, sizeof(time_str_buf), "%F %T", &local_time)) { fprintf(dest, "[%s.%9lu] ", time_str_buf, utc_time.tv_nsec); } } fprintf(dest, "[%s] %s: ", LOG_LEVEL_STRING_TABLE[log_level], module); vfprintf(dest, fmt, varargs); fprintf(dest, "\n"); ERR_print_errors_fp(dest); if (dest_loc->type == LOG_LOC_TYPE_FS && !dest_loc->keep_file_open) { fclose(dest_loc->location); dest_loc->location = NULL; } }