diff --git a/lnm/include/lnm/log.h b/lnm/include/lnm/log.h new file mode 100644 index 0000000..42f27de --- /dev/null +++ b/lnm/include/lnm/log.h @@ -0,0 +1,47 @@ +#ifndef LNM_LOG +#define LOG + +#include + +#include "lnm/common.h" + +typedef struct lnm_logger lnm_logger; + +typedef enum lnm_log_level { + lnm_log_level_debug = 0, + lnm_log_level_info, + lnm_log_level_notice, + lnm_log_level_warning, + lnm_log_level_error, + lnm_log_level_critical +} lnm_log_level; + +extern const char *lnm_log_level_names[]; + +/** + * Initialize the global logger. + */ +lnm_err lnm_log_init_global(); + +/** + * Register stdout as one of the streams for the global logger. + */ +lnm_err lnm_log_register_stdout(lnm_log_level level); + +void lnm_log(lnm_log_level level, const char *section, const char *fmt, ...) + __attribute__((format(printf, 3, 4))); + +#define lnm_ldebug(section, fmt, ...) \ + lnm_log(lnm_log_level_debug, section, fmt, __VA_ARGS__) +#define lnm_linfo(section, fmt, ...) \ + lnm_log(lnm_log_level_info, section, fmt, __VA_ARGS__) +#define lnm_lnotice(section, fmt, ...) \ + lnm_log(lnm_log_level_notice, section, fmt, __VA_ARGS__) +#define lnm_lwarning(section, fmt, ...) \ + lnm_log(lnm_log_level_warning, section, fmt, __VA_ARGS__) +#define lnm_lerror(section, fmt, ...) \ + lnm_log(lnm_log_level_error, section, fmt, __VA_ARGS__) +#define lnm_lcritical(section, fmt, ...) \ + lnm_log(lnm_log_level_critical, section, fmt, __VA_ARGS__) + +#endif diff --git a/lnm/src/_include/lnm/log_internal.h b/lnm/src/_include/lnm/log_internal.h new file mode 100644 index 0000000..ebcd243 --- /dev/null +++ b/lnm/src/_include/lnm/log_internal.h @@ -0,0 +1,26 @@ +#ifndef LNM_LOG_INTERNAL +#define LNM_LOG_INTERNAL + +#include "lnm/log.h" + +typedef enum lnm_logger_stream_type { + lnm_logger_stream_type_file = 0 +} lnm_logger_stream_type; + +typedef struct lnm_logger_stream { + void *ptr; + lnm_logger_stream_type type; + lnm_log_level level; +} lnm_logger_stream; + +struct lnm_logger { + struct { + lnm_logger_stream **arr; + size_t len; + } streams; +}; + +lnm_err lnm_logger_stream_register(lnm_logger *logger, + lnm_logger_stream *stream); + +#endif diff --git a/lnm/src/lnm_log.c b/lnm/src/lnm_log.c new file mode 100644 index 0000000..15fb00f --- /dev/null +++ b/lnm/src/lnm_log.c @@ -0,0 +1,86 @@ +#include +#include + +#include "lnm/common.h" +#include "lnm/log_internal.h" + +const char *lnm_log_level_names[] = {"DEBUG ", "INFO ", "NOTICE ", + "WARNING ", "ERROR ", "CRITICAL"}; + +lnm_logger *global_logger = NULL; + +lnm_err lnm_log_init_global() { + global_logger = calloc(1, sizeof(lnm_logger)); + + return global_logger == NULL ? lnm_err_failed_alloc : lnm_err_ok; +} + +lnm_err lnm_logger_stream_register(lnm_logger *logger, + lnm_logger_stream *stream) { + lnm_logger_stream **new = + logger->streams.len == 0 + ? malloc(sizeof(lnm_logger_stream *)) + : realloc(logger->streams.arr, + (logger->streams.len + 1) * sizeof(lnm_logger_stream *)); + + if (new == NULL) { + return lnm_err_failed_alloc; + } + + new[logger->streams.len] = stream; + logger->streams.arr = new; + logger->streams.len++; + + return lnm_err_ok; +} + +lnm_err lnm_log_register_stdout(lnm_log_level level) { + lnm_logger_stream *stream = malloc(sizeof(lnm_logger_stream)); + + if (stream == NULL) { + return lnm_err_failed_alloc; + } + + stream->type = lnm_logger_stream_type_file; + stream->ptr = stdout; + stream->level = level; + + LNM_RES2(lnm_logger_stream_register(global_logger, stream), free(stream)); + + return lnm_err_ok; +} + +void lnm_vlog(lnm_log_level level, const char *section, const char *fmt, + va_list ap) { + char date_str[32]; + + time_t now = time(NULL); + strftime(date_str, sizeof(date_str) - 1, "%Y-%m-%d %H:%M:%S", + localtime(&now)); + + for (size_t i = 0; i < global_logger->streams.len; i++) { + lnm_logger_stream *stream = global_logger->streams.arr[i]; + + if (level < stream->level) { + continue; + } + + switch (stream->type) { + case lnm_logger_stream_type_file: + fprintf(stream->ptr, "[%s][%s][%s] ", date_str, + lnm_log_level_names[level], section); + vfprintf(stream->ptr, fmt, ap); + fprintf(stream->ptr, "\n"); + break; + } + + va_end(ap); + } +} + +void lnm_log(lnm_log_level level, const char *section, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + lnm_vlog(level, section, fmt, ap); + va_end(ap); +} diff --git a/src/main.c b/src/main.c index 4970d95..d25aec3 100644 --- a/src/main.c +++ b/src/main.c @@ -3,6 +3,7 @@ #include #include "lnm/http/loop.h" +#include "lnm/log.h" #include "lander.h" #include "log.h" @@ -61,7 +62,8 @@ lnm_http_loop *loop_init(lander_gctx *gctx, const char *api_key) { #define ENV(var, env_var) \ const char *var = getenv(env_var); \ if (var == NULL) { \ - critical(1, "Missing environment variable %s", env_var); \ + lnm_lcritical("main", "Missing environment variable %s", env_var); \ + exit(1); \ } #define ENV_OPT(var, env_var, default) \ @@ -71,9 +73,11 @@ lnm_http_loop *loop_init(lander_gctx *gctx, const char *api_key) { } int main() { - setvbuf(stdout, NULL, _IONBF, 0); srand(time(NULL)); + lnm_log_init_global(); + lnm_log_register_stdout(lnm_log_level_debug); + ENV(api_key, "LANDER_API_KEY"); ENV_OPT(port_str, "LANDER_PORT", "18080"); ENV_OPT(data_dir_s, "LANDER_DATA_DIR", "."); @@ -81,7 +85,8 @@ int main() { int port = atoi(port_str); if (port <= 0 || port >= 1 << 16) { - critical(1, "Invalid TCP port %s", port_str); + lnm_lcritical("main", "Invalid TCP port %s", port_str); + exit(1); } lander_gctx *c_gctx = lander_gctx_init(); @@ -90,13 +95,14 @@ int main() { lsm_str *data_dir; lsm_str_init_copy(&data_dir, (char *)data_dir_s); - info("Initializing store from path '%s'", data_dir_s); + lnm_linfo("main", "Initializing store from path '%s'", data_dir_s); if (lsm_store_load(&c_gctx->store, data_dir) != lsm_error_ok) { - critical(2, "Failed to load existing store."); + lnm_lcritical("main", "%s", "Failed to load existing store."); } - info("Store loaded containing %lu entries", lsm_store_size(c_gctx->store)); + lnm_linfo("main", "Store loaded containing %lu entries", + lsm_store_size(c_gctx->store)); lnm_http_loop *hl = loop_init(c_gctx, api_key); lnm_http_loop_run(hl, port);