177 lines
4.3 KiB
C
177 lines
4.3 KiB
C
#include "log.h"
|
|
|
|
#include <assert.h>
|
|
#include <stdarg.h>
|
|
#include <time.h>
|
|
|
|
#include <openssl/err.h>
|
|
|
|
#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;
|
|
}
|
|
|
|
}
|