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

2023-10-29

前言

  • 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();
        }
      
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • 软件测试|Python中如何提取列表中索引为奇数的元素

    简介 在Python中 我们经常需要从列表中提取特定位置的元素 如果我们想要提取列表中索引为奇数的元素 可以使用一些简单的方法来实现这一目标 本文将介绍如何在Python中提取列表中索引为奇数的元素 并提供示例代码来帮助大家更好地理解这个过
  • 让CHAT介绍下V2ray

    CHAT回复 V2Ray是一个网络工具 主要用于科学上网和保护用户的网络安全 它的名字源自Vmess Ray 光线 通过使用新的网络协议 为用户提供稳定且灵活的代理服务 下面是一些V2Ray的主要特性 1 多协议支持 V2Ray 提供了大量
  • 软件测试|使用matplotlib绘制平行坐标系图

    简介 绘制平行坐标系图 Parallel Coordinates Plot 是一种用于可视化多维数据的强大方法 在这篇文章中 我们将介绍如何使用Matplotlib库创建平行坐标系图 以及如何解释和定制这种图表 我们将使用一个示例数据集来演
  • 电商数据api拼多多接口获取商品实时数据价格比价api代码演示案例

    拼多多商品详情接口 接口接入入口 它的主要功能是允许卖家从自己的系统中快速获取商品详细信息 通过这个接口 卖家可以提取到商品的各类数据 包括但不限于商品标题 价格 优惠价 收藏数 下单人数 月销售量等 此外 还可以获取到商品的SKU图 详情
  • 基于java的物流信息网系统设计与实现

    基于java的物流信息网系统设计与实现 I 引言 A 研究背景和动机 基于Java的物流信息网系统设计与实现的研究背景和动机 随着互联网的普及和电子商务的快速发展 物流信息网系统已成为现代物流管理的重要组成部分 物流信息网系统能够实现物流信
  • 【计算机毕业设计】白优校园社团网站的设计与实现

    近些年 随着中国经济发展 人民的生活质量逐渐提高 对网络的依赖性越来越高 通过网络处理的事务越来越多 随着白优校园社团网站的常态化 如果依然采用传统的管理方式 将会为工作人员带来庞大的工作量 这将是一个巨大考验 需要投入大量人力开展对社团
  • 2024诸多大厂春招提前启动!Android的程序员还在等什么

    春招 提前批 已开 xdm别打瞌睡了 格力 顺丰 酷狗 沃尔玛中国 理想 科大讯飞等开启春招 开始收简历了 还有hc的企业提前抢人 春招时间短 节奏快 招满即止 就算挂了也绝不能不投 对企业来说 秋招和春招都是储备人才的黄金时期 春招中 除
  • 一台java服务器可以跑多少个线程?

    一台java服务器可以跑多少个线程 一台java服务器能跑多少个线程 这个问题来自一次线上报警如下图 超过了我们的配置阈值 打出jstack文件 通过IBM Thread and Monitor Dump Analyzer for Java
  • 计算机Java项目|尤文图斯足球俱乐部网上商城系统

    作者简介 Java领域优质创作者 CSDN博客专家 CSDN内容合伙人 掘金特邀作者 阿里云博客专家 51CTO特邀作者 多年架构师设计经验 腾讯课堂常驻讲师 主要内容 Java项目 Python项目 前端项目 人工智能与大数据 简历模板
  • 计算机Java项目|在线图书管理

    作者简介 Java领域优质创作者 CSDN博客专家 CSDN内容合伙人 掘金特邀作者 阿里云博客专家 51CTO特邀作者 多年架构师设计经验 腾讯课堂常驻讲师 主要内容 Java项目 Python项目 前端项目 人工智能与大数据 简历模板
  • 计算机Java项目|基于SSM的篮球系列网上商城设计与实现

    作者简介 Java领域优质创作者 CSDN博客专家 CSDN内容合伙人 掘金特邀作者 阿里云博客专家 51CTO特邀作者 多年架构师设计经验 腾讯课堂常驻讲师 主要内容 Java项目 Python项目 前端项目 人工智能与大数据 简历模板
  • APP开发毕业设计|ssm爱心小屋公益机构智慧管理APP

    作者主页 编程指南针 作者简介 Java领域优质创作者 CSDN博客专家 CSDN内容合伙人 掘金特邀作者 阿里云博客专家 51CTO特邀作者 多年架构师设计经验 腾讯课堂常驻讲师 主要内容 Java项目 Python项目 前端项目 人工智
  • JCMsuite应用:光学环形谐振腔模拟

    本案程演示了环形谐振腔的模拟 这种类型的集成光子器件 例如用作升 降滤波器或在传感应用中 当物质或粒子附着在环上时 通过测量其共振频率的位移来检测 对于集成光子电路中的无源光器件 s矩阵通常是研究的热点 它描述了通过端口 波导进入设备的电磁
  • 基于节点电价的电网对电动汽车接纳能力评估模型研究(Matlab代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码 数据
  • 2024年华为OD机试真题-查找接口成功率最优时间段-Python-OD统一考试(C卷)

    题目描述 服务之间交换的接口成功率作为服务调用关键质量特性 某个时间段内的接口失败率使用一个数组表示 数组中每个元素都是单位时间内失败率数值 数组中的数值为0 100的整数 给定一个数值 minAverageLost 表示某个时间段内平均失
  • 计算机Java项目|有机蔬菜商城

    作者简介 Java领域优质创作者 CSDN博客专家 CSDN内容合伙人 掘金特邀作者 阿里云博客专家 51CTO特邀作者 多年架构师设计经验 腾讯课堂常驻讲师 主要内容 Java项目 Python项目 前端项目 人工智能与大数据 简历模板
  • sychnorized积累

    sychnorized 1 对象锁 包括方法锁 默认锁对象为this 当前实例对象 和同步代码块锁 自己指定锁对象 2 类锁 指synchronize修饰静态的方法或指定锁对象为Class对象 3 加锁和释放锁的原理 现象 时机 内置锁th
  • Java开发中不要使用受检异常

    简介 Java是唯一 主流 实现了受检异常概念的编程语言 一开始 受检异常就是争议的焦点 在当时被视为一种创新概念 Java于1996年推出 如今却被视不良实践 本文要讨论Java中非受检异常和受检异常的动机以及它们优缺点 与大多数关注这个
  • 【安全】Java幂等性校验解决重复点击(6种实现方式)

    目录 一 简介 1 1 什么是幂等 1 2 为什么需要幂等性 1 3 接口超时 应该如何处理 1 4 幂等性对系统的影响 二 Restful API 接口的幂等性 三 实现方式 3 1 数据库层面 主键 唯一索引冲突 3 2 数据库层面 乐
  • 计算机Java项目|java游戏账号交易系统

    作者简介 Java领域优质创作者 CSDN博客专家 CSDN内容合伙人 掘金特邀作者 阿里云博客专家 51CTO特邀作者 多年架构师设计经验 腾讯课堂常驻讲师 主要内容 Java项目 Python项目 前端项目 人工智能与大数据 简历模板

随机推荐

  • 解决dubbo问题:com.alibaba.dubbo.rpc.RpcException: Forbid consumer (很可能是一个访问都没有注册成功)

    线下环境经常出现类似这种异常 com alibaba dubbo rpc RpcException Forbid consumer access service from registry use dubbo version 2 5 3 P
  • CVPR2020超分辨率重建论文阅读笔记

    为什么要进行超分辨率重建 1 视觉效果不吸引人 2 影响下游方法使用 如分割等 3 电子显示产品分辨率提高 需要更高分辨率的图像 超分辨率重建问题面临难点和存在问题如下 1 病态问题 一对多 同样的LR图像对应无数解 2 MSE指标可能导致
  • STM32 基础系列教程 38 - Lwip_http

    前言 HTTP协议 HyperText Transfer Protocol 超文本传输协议 是因特网上应用最为广泛的种网络传输协议 所有的WWW文件都必须遵守这个标准 HTTP是一个基于TCP IP通信协议来传递数据 HTML 文件 图片文
  • CNN经典网络模型(四):GoogLeNet简介及代码实现(PyTorch超详细注释版)

    目录 一 开发背景 二 网络结构 三 模型特点 四 代码实现 1 model py 2 train py 3 predict py 4 spilit data py 五 参考内容 一 开发背景 GoogLeNet在2014年由Google团
  • @Validated 注解不起作用 怎么办?@Validated 无效 解决办法

    有一种可能是之前没有查到的 那就是pom缺少依赖 在项目的pom xml 文件中添加以上依赖 可有效解决问题
  • MySQL触发器trigger的使用

    Q 什么是触发器 A 触发器是与表有关的数据库对象 在满足定义条件时触发 并执行触发器中定义的语句集合 触发器的特性 1 有begin end体 begin end 之间的语句可以写的简单或者复杂 2 什么条件会触发 I D U 3 什么时
  • 线程的六种状态

    1 New 新建状态 线程刚被创建 start方法之前的状态 2 Runnable 运行状态 得到时间片运行中状态 Ready就绪 未得到时间片就绪状态 3 Blocked 阻塞状态 如果遇到锁 线程就会变为阻塞状态等待另一个线程释放锁 4
  • repo 使用

    repo 使用 repo start 创建并切换分支 repo start newbranchname all projectName repo start是对git checkout b 命令的封装 git checkout b 是在当前
  • 无监督特征选择算法综述

    无监督特征选择算法 Filter方法 只使用数据的内在属性 不使用聚类等其他辅助方法 速度快 单变量 Information based methods SUD Sequential backward selection method fo
  • 毕业设计-基于机器视觉的手写字体智能识别系统

    目录 前言 课题背景和意义 实现技术思路 一 系统整体结构框架设计 二 系统硬件设计 三 系统软件框架设计 四 实验与分析 五 总结 实现效果图样例 最后 前言 大四是整个大学期间最忙碌的时光 一边要忙着备考或实习为毕业后面临的就业升学做准
  • 分布式系统下的纠删码(二) -- Locally Repairable Codes (LRC)

    分布式系统下的纠删码 二 Locally Repairable Codes LRC 一 名词解释 MDS Maximun Distance Separable MDS 性质 是纠删码的一个重要性质 它保证n k m个磁盘中任意k个磁盘都可恢
  • OpenLayers官网教程-移动端地图和传感器

    这一系列翻译自openlayers官网的WorkShop OL官网提供了多个系列教程供开发者学习参考 其中QuickStart是面向初学者的hello world Tutorials提供了构建OL应用的一些基础知识 WorkShop 本系列
  • scss 样式穿透

    当一些组件 例如 轮播 全局引入时 只改当前页面的样式 用css类选择器不能直接选择更改 应用scss样式穿透 注 scoped让css只在当前组件生效 不考虑兼容问题 去掉scoped也可以直接更改css样式
  • # leetcode#5最长回文数C++

    leetcode 5最长回文数C 一 思路一 中心扩散 对每一个字符 检测它与它旁边的数是否为回文数 如果是 那么再扩展它 的长度检查 分奇偶情况讨论 得到以该字符为中心最长的回文数 在遍历过程中用max 2 储存该目前最长的回文数位置和长
  • iphone11屏比例_iPhone每一代的屏幕尺寸比例是多少

    iPhone2G屏幕为3 5英寸 分辨率为320 480像素 比例为3 2 iPhone3G屏幕为3 5英寸 分辨率为320 480像素 比例为3 2 iPhone3GS屏幕为3 5英寸 分辨率为320 480像素 比例为3 2 iPhon
  • QOpenGLWidget 纹理贴图

    环境 QT 5 12 8 本人初学Opengl 想要绘制一个正方形并且贴纹理 以下是参考别人代码自己整理的 创建QT工程 结构如下 代码如下 glwidget h ifndef GLWIDGET H define GLWIDGET H in
  • [Python 与 炒股] TuShare 使用篇之三

    2016年新年第一贴 大年夜搞这个只能说明春晚实在是有点无聊 在之前的blog里写了一个最简单的例子 http blog csdn net robertsong2004 article details 50642655 现在试一下简单的分析
  • 渗透测试-01信息收集

    0x01信息收集 1 什么是信息收集 信息收集是指通过各种方式获取所需要的信息 以便我们在后续的渗透过程更好的进行 比如目标的站点IP 中间件 脚本语言 端口 邮箱等等 信息收集包含资产收集但不限于资产收集 2 信息收集的意义 1 信息收集
  • 使用 easyjson,生成 xxx_easyjson.go 文件之后,对测试结果所产生的影响

    文章评论 原文地址 https blog csdn net luslin1711 article details 90244468 正文 博主 你好 文中的测试结果 似乎不是很正确 由于评论区字数的限制 我另开一篇文章 请您解惑 以下是我的
  • 轻量级c语言开源日志库log.c介绍 - 实现不同级别和参数化日志打印

    前言 c语言没有现成的日志库 如果要记录日志 需要自己封装一个日志库 如果要实现日志级别和参数打印 还是比较麻烦的 正好在github找到了一个c语言开源日志库 可以实现日志级别打印 参数打印 而且还会记录日期和行号 最重要的是代码非常少