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

这篇具有很好参考价值的文章主要介绍了轻量级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 <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);
        }
      
  • 演示效果
    c语言 日志库,开发语言,# C/C++开发,c语言,开源

源码

  • 如果访问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();
       }
      

文章来源地址https://www.toymoban.com/news/detail-730081.html

到了这里,关于轻量级c语言开源日志库log.c介绍 - 实现不同级别和参数化日志打印的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C#轻量级日志功能(只有一个类)

    最近在开发基于.net6的一个数据监控软件,使用其它开源log库都有点麻烦,就想着对Console.WriteLine()方法重定向到文件,非常方便的实现日志记录功能,同时也不影响之前的代码结构。 软件开始的地方要设置该重定向:

    2024年01月21日
    浏览(63)
  • 『SEQ日志』在 .NET中快速集成轻量级的分布式日志平台

    📣读完这篇文章里你能收获到 如何在Docker中部署 SEQ:介绍了如何创建和运行 SEQ 容器,给出了详细的执行操作 如何使用 NLog 接入 .NET Core 应用程序的日志:详细介绍了 NLog 和 NLog.Seq 来配置和记录日志的步骤 日志记录示例:博客提供了一个简单的日志记录示例,展示了如何在

    2024年02月11日
    浏览(60)
  • 【架构】K8s中部署轻量级日志系统Loki

    Loki 是什么? Loki是由Grafana Labs开源的一个水平可扩展、高可用性,多租户的日志聚合系统的日志聚合系统。它的设计初衷是为了解决在大规模分布式系统中,处理海量日志的问题。Loki采用了分布式的架构,并且与Prometheus、Grafana密切集成,可以快速地处理大规模的日志数据。

    2024年02月20日
    浏览(60)
  • Kubernetes轻量级日志工具Loki安装及踩坑记录

    Loki是Grafana出品的一个轻量级日志系统,熟悉ELK的都知道ELK使用起来的成本,而且仅仅是日志检索使用ELK的话有点大材小用了。Loki8技术栈中使用了以下组件。 Promtail 用来将容器日志发送到 Loki 或者 Grafana 服务上的日志收集工具,该工具主要包括发现采集目标以及给日志流添

    2024年02月03日
    浏览(55)
  • Qat++,轻量级开源C++ Web框架

    目录 一.简介 二.编译Oat++ 1.环境 2.编译/安装 三.试用 1.创建一个 CMake 项目 2.自定义客户端请求响应 3.将请求Router到服务器 4.用浏览器验证 Oat++是一个面向C++的现代Web框架 官网地址:https://oatpp.io github地址:https://github.com/oatpp/oatpp Oat++具有如下特性: ●随处运行 Oat++没有任何

    2024年02月01日
    浏览(70)
  • Gitea:轻量级、开源的Git仓库管理平台

    Gitea是一款开源的、基于Go语言编写的轻量级Git服务器。它提供了类似于GitHub的功能,如代码托管、版本控制、团队协作等,但更加轻便和易于部署。Gitea的设计初衷是为了让团队或个人能够更方便地管理和分享自己的代码,同时不需要花费大量的资源和精力去搭建和维护一个

    2024年04月23日
    浏览(42)
  • 10 分钟在K8s 中部署轻量级日志系统 Loki

    转载至我的博客 https://www.infrastack.cn ,公众号:架构成长指南 Loki 是什么? Loki是由Grafana Labs开源的一个水平可扩展、高可用性,多租户的日志聚合系统的日志聚合系统。它的设计初衷是为了解决在大规模分布式系统中,处理海量日志的问题。Loki采用了分布式的架构,并且与

    2024年02月21日
    浏览(59)
  • 一些优秀的开源轻量级TCP/IP协议栈

    以下是一些优秀的开源轻量级TCP/IP协议栈,它们适用于嵌入式设备和其他资源受限的环境: lwIP(lightweight IP):lwIP 是一个非常流行的开源 TCP/IP 协议栈,它专门为嵌入式系统设计,具有低内存占用和高效率的特点。lwIP 具有TCP、UDP、IP、ICMP、ARP、DNS、SNMP、DHCP等协议的支持,

    2024年02月16日
    浏览(51)
  • 轻量级全功能开源免费Mailu邮件服务器部署

    实践说明:基于AlmaLinux9,但适用场景不限于此。 文档形成时期:2023年 因系统或软件版本不同,构建部署可能略有差异,但本文未做细分,对稍有经验者应不存在明显障碍。 因软件世界之复杂和个人能力之限,难免疏漏和错误,欢迎指正。 占用资源少而使用成本低; 基本功

    2024年02月02日
    浏览(60)
  • 推荐一款轻量级全栈式开源测试平台!

    1、RunnerGo介绍 今天给大家介绍一个好用的测试平台:RunnerGo(开源)。RunnerGo是一款轻量级、全栈式的测试平台,支持接口管理、场景管理、性能测试、自动化测试等功能。与市面上的性能测试工具不同的是RunnerGo基于go语言研发,更加轻量级。           附上官网和开源链

    2024年02月12日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包