terom@0: #include "log.h" terom@0: terom@0: #include terom@0: #include terom@0: #include terom@0: #include terom@0: #include terom@0: terom@0: /** terom@0: * The global log level terom@0: */ terom@0: static enum log_level _log_level = LOG_LEVEL_DEFAULT; terom@0: terom@0: /** terom@0: * List of log level names terom@0: */ terom@0: const char *log_level_names[] = { terom@0: "DEBUG", terom@0: "INFO", terom@0: "WARN", terom@0: "ERROR", terom@0: "FATAL", terom@0: NULL terom@0: }; terom@0: terom@0: #define _LOG_LEVEL_NAME(ll) case LOG_ ## ll: return #ll; terom@0: const char *log_level_name (enum log_level level) terom@0: { terom@0: switch (level) { terom@0: _LOG_LEVEL_NAME(DEBUG) terom@0: _LOG_LEVEL_NAME(INFO) terom@0: _LOG_LEVEL_NAME(WARN) terom@0: _LOG_LEVEL_NAME(ERROR) terom@0: _LOG_LEVEL_NAME(FATAL) terom@0: default: return "???"; terom@0: } terom@0: } terom@0: #undef _LOG_LEVEL_NAME terom@0: terom@0: void set_log_level (enum log_level level) terom@0: { terom@0: // meep meep terom@0: _log_level = level; terom@0: } terom@0: terom@0: size_t str_append_fmt_va (char *buf_ptr, size_t *buf_size, const char *fmt, va_list args) terom@0: { terom@62: int ret = 0; terom@0: terom@0: if (*buf_size && (ret = vsnprintf(buf_ptr, *buf_size, fmt, args)) < 0) terom@0: return 0; terom@0: terom@0: if (ret > *buf_size) terom@0: *buf_size = 0; terom@0: terom@0: else terom@0: *buf_size -= ret; terom@0: terom@0: return ret; terom@0: } terom@0: terom@0: size_t str_append_fmt (char *buf_ptr, size_t *buf_size, const char *fmt, ...) terom@0: { terom@0: va_list vargs; terom@0: size_t ret; terom@0: terom@0: va_start(vargs, fmt); terom@0: ret = str_append_fmt_va(buf_ptr, buf_size, fmt, vargs); terom@0: va_end(vargs); terom@0: terom@0: return ret; terom@0: } terom@0: terom@0: void log_output_tag_va (enum log_level level, const char *tag, const char *func, const char *user_fmt, va_list user_fmtargs, const char *log_fmt, va_list log_fmtargs) terom@0: { terom@0: char buf[LOG_MSG_MAX], *buf_ptr = buf; terom@0: size_t buf_size = sizeof(buf); terom@0: terom@0: // filter out? terom@0: if (level < _log_level) terom@0: return; terom@0: terom@0: buf_ptr += str_append_fmt(buf_ptr, &buf_size, "[%5s] %20s : ", tag, func); terom@0: terom@0: // output the user data terom@0: if (user_fmt) terom@0: buf_ptr += str_append_fmt_va(buf_ptr, &buf_size, user_fmt, user_fmtargs); terom@0: terom@0: // output the suffix terom@0: if (log_fmt) terom@0: buf_ptr += str_append_fmt_va(buf_ptr, &buf_size, log_fmt, log_fmtargs); terom@0: terom@0: // display terom@0: // XXX: handle SIGINTR? terom@0: fprintf(stderr, "%s\n", buf); terom@0: } terom@0: terom@0: void log_output_tag (enum log_level level, const char *tag, const char *func, const char *user_fmt, va_list user_fmtargs, const char *log_fmt, ...) terom@0: { terom@0: va_list vargs; terom@0: terom@0: va_start(vargs, log_fmt); terom@0: log_output_tag_va(level, tag, func, user_fmt, user_fmtargs, log_fmt, vargs); terom@0: va_end(vargs); terom@0: } terom@0: terom@0: void _log_msg (enum log_level level, const char *func, const char *format, ...) terom@0: { terom@0: va_list vargs; terom@0: terom@0: // formatted output: no suffix terom@0: va_start(vargs, format); terom@0: log_output_tag(level, log_level_name(level), func, format, vargs, NULL); terom@0: va_end(vargs); terom@0: } terom@0: terom@0: void _log_msg_va2 (enum log_level level, const char *func, const char *fmt1, va_list fmtargs1, const char *fmt2, va_list fmtargs2) terom@0: { terom@0: log_output_tag_va(level, log_level_name(level), func, fmt1, fmtargs1, fmt2, fmtargs2); terom@0: } terom@0: terom@0: void _log_errno (enum log_level level, const char *func, const char *format, ...) terom@0: { terom@0: va_list vargs; terom@0: terom@0: // formatted output: suffix strerror() terom@0: va_start(vargs, format); terom@0: log_output_tag(level, log_level_name(level), func, format, vargs, ": %s", strerror(errno)); terom@0: va_end(vargs); terom@0: } terom@0: terom@0: void _log_exit (enum log_level level, int exit_code, const char *func, const char *format, ...) terom@0: { terom@0: va_list vargs; terom@0: terom@0: // formatted output without any suffix terom@0: va_start(vargs, format); terom@0: log_output_tag(level, "EXIT", func, format, vargs, NULL); terom@0: va_end(vargs); terom@0: terom@0: // exit terom@0: exit(exit_code); terom@0: } terom@0: