• 轻量级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 
        
          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);
          }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
    • 演示效果
      在这里插入图片描述

    源码

    • 如果访问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
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
        • 30
        • 31
        • 32
        • 33
        • 34
        • 35
        • 36
        • 37
        • 38
        • 39
        • 40
        • 41
        • 42
    • 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();
          }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
        • 30
        • 31
        • 32
        • 33
        • 34
        • 35
        • 36
        • 37
        • 38
        • 39
        • 40
        • 41
        • 42
        • 43
        • 44
        • 45
        • 46
        • 47
        • 48
        • 49
        • 50
        • 51
        • 52
        • 53
        • 54
        • 55
        • 56
        • 57
        • 58
        • 59
        • 60
        • 61
        • 62
        • 63
        • 64
        • 65
        • 66
        • 67
        • 68
        • 69
        • 70
        • 71
        • 72
        • 73
        • 74
        • 75
        • 76
        • 77
        • 78
        • 79
        • 80
        • 81
        • 82
        • 83
        • 84
        • 85
        • 86
        • 87
        • 88
        • 89
        • 90
        • 91
        • 92
        • 93
        • 94
        • 95
        • 96
        • 97
        • 98
        • 99
        • 100
        • 101
        • 102
        • 103
        • 104
        • 105
        • 106
        • 107
        • 108
        • 109
        • 110
        • 111
        • 112
        • 113
        • 114
        • 115
        • 116
        • 117
        • 118
        • 119
        • 120
        • 121
        • 122
        • 123
        • 124
        • 125
        • 126
        • 127
        • 128
        • 129
        • 130
        • 131
        • 132
    • 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();
         }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
        • 30
        • 31
        • 32
        • 33
        • 34
        • 35
        • 36
        • 37
        • 38
        • 39
        • 40
        • 41
        • 42
        • 43
        • 44
        • 45
        • 46
        • 47
        • 48
        • 49
        • 50
        • 51
        • 52
        • 53
        • 54
        • 55
        • 56
        • 57
        • 58
        • 59
        • 60
        • 61
        • 62
        • 63
        • 64
        • 65
        • 66
        • 67
        • 68
        • 69
        • 70
        • 71
        • 72
        • 73
        • 74
        • 75
        • 76
        • 77
        • 78
        • 79
        • 80
        • 81
        • 82
        • 83
        • 84
        • 85
        • 86
        • 87
        • 88
        • 89
        • 90
        • 91
        • 92
        • 93
        • 94
        • 95
        • 96
        • 97
        • 98
        • 99
        • 100
        • 101
        • 102
        • 103
        • 104
        • 105
        • 106
        • 107
        • 108
        • 109
        • 110
        • 111
        • 112
        • 113
        • 114
        • 115
        • 116
        • 117
        • 118
        • 119
        • 120
        • 121
        • 122
        • 123
        • 124
        • 125
  • 相关阅读:
    Java多线程-ThreadPool线程池-2(四)
    23062C++&QTday3
    Java并发编程—线程池
    中远通在创业板IPO过会:前三季度收入11亿元,罗厚斌为董事长
    0开篇-介绍
    【数据结构】队列(C语言实现)
    AQS小总结
    linux(centos7)常用命令 开启关闭防火墙
    【自学笔记】Python中的逻辑函数:any()、all()及同类函数的用法与示例
    芯片漫游指南(1)-- UVM世界观
  • 原文地址:https://blog.csdn.net/new9232/article/details/132992574