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

news2024/11/24 8:54:23

前言

  • 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);
        }
      
  • 演示效果
    在这里插入图片描述

源码

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1020774.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LVGL移植win端模拟显示流畅解决方案-使用 SquareLine 生成前端 UI 文件

lvgl_port_win_vscode 在 win 平台对 lvgl 方便的进行模拟显示&#xff0c;程序文件结构清晰&#xff0c;lvgl with SDL2&#xff0c;cmake 构建&#xff0c;VsCode 一键运行&#xff0c;使用 SquareLine 生成前端 UI 文件&#xff0c;win 上直接跑。 相比官方的 lvgl 移植到…

一百七十九、Linux——Linux报错No package epel-release available

一、目的 在Linux中配置Xmanager服务时&#xff0c;执行脚本时Linux报错No package epel-release available 二、解决措施 &#xff08;一&#xff09;第一步&#xff0c;# wget http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm &#xff08;二&…

@Validated 和 @Valid 的区别,你真的懂吗?SpringBoot 参数校验必知必会!

概述 Valid是使用Hibernate validation的时候使用Validated是只用Spring Validator校验机制使用 说明&#xff1a;java的JSR303声明了Valid这类接口&#xff0c;而Hibernate-validator对其进行了实现 Validation对Valid进行了二次封装&#xff0c;在使用上并没有区别&#xff…

水一下文章

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…

zookeeper —— 分布式服务协调框架

zookeeper —— 分布式服务协调框架 一、Zookeeper概述1、Zookeeper的基本概念2、Zookeeper的特点3、Zookeeper的数据结构 二、Zookeeper的安装部署1、Zookeeper的下载2、Zookeeper的安装本地模式&#xff08;单机模式standalone&#xff09;安装部署分布式&#xff08;集群模式…

视频监控系统/视频汇聚平台EasyCVR对国标类型编码进行判断的实现方式

视频监控平台/视频存储/视频分析平台EasyCVR基于云边端一体化管理&#xff0c;支持多类型设备、多协议方式接入&#xff0c;具体包括&#xff1a;国标GB28181协议、RTMP、RTSP/Onvif、海康Ehome&#xff0c;以及海康SDK、大华SDK、华为SDK、宇视SDK、乐橙SDK、萤石SDK等&#x…

WebGL 计算点光源下的漫反射光颜色

目录 点光源光 逐顶点光照&#xff08;插值&#xff09; 示例程序&#xff08;PointLightedCube.js&#xff09; 代码详解 示例效果 逐顶点处理点光源光照效果时出现的不自然现象 更逼真&#xff1a;逐片元光照 示例程序&#xff08;PointLightedCube_perFragment.js…

paddlespeech asr脚本demo

概述 paddlespeech是百度飞桨平台的开源工具包&#xff0c;主要用于语音和音频的分析处理&#xff0c;其中包含多个可选模型&#xff0c;提供语音识别、语音合成、说话人验证、关键词识别、音频分类和语音翻译等功能。 本文介绍利用ps中的asr功能实现批量处理音频文件的demo。…

回溯算法 解题思路

文章目录 算法介绍回溯算法能解决的问题解题模板1. 组合问题2. N皇后问题 算法介绍 回溯法&#xff08;Back Tracking Method&#xff09;&#xff08;探索与回溯法&#xff09;是一种选优搜索法&#xff0c;又称为试探法&#xff0c;按选优条件向前搜索&#xff0c;以达到目标…

URL 管理器

基本介绍 对外接口 对外提供两个接口&#xff1a;一个可以提取URL&#xff0c;一个可以增加URL&#xff0c;分别对应图上的1和2。 当要爬取某个网页时&#xff0c;则可以从1接口提取出该网页的URL进行爬取。 有时候爬取的网页内容中会包含别的网页链接&#xff0c;即包含有U…

java版Spring Cloud+Mybatis+Oauth2+分布式+微服务+实现工程管理系统

鸿鹄工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离构建工程项目管理系统 1. 项目背景 一、随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大。为了提高工程管理效率、减轻劳动强度、提高信息处理速度和准确性&#xff0c;公司对内部工程管…

Sui zkLogin让真正链接10亿用户成为可能

近日&#xff0c;Sui宣布推出zkLogin&#xff0c;这是将用户引入链上的最简单方式。zkLogin是Sui的一种原生功能&#xff0c;允许用户使用来自Google和Twitch等现有的Web2身份验证登录Web3应用程序&#xff0c;消除了用户需要记住或记录私钥的流程。 创建钱包通常被认为是区块…

使用vite创建vue3项目及项目的配置 | 环境准备 ESLint配置 prettier配置 husky配置 项目继承

文章目录 使用vite创建vue3项目及项目的配置1.环境准备2.项目配置ESLint校验代码工具配置 - js代码检测工具1.安装ESLint到开发环境 devDependencies2.生成配置文件:.eslint.cjs**3.安装vue3环境代码校验插件**4. 修改.eslintrc.cjs配置文件5.生成ESLint忽略文件6.在package.js…

K8S pod资源、探针

目录 一.pod资源限制 1.pod资源限制方式 2.pod资源限制指定时指定的参数 &#xff08;1&#xff09;request 资源 &#xff08;2&#xff09; limit 资源 &#xff08;3&#xff09;两种资源匹配方式 3.资源限制的示例 &#xff08;1&#xff09;官网示例 2&#xff0…

张勇时代落幕 蔡崇信能否让阿里变得更好

这两年&#xff0c;互联网行业似乎迎来了组织变革潮&#xff0c;只是谁也没想到&#xff0c;阿里的来得这么快&#xff0c;这么彻底。 9月10日晚&#xff0c;阿里巴巴董事会主席蔡崇信发布全员信&#xff0c;宣布已按计划完成集团管理职务交接&#xff0c;由他接任集团董事会主…

【JavaScript】对象类似数组那种数据结构 搜索一组匹配的数据

在 JavaScript 中&#xff0c;如果您想在类似数组的对象中进行关键字搜索并找到一组匹配的数据&#xff0c;可以使用filter()方法结合正则表达式来实现。 以下是一个示例代码&#xff0c;演示如何在类似数组的对象中进行关键字搜索并找到匹配的数据&#xff1a; const obj {…

APEX数据源加载实现Excel表数据导入及自定义存储过程

在APEX应用程序中会涉及到数据加载&#xff0c;说白了就是导入导出数据到数据库中&#xff0c;这里就以Excel导入数据到TEST_DATA_WXX表为例&#xff0c;来学习共享组件 数据源 数据加载定义 1 第一步先导出一个数据模板 进入《王小小鸭的学习demo》打开【用户管理】-【操作】…

c++ day 6

1、 将之前定义的栈类和队列类都实现成模板类 #include <iostream>using namespace std;#define MAX 128template<typename T>class Stack { public://构造函数Stack();//析构函数~Stack();//拷贝构造函数Stack(const Stack &other);//入栈int push(T e);//出…

【Redis7】--4.事务、管道、发布和订阅

文章目录 事务1.Redis事务2.Redis事务特性3.Redis事务命令3.1MULTI3.2EXEC3.3DISCARD3.4WATCH3.5UNWATCH 4.不保证原子性4.1"全体连坐"4.2"冤头债主" 5.事务执行流程 管道1.pipeline的使用2.pipeline小总结 发布和订阅1.常用命令1.1SUBSCRIBE1.2PUBLISH1.3…

小鹏、长城先后宣布智能计划,传统车企与新势力决战AI赛点?

点击关注 文&#xff5c;姚 悦&#xff0c;编&#xff5c;王一粟 “尽管我们已经造车30多年&#xff0c;但现在我们面临一个全新问题和挑战。”长城汽车AI Lab负责人杨继峰表示&#xff0c;“在AI时代里每个问题都是AI问题。” 杨继峰所负责的AI Lab&#xff0c;正是长城汽车…