#ifndef LOG_H #define LOG_H #include "string.h" #include "sys.h" #define LOG_LEVEL(l) (l <= LOG_LEVEL_COMPTIME) /* Log level configuration */ #ifndef LOG_LEVEL_COMPTIME # if RTC || PROFILING # define LOG_LEVEL_COMPTIME LOG_LEVEL_DEBUG # else # define LOG_LEVEL_COMPTIME LOG_LEVEL_INFO # endif #endif /* Source location configuration */ #ifndef LOG_INCLUDE_SOURCE_LOCATION # define LOG_INCLUDE_SOURCE_LOCATION (DEBINFO) #endif #define LOG_LEVEL_NONE -1 #define LOG_LEVEL_CRITICAL 0 #define LOG_LEVEL_ERROR 1 #define LOG_LEVEL_WARNING 2 #define LOG_LEVEL_SUCCESS 3 #define LOG_LEVEL_INFO 4 #define LOG_LEVEL_DEBUG 5 #define LOG_LEVEL_COUNT 6 /* ========================== * * Callback interface * ========================== */ struct log_level_settings { struct string shorthand; u32 color; }; struct log_event { /* Msg lifetime is only as long as callback duration */ struct string msg; i32 level; struct sys_datetime datetime; i64 time_ns; /* These will be nulled if LOG_INCLUDE_SOURCE_LOCATION is disabled */ struct string file; i32 line; }; #define LOG_EVENT_CALLBACK_FUNC_DEF(name, log_event_arg) void name(struct log_event log_event_arg) typedef LOG_EVENT_CALLBACK_FUNC_DEF(log_event_callback_func, log_event); void log_register_callback(log_event_callback_func *func, i32 level); /* ========================== * * Logging macros * ========================== */ #define log_panic(msg) _log_panic(msg) #if LOG_LEVEL(LOG_LEVEL_CRITICAL) # if LOG_INCLUDE_SOURCE_LOCATION # define log_critical(msg) _log(LOG_LEVEL_CRITICAL, LIT(__FILE__), __LINE__, msg) # define logf_critical(fmt_lit, ...) _logf(LOG_LEVEL_CRITICAL, LIT(__FILE__), __LINE__, LIT(fmt_lit) , ## __VA_ARGS__, FMT_END) # else # define log_critical(msg) _log(LOG_LEVEL_CRITICAL, msg) # define logf_critical(fmt_lit, ...) _logf(LOG_LEVEL_CRITICAL, LIT(fmt_lit) , ## __VA_ARGS__, FMT_END) # endif #else # define log_critical(msg) # define logf_critical(fmt_lit, ...) #endif #if LOG_LEVEL(LOG_LEVEL_ERROR) # if LOG_INCLUDE_SOURCE_LOCATION # define log_error(msg) _log(LOG_LEVEL_ERROR, LIT(__FILE__), __LINE__, msg) # define logf_error(fmt_lit, ...) _logf(LOG_LEVEL_ERROR, LIT(__FILE__), __LINE__, LIT(fmt_lit) , ## __VA_ARGS__, FMT_END) # else # define log_error(msg) _log(LOG_LEVEL_ERROR, msg) # define logf_error(fmt_lit, ...) _logf(LOG_LEVEL_ERROR, LIT(fmt_lit) , ## __VA_ARGS__, FMT_END) # endif #else # define log_error(msg) # define logf_error(fmt_lit, ...) #endif #if LOG_LEVEL(LOG_LEVEL_WARNING) # if LOG_INCLUDE_SOURCE_LOCATION # define log_warning(msg) _log(LOG_LEVEL_WARNING, LIT(__FILE__), __LINE__, msg) # define logf_warning(fmt_lit, ...) _logf(LOG_LEVEL_WARNING, LIT(__FILE__), __LINE__, LIT(fmt_lit) , ## __VA_ARGS__, FMT_END) # else # define log_warning(msg) _log(LOG_LEVEL_WARNING, msg) # define logf_warning(fmt_lit, ...) _logf(LOG_LEVEL_WARNING, LIT(fmt_lit) , ## __VA_ARGS__, FMT_END) # endif #else # define log_warning(msg) # define logf_warning(fmt_lit, ...) #endif #if LOG_LEVEL(LOG_LEVEL_SUCCESS) # if LOG_INCLUDE_SOURCE_LOCATION # define log_success(msg) _log(LOG_LEVEL_SUCCESS, LIT(__FILE__), __LINE__, msg) # define logf_success(fmt_lit, ...) _logf(LOG_LEVEL_SUCCESS, LIT(__FILE__), __LINE__, LIT(fmt_lit) , ## __VA_ARGS__, FMT_END) # else # define log_success(msg) _log(LOG_LEVEL_SUCCESS, msg) # define logf_success(fmt_lit, ...) _logf(LOG_LEVEL_SUCCESS, LIT(fmt_lit) , ## __VA_ARGS__, FMT_END) # endif #else # define log_success(msg) # define logf_success(fmt_lit, ...) #endif #if LOG_LEVEL(LOG_LEVEL_INFO) # if LOG_INCLUDE_SOURCE_LOCATION # define log_info(msg) _log(LOG_LEVEL_INFO, LIT(__FILE__), __LINE__, msg) # define logf_info(fmt_lit, ...) _logf(LOG_LEVEL_INFO, LIT(__FILE__), __LINE__, LIT(fmt_lit) , ## __VA_ARGS__, FMT_END) # else # define log_info(msg) _log(LOG_LEVEL_INFO, msg) # define logf_info(fmt_lit, ...) _logf(LOG_LEVEL_INFO, LIT(fmt_lit) , ## __VA_ARGS__, FMT_END) # endif #else # define log_info(msg) # define logf_info(fmt_lit, ...) #endif #if LOG_LEVEL(LOG_LEVEL_DEBUG) # if LOG_INCLUDE_SOURCE_LOCATION # define log_debug(msg) _log(LOG_LEVEL_DEBUG, LIT(__FILE__), __LINE__, msg) # define logf_debug(fmt_lit, ...) _logf(LOG_LEVEL_DEBUG, LIT(__FILE__), __LINE__, LIT(fmt_lit) , ## __VA_ARGS__, FMT_END) # else # define log_debug(msg) _log(LOG_LEVEL_DEBUG, msg) # define logf_debug(fmt_lit, ...) _logf(LOG_LEVEL_DEBUG, LIT(fmt_lit) , ## __VA_ARGS__, FMT_END) # endif #else # define log_debug(msg) # define logf_debug(fmt_lit, ...) #endif /* ========================== * * Function declarations * ========================== */ void log_startup(struct string logfile_path); void _log_panic(struct string msg); #if LOG_INCLUDE_SOURCE_LOCATION void _log(i32 level, struct string file, u32 line, struct string msg); #else void _log(i32 level, struct string msg); #endif #if LOG_INCLUDE_SOURCE_LOCATION void _logfv(i32 level, struct string file, u32 line, struct string fmt, va_list args); #else void _logfv(i32 level, struct string fmt, va_list args); #endif #if LOG_INCLUDE_SOURCE_LOCATION void _logf(i32 level, struct string file, u32 line, struct string fmt, ...); #else void _logf(i32 level, struct string fmt, ...); #endif #endif