轻量级c语言开源日志库log.c介绍 - 实现不同级别和参数化日志打印

前言

  • c语言没有现成的日志库,如果要记录日志,需要自己封装一个日志库。如果要实现日志级别和参数打印,还是比较麻烦的,正好在github找到了一个c语言开源日志库,可以实现日志级别打印,参数打印,而且还会记录日期和行号,最重要的是代码非常少,只有100多行,可以直接包含在我们自己的工程代码中,不需要任何依赖。

源码地址

  • github源码连接

使用介绍

  • 直接把工程目录下的log.c和log.h下载下来,包含到工程代码中即可,没有其他依赖。
  • 日志级别由低到高,分别为 LOG_TRACELOG_DEBUGLOG_INFOLOG_WARNLOG_ERRORLOG_FATAL
  • 如果设置日志级别为LOG_TRACE,则所有级别日志都会打印,如果设置日志级别为LOG_WARN,则只会打印LOG_WARN以及更高级别(即LOG_ERROR和LOG_FATAL)的日志

演示

  • 测试代码
    •   #include "log.h"
        #include 
      
        int main() {
            FILE *fp = fopen("log.txt", "a+");
            if(fp == NULL){
                    printf("create log file failed.\n");
                    return -1;
            }
      
            //设置日志级别(在终端打印)
            log_set_level(LOG_TRACE);
      
            //设置日志级别(在文件中打印)
            log_add_fp(fp, LOG_INFO);
      
      
            log_trace("start trace.");
            log_debug("start debug.");
            log_info("start info.");
            log_warn("start warn.");
            log_error("start error.");
            log_fatal("start fatal");
      
            // 支持参数打印
            log_info("number is %d, string is %s", 10010, "helloword");
      
            fclose(fp);
        }
      
  • 演示效果
    轻量级c语言开源日志库log.c介绍 - 实现不同级别和参数化日志打印_第1张图片

源码

  • 如果访问github有问题,我把源码贴到下面了。
  • log.h
    •   #ifndef LOG_H
        #define LOG_H
      
        #include 
        #include 
        #include 
        #include 
      
        #define LOG_VERSION "0.1.0"
      
        typedef struct {
            va_list ap;
            const char *fmt;
            const char *file;
            struct tm *time;
            void *udata;
            int line;
            int level;
        } log_Event;
      
        typedef void (*log_LogFn)(log_Event *ev);
        typedef void (*log_LockFn)(bool lock, void *udata);
      
        enum { LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL };
      
        #define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__)
        #define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__)
        #define log_info(...)  log_log(LOG_INFO,  __FILE__, __LINE__, __VA_ARGS__)
        #define log_warn(...)  log_log(LOG_WARN,  __FILE__, __LINE__, __VA_ARGS__)
        #define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__)
        #define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__)
      
        const char* log_level_string(int level);
        void log_set_lock(log_LockFn fn, void *udata);
        void log_set_level(int level);
        void log_set_quiet(bool enable);
        int log_add_callback(log_LogFn fn, void *udata, int level);
        int log_add_fp(FILE *fp, int level);
      
        void log_log(int level, const char *file, int line, const char *fmt, ...);
      
        #endif
      
  • log.c
    •   #include "log.h"
        #define MAX_CALLBACKS 32
      
        typedef struct {
            log_LogFn fn;
            void *udata;
            int level;
        } Callback;
      
        static struct {
            void *udata;
            log_LockFn lock;
            int level;
            bool quiet;
            Callback callbacks[MAX_CALLBACKS];
        } L;
      
      
        static const char *level_strings[] = {"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"};
      
        #ifdef LOG_USE_COLOR
        static const char *level_colors[] = {"\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m"};
        #endif
      
      
        static void stdout_callback(log_Event *ev) {
            char buf[16];
            buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->time)] = '\0';
            #ifdef LOG_USE_COLOR
                fprintf(ev->udata, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", buf, level_colors[ev->level], level_strings[ev->level], ev->file, ev->line);
            #else
                fprintf(ev->udata, "%s %-5s %s:%d: ", buf, level_strings[ev->level], ev->file, ev->line);
            #endif
            vfprintf(ev->udata, ev->fmt, ev->ap);
            fprintf(ev->udata, "\n");
            fflush(ev->udata);
        }
      
        static void file_callback(log_Event *ev) {
            char buf[64];
            buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0';
            fprintf(ev->udata, "%s %-5s %s:%d: ", buf, level_strings[ev->level], ev->file, ev->line);
            vfprintf(ev->udata, ev->fmt, ev->ap);
            fprintf(ev->udata, "\n");
            fflush(ev->udata);
        }
      
        static void lock(void)   { 
            if (L.lock) { 
                L.lock(true, L.udata); 
            }
        }
      
        static void unlock(void) {
            if (L.lock) { 
                L.lock(false, L.udata); 
            }
        }
      
        const char* log_level_string(int level) { 
            return level_strings[level];
        }
      
        void log_set_lock(log_LockFn fn, void *udata) {
            L.lock = fn;
            L.udata = udata;
        }
      
        void log_set_level(int level) {
            L.level = level;
        }
      
      
        void log_set_quiet(bool enable) {
            L.quiet = enable;
        }
      
      
        int log_add_callback(log_LogFn fn, void *udata, int level) {
            for (int i = 0; i < MAX_CALLBACKS; i++) {
                if (!L.callbacks[i].fn) {
                    L.callbacks[i] = (Callback) { fn, udata, level };
                    return 0;
                }
            }
            return -1;
        }
      
      
        int log_add_fp(FILE *fp, int level) {
            return log_add_callback(file_callback, fp, level);
        }
      
      
        static void init_event(log_Event *ev, void *udata) {
            if (!ev->time) {
                time_t t = time(NULL);
                ev->time = localtime(&t);
            }
            ev->udata = udata;
        }
      
      
        void log_log(int level, const char *file, int line, const char *fmt, ...) {
            log_Event ev = {
                .fmt   = fmt,
                .file  = file,
                .line  = line,
                .level = level,
            };
      
            lock();
      
            if (!L.quiet && level >= L.level) {
                init_event(&ev, stderr);
                va_start(ev.ap, fmt);
                stdout_callback(&ev);
                va_end(ev.ap);
            }
      
            for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++) {
                Callback *cb = &L.callbacks[i];
                if (level >= cb->level) {
                    init_event(&ev, cb->udata);
                    va_start(ev.ap, fmt);
                    cb->fn(&ev);
                    va_end(ev.ap);
                }
            }
      
            unlock();
        }
      

你可能感兴趣的:(开发语言,#,C/C++开发,c语言,开源)