terom@21: terom@21: #include "log.h" terom@137: #include "str.h" terom@21: terom@21: #include terom@21: #include terom@118: #include terom@21: terom@73: /** terom@137: * The default log output func terom@137: */ terom@137: void log_default_func (const char *line, void *arg) terom@137: { terom@137: (void) arg; terom@137: terom@137: // display terom@137: printf("%s\n", line); terom@137: } terom@137: terom@137: /** terom@73: * The global log level terom@73: */ terom@73: static enum log_level _log_level = LOG_LEVEL_DEFAULT; terom@73: terom@104: /** terom@137: * The global log output func terom@137: */ terom@137: static struct log_output_ctx { terom@137: /** The function itself */ terom@137: log_output_func func; terom@137: terom@137: /** The arg */ terom@137: void *arg; terom@137: } _log_output_ctx = { log_default_func, NULL }; terom@137: terom@137: /** terom@104: * List of log level names terom@104: */ terom@104: const char *log_level_names[] = { terom@104: "DEBUG", terom@104: "INFO", terom@104: "WARN", terom@104: "ERROR", terom@104: "FATAL", terom@104: NULL terom@104: }; terom@104: terom@21: #define _LOG_LEVEL_NAME(ll) case LOG_ ## ll: return #ll; terom@21: const char *log_level_name (enum log_level level) terom@21: { terom@21: switch (level) { terom@21: _LOG_LEVEL_NAME(DEBUG) terom@21: _LOG_LEVEL_NAME(INFO) terom@21: _LOG_LEVEL_NAME(WARN) terom@21: _LOG_LEVEL_NAME(ERROR) terom@21: _LOG_LEVEL_NAME(FATAL) terom@21: default: return "???"; terom@21: } terom@21: } terom@137: #undef _LOG_LEVEL_NAME terom@21: terom@73: void set_log_level (enum log_level level) terom@73: { terom@73: // meep meep terom@73: _log_level = level; terom@73: } terom@73: terom@137: void log_set_func (log_output_func func, void *arg) terom@21: { terom@137: // replace the current one terom@137: _log_output_ctx.func = func ? func : log_default_func; terom@137: _log_output_ctx.arg = arg; terom@137: } terom@137: terom@137: /** terom@137: * Format the full output line, and pass it to the log_output_func. The line will be of the form: terom@137: * "[] : [ ]" terom@137: */ terom@137: static void log_output (enum log_level level, const char *func, const char *user_fmt, va_list user_fmtargs, const char *log_fmt, ...) terom@137: { terom@137: char buf[LOG_MSG_MAX], *buf_ptr = buf; terom@137: size_t buf_size = sizeof(buf); terom@21: terom@73: // filter out? terom@73: if (level < _log_level) terom@73: return; terom@137: terom@137: // output the header terom@137: buf_ptr += str_advance(NULL, &buf_size, str_append_fmt(buf_ptr, buf_size, "[%5s] %20s : ", log_level_name(level), func)); terom@21: terom@137: // output the user data terom@137: buf_ptr += str_advance(NULL, &buf_size, str_append_fmt_va(buf_ptr, buf_size, user_fmt, user_fmtargs)); terom@137: terom@137: // output the suffix terom@137: if (log_fmt) { terom@137: va_list vargs; terom@137: terom@137: va_start(vargs, log_fmt); terom@137: buf_ptr += str_advance(NULL, &buf_size, str_append_fmt_va(buf_ptr, buf_size, log_fmt, vargs)); terom@137: va_end(vargs); terom@137: } terom@137: terom@137: // send it to the output func terom@137: _log_output_ctx.func(buf, _log_output_ctx.arg); terom@137: } terom@137: terom@137: void log_msg (enum log_level level, const char *func, const char *format, ...) terom@137: { terom@137: va_list vargs; terom@137: terom@137: // formatted output: no suffix terom@21: va_start(vargs, format); terom@137: log_output(level, func, format, vargs, NULL); terom@21: va_end(vargs); terom@137: } terom@21: terom@139: void _log_err_code (enum log_level level, err_t err, const char *func, const char *format, ...) terom@137: { terom@137: va_list vargs; terom@137: terom@137: // formatted output: suffix error_name() terom@137: va_start(vargs, format); terom@137: log_output(level, func, format, vargs, ": %s", error_name(err)); terom@137: va_end(vargs); terom@21: } terom@21: terom@139: void _log_err (enum log_level level, struct error_info *err, const char *func, const char *format, ...) terom@21: { terom@21: va_list vargs; terom@21: terom@137: // formatted output: suffix error_msg() terom@21: va_start(vargs, format); terom@137: log_output(level, func, format, vargs, ": %s", error_msg(err)); terom@21: va_end(vargs); terom@21: } terom@118: terom@118: void _log_perr (enum log_level level, const char *func, const char *format, ...) terom@118: { terom@118: va_list vargs; terom@118: terom@137: // formatted output: suffix strerror() terom@118: va_start(vargs, format); terom@137: log_output(level, func, format, vargs, ": %s", strerror(errno)); terom@118: va_end(vargs); terom@118: } terom@118: