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

464 0
Honkers 2025-6-13 02:29:49 | 显示全部楼层 |阅读模式

前言

  • 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)的日志

演示

  • 测试代码
      1. #include "log.h"
      2. #include <stdio.h>
      3. int main() {
      4. FILE *fp = fopen("log.txt", "a+");
      5. if(fp == NULL){
      6. printf("create log file failed.\n");
      7. return -1;
      8. }
      9. //设置日志级别(在终端打印)
      10. log_set_level(LOG_TRACE);
      11. //设置日志级别(在文件中打印)
      12. log_add_fp(fp, LOG_INFO);
      13. log_trace("start trace.");
      14. log_debug("start debug.");
      15. log_info("start info.");
      16. log_warn("start warn.");
      17. log_error("start error.");
      18. log_fatal("start fatal");
      19. // 支持参数打印
      20. log_info("number is %d, string is %s", 10010, "helloword");
      21. fclose(fp);
      22. }
      复制代码
  • 演示效果

源码

  • 如果访问github有问题,我把源码贴到下面了。
  • log.h
      1. #ifndef LOG_H
      2. #define LOG_H
      3. #include <stdio.h>
      4. #include <stdarg.h>
      5. #include <stdbool.h>
      6. #include <time.h>
      7. #define LOG_VERSION "0.1.0"
      8. typedef struct {
      9. va_list ap;
      10. const char *fmt;
      11. const char *file;
      12. struct tm *time;
      13. void *udata;
      14. int line;
      15. int level;
      16. } log_Event;
      17. typedef void (*log_LogFn)(log_Event *ev);
      18. typedef void (*log_LockFn)(bool lock, void *udata);
      19. enum { LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL };
      20. #define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__)
      21. #define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__)
      22. #define log_info(...) log_log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__)
      23. #define log_warn(...) log_log(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__)
      24. #define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__)
      25. #define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__)
      26. const char* log_level_string(int level);
      27. void log_set_lock(log_LockFn fn, void *udata);
      28. void log_set_level(int level);
      29. void log_set_quiet(bool enable);
      30. int log_add_callback(log_LogFn fn, void *udata, int level);
      31. int log_add_fp(FILE *fp, int level);
      32. void log_log(int level, const char *file, int line, const char *fmt, ...);
      33. #endif
      复制代码
  • log.c
      1. #include "log.h"
      2. #define MAX_CALLBACKS 32
      3. typedef struct {
      4. log_LogFn fn;
      5. void *udata;
      6. int level;
      7. } Callback;
      8. static struct {
      9. void *udata;
      10. log_LockFn lock;
      11. int level;
      12. bool quiet;
      13. Callback callbacks[MAX_CALLBACKS];
      14. } L;
      15. static const char *level_strings[] = {"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"};
      16. #ifdef LOG_USE_COLOR
      17. static const char *level_colors[] = {"\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m"};
      18. #endif
      19. static void stdout_callback(log_Event *ev) {
      20. char buf[16];
      21. buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->time)] = '\0';
      22. #ifdef LOG_USE_COLOR
      23. 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);
      24. #else
      25. fprintf(ev->udata, "%s %-5s %s:%d: ", buf, level_strings[ev->level], ev->file, ev->line);
      26. #endif
      27. vfprintf(ev->udata, ev->fmt, ev->ap);
      28. fprintf(ev->udata, "\n");
      29. fflush(ev->udata);
      30. }
      31. static void file_callback(log_Event *ev) {
      32. char buf[64];
      33. buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0';
      34. fprintf(ev->udata, "%s %-5s %s:%d: ", buf, level_strings[ev->level], ev->file, ev->line);
      35. vfprintf(ev->udata, ev->fmt, ev->ap);
      36. fprintf(ev->udata, "\n");
      37. fflush(ev->udata);
      38. }
      39. static void lock(void) {
      40. if (L.lock) {
      41. L.lock(true, L.udata);
      42. }
      43. }
      44. static void unlock(void) {
      45. if (L.lock) {
      46. L.lock(false, L.udata);
      47. }
      48. }
      49. const char* log_level_string(int level) {
      50. return level_strings[level];
      51. }
      52. void log_set_lock(log_LockFn fn, void *udata) {
      53. L.lock = fn;
      54. L.udata = udata;
      55. }
      56. void log_set_level(int level) {
      57. L.level = level;
      58. }
      59. void log_set_quiet(bool enable) {
      60. L.quiet = enable;
      61. }
      62. int log_add_callback(log_LogFn fn, void *udata, int level) {
      63. for (int i = 0; i < MAX_CALLBACKS; i++) {
      64. if (!L.callbacks[i].fn) {
      65. L.callbacks[i] = (Callback) { fn, udata, level };
      66. return 0;
      67. }
      68. }
      69. return -1;
      70. }
      71. int log_add_fp(FILE *fp, int level) {
      72. return log_add_callback(file_callback, fp, level);
      73. }
      74. static void init_event(log_Event *ev, void *udata) {
      75. if (!ev->time) {
      76. time_t t = time(NULL);
      77. ev->time = localtime(&t);
      78. }
      79. ev->udata = udata;
      80. }
      81. void log_log(int level, const char *file, int line, const char *fmt, ...) {
      82. log_Event ev = {
      83. .fmt = fmt,
      84. .file = file,
      85. .line = line,
      86. .level = level,
      87. };
      88. lock();
      89. if (!L.quiet && level >= L.level) {
      90. init_event(&ev, stderr);
      91. va_start(ev.ap, fmt);
      92. stdout_callback(&ev);
      93. va_end(ev.ap);
      94. }
      95. for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++) {
      96. Callback *cb = &L.callbacks[i];
      97. if (level >= cb->level) {
      98. init_event(&ev, cb->udata);
      99. va_start(ev.ap, fmt);
      100. cb->fn(&ev);
      101. va_end(ev.ap);
      102. }
      103. }
      104. unlock();
      105. }
      复制代码
  • windows平台编译时有报错,结构体赋值语法不支持,我做了修改。
  • 修改后的 log.c
      1. #include "log.h"
      2. #define MAX_CALLBACKS 32
      3. typedef struct {
      4. log_LogFn fn;
      5. void *udata;
      6. int level;
      7. } Callback;
      8. static struct {
      9. void *udata;
      10. log_LockFn lock;
      11. int level;
      12. bool quiet;
      13. Callback callbacks[MAX_CALLBACKS];
      14. } L;
      15. static const char *level_strings[] = {"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"};
      16. #ifdef LOG_USE_COLOR
      17. static const char *level_colors[] = {"\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m"};
      18. #endif
      19. static void stdout_callback(log_Event *ev) {
      20. char buf[100] = {0};
      21. time_t timep;
      22. time(&timep);
      23. struct tm *pt = gmtime(&timep);
      24. 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);
      25. #ifdef LOG_USE_COLOR
      26. 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);
      27. #else
      28. fprintf((FILE *)ev->udata, "%s %-5s %s:%d: ", buf, level_strings[ev->level], ev->file, ev->line);
      29. #endif
      30. vfprintf((FILE *)ev->udata, ev->fmt, ev->ap);
      31. fprintf((FILE *)ev->udata, "\n");
      32. fflush((FILE *)ev->udata);
      33. }
      34. static void file_callback(log_Event *ev) {
      35. char buf[100] = {0};
      36. time_t timep;
      37. time(&timep);
      38. struct tm *pt = gmtime(&timep);
      39. 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);
      40. fprintf((FILE *)ev->udata, "%s %-5s %s:%d: ", buf, level_strings[ev->level], ev->file, ev->line);
      41. vfprintf((FILE *)ev->udata, ev->fmt, ev->ap);
      42. fprintf((FILE *)ev->udata, "\n");
      43. fflush((FILE *)ev->udata);
      44. }
      45. static void lock(void) {
      46. if (L.lock) {
      47. L.lock(true, L.udata);
      48. }
      49. }
      50. static void unlock(void) {
      51. if (L.lock) {
      52. L.lock(false, L.udata);
      53. }
      54. }
      55. const char *log_level_string(int level) { return level_strings[level]; }
      56. void log_set_lock(log_LockFn fn, void *udata) {
      57. L.lock = fn;
      58. L.udata = udata;
      59. }
      60. void log_set_level(int level) { L.level = level; }
      61. void log_set_quiet(bool enable) { L.quiet = enable; }
      62. int log_add_callback(log_LogFn fn, void *udata, int level) {
      63. for (int i = 0; i < MAX_CALLBACKS; i++) {
      64. if (!L.callbacks[i].fn) {
      65. L.callbacks[i].fn = fn;
      66. L.callbacks[i].udata = udata;
      67. L.callbacks[i].level = level;
      68. return 0;
      69. }
      70. }
      71. return -1;
      72. }
      73. int log_add_fp(FILE *fp, int level) { return log_add_callback(file_callback, fp, level); }
      74. static void init_event(log_Event *ev, void *udata) {
      75. if (!ev->time) {
      76. time_t t = time(NULL);
      77. ev->time = gmtime(&t);
      78. }
      79. ev->udata = udata;
      80. }
      81. void log_log(int level, const char *file, int line, const char *fmt, ...) {
      82. log_Event ev;
      83. ev.fmt = fmt;
      84. ev.file = file;
      85. ev.line = line;
      86. ev.level = level;
      87. lock();
      88. if (!L.quiet && level >= L.level) {
      89. init_event(&ev, stderr);
      90. va_start(ev.ap, fmt);
      91. stdout_callback(&ev);
      92. va_end(ev.ap);
      93. }
      94. for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++) {
      95. Callback *cb = &L.callbacks[i];
      96. if (level >= cb->level) {
      97. init_event(&ev, cb->udata);
      98. va_start(ev.ap, fmt);
      99. cb->fn(&ev);
      100. va_end(ev.ap);
      101. }
      102. }
      103. unlock();
      104. }
      复制代码

新增功能

  • 在上述基础上,增加了毫秒级日期的打印,以及windows平台线程id打印。
  • 由于用到了系统API,在嵌入式设备上可能不支持。
  • 源码地址

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Honkers

荣誉红客

关注
  • 4014
    主题
  • 36
    粉丝
  • 0
    关注
这家伙很懒,什么都没留下!

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2025 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行