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

前言

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

源码地址

使用介绍

  • 直接把工程目录下的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 <stdio.h>
      
        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);
        }
      
  • 演示效果
    在这里插入图片描述

源码

  • 如果访问github有问题,我把源码贴到下面了。
  • log.h
    •   #ifndef LOG_H
        #define LOG_H
      
        #include <stdio.h>
        #include <stdarg.h>
        #include <stdbool.h>
        #include <time.h>
      
        #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();
        }
      
  • windows平台编译时有报错,结构体赋值语法不支持,我做了修改。
  • 修改后的 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[100] = {0};
           time_t timep;
           time(&timep);
           struct tm *pt = gmtime(&timep);
           sprintf(buf, "%d-%02d-%02d %02d:%02d:%02d", 1900 + pt->tm_year, 1 + pt->tm_mon, pt->tm_mday, (8 + pt->tm_hour) % 24, pt->tm_min, pt->tm_sec);
       #ifdef LOG_USE_COLOR
           fprintf((FILE *)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((FILE *)ev->udata, "%s %-5s %s:%d: ", buf, level_strings[ev->level], ev->file, ev->line);
       #endif
           vfprintf((FILE *)ev->udata, ev->fmt, ev->ap);
           fprintf((FILE *)ev->udata, "\n");
           fflush((FILE *)ev->udata);
       }
       
       static void file_callback(log_Event *ev) {
           char buf[100] = {0};
           time_t timep;
           time(&timep);
           struct tm *pt = gmtime(&timep);
           sprintf(buf, "%d-%02d-%02d %02d:%02d:%02d", 1900 + pt->tm_year, 1 + pt->tm_mon, pt->tm_mday, (8 + pt->tm_hour) % 24, pt->tm_min, pt->tm_sec);
           fprintf((FILE *)ev->udata, "%s %-5s %s:%d: ", buf, level_strings[ev->level], ev->file, ev->line);
           vfprintf((FILE *)ev->udata, ev->fmt, ev->ap);
           fprintf((FILE *)ev->udata, "\n");
           fflush((FILE *)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].fn = fn;
                   L.callbacks[i].udata = udata;
                   L.callbacks[i].level = 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 = gmtime(&t);
           }
           ev->udata = udata;
       }
       
       void log_log(int level, const char *file, int line, const char *fmt, ...) {
           log_Event ev;
           ev.fmt = fmt;
           ev.file = file;
           ev.line = line;
           ev.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();
       }
      
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大草原的小灰灰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值