当前位置: 首页 > news >正文

C语言中的日志机制:打造全面强大的日志系统

99dd28450fb34a8a9873d1a5a6361114.jpeg

前言

在软件开发中,良好的日志记录机制对于调试、监控程序状态和维护系统的稳定性至关重要。本文将介绍如何在C语言中构建一个全面强大的日志系统,并提供一些示例代码。

1. 日志的基本概念

  • 日志级别:用于分类日志信息的重要性,如 DEBUG, INFO, WARNING, ERROR, CRITICAL 等。
  • 日志消息:包含日志级别、时间戳、文件名、行号、消息内容等。
  • 日志输出:日志可以输出到控制台、文件或网络服务等。

2. 日志级别宏定义

定义日志级别的宏,便于管理和调整日志输出。

1#define LOG_DEBUG 1
2#define LOG_INFO 2
3#define LOG_WARNING 3
4#define LOG_ERROR 4
5#define LOG_CRITICAL 5
6
7#define LOG_LEVEL LOG_DEBUG // 设置日志级别
8
9#define LOG(level, ...) \
10    do { \
11        if (level >= LOG_LEVEL) { \
12            fprintf(stderr, "[%s] %s:%d: ", logLevelToString(level), __FILE__, __LINE__); \
13            fprintf(stderr, __VA_ARGS__); \
14            fprintf(stderr, "\n"); \
15        } \
16    } while (0)
17
18static const char* logLevelToString(int level) {
19    switch (level) {
20        case LOG_DEBUG: return "DEBUG";
21        case LOG_INFO: return "INFO";
22        case LOG_WARNING: return "WARNING";
23        case LOG_ERROR: return "ERROR";
24        case LOG_CRITICAL: return "CRITICAL";
25        default: return "UNKNOWN";
26    }
27}

解释

  • LOG_LEVEL 定义了当前的日志级别。
  • LOG 宏用于输出日志,根据日志级别过滤日志输出。
  • logLevelToString 函数将日志级别转换为字符串。

3. 使用日志宏

使用定义好的日志宏来记录日志。

1#include <stdio.h>
2
3int main() {
4    LOG(LOG_DEBUG, "This is a debug message.");
5    LOG(LOG_INFO, "This is an info message.");
6    LOG(LOG_WARNING, "This is a warning message.");
7    LOG(LOG_ERROR, "This is an error message.");
8    LOG(LOG_CRITICAL, "This is a critical message.");
9
10    return 0;
11}

输出:

1[DEBUG] main.c:17: This is a debug message.
2[INFO] main.c:18: This is an info message.
3[WARNING] main.c:19: This is a warning message.
4[ERROR] main.c:20: This is an error message.
5[CRITICAL] main.c:21: This is a critical message.

解释

  • 使用 LOG 宏记录不同级别的日志。

4. 日志到文件

将日志输出到文件。

1#include <stdio.h>
2#include <stdarg.h>
3#include <string.h>
4
5#define MAX_LOG_SIZE 1024
6
7void logToFile(const char *level, const char *file, int line, const char *fmt, ...) {
8    FILE *logfile = fopen("app.log", "a"); // 打开日志文件
9    if (logfile == NULL) {
10        perror("Failed to open log file");
11        return;
12    }
13
14    va_list args;
15    va_start(args, fmt);
16    char logBuffer[MAX_LOG_SIZE];
17    vsnprintf(logBuffer, MAX_LOG_SIZE - 1, fmt, args);
18    va_end(args);
19
20    time_t now = time(NULL);
21    struct tm *timeinfo = localtime(&now);
22    char timestamp[20];
23    strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", timeinfo);
24
25    fprintf(logfile, "[%s] %s %s:%d: %s\n", level, timestamp, file, line, logBuffer);
26    fclose(logfile);
27}
28
29#define LOG(level, ...) \
30    do { \
31        if (level >= LOG_LEVEL) { \
32            logToFile(logLevelToString(level), __FILE__, __LINE__, __VA_ARGS__); \
33        } \
34    } while (0)

解释

  • logToFile 函数用于将日志写入文件。
  • 使用 vsnprintf 和 va_list 处理可变参数列表。
  • 添加时间戳到日志消息。

5. 日志的旋转

实现日志文件的自动旋转,以便管理日志文件的大小。

1#include <stdio.h>
2#include <string.h>
3#include <errno.h>
4
5void rotateLog() {
6    FILE *logfile = fopen("app.log", "r");
7    if (logfile == NULL) {
8        perror("Failed to open log file");
9        return;
10    }
11
12    struct stat fileStat;
13    if (fstat(fileno(logfile), &fileStat) == -1) {
14        perror("Failed to get file status");
15        fclose(logfile);
16        return;
17    }
18
19    if (fileStat.st_size > 1024 * 1024) { // 如果日志文件大于1MB
20        fclose(logfile);
21        if (rename("app.log", "app.log.old") == -1) {
22            perror("Failed to rename log file");
23        }
24    } else {
25        fclose(logfile);
26    }
27}
28
29int main() {
30    // ... 日志记录代码 ...
31
32    // 在每次记录日志前检查是否需要旋转日志文件
33    rotateLog();
34    LOG(LOG_INFO, "This is an info message.");
35
36    return 0;
37}

解释

  • rotateLog 函数检查日志文件大小,如果超过阈值,则重命名旧的日志文件。
  • 在记录日志前调用 rotateLog

6. 日志配置

实现日志配置的读取和设置。

1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4
5typedef struct {
6    int level;
7    char *filename;
8} LogConfig;
9
10LogConfig loadConfig() {
11    LogConfig config = {LOG_DEBUG, "app.log"};
12
13    FILE *configFile = fopen("log.conf", "r");
14    if (configFile == NULL) {
15        perror("Failed to open config file");
16        return config;
17    }
18
19    char line[256];
20    while (fgets(line, sizeof(line), configFile) != NULL) {
21        if (strncmp(line, "level=", 6) == 0) {
22            char *levelStr = line + 6;
23            config.level = atoi(levelStr);
24        } else if (strncmp(line, "filename=", 9) == 0) {
25            char *filename = line + 9;
26            config.filename = strdup(filename);
27        }
28    }
29
30    fclose(configFile);
31
32    return config;
33}
34
35void setLogLevel(LogConfig config) {
36    LOG_LEVEL = config.level;
37    // 更改 logToFile 函数中的日志文件名
38}
39
40int main() {
41    LogConfig config = loadConfig();
42    setLogLevel(config);
43
44    // ... 日志记录代码 ...
45
46    return 0;
47}

解释

  • loadConfig 函数读取配置文件。
  • setLogLevel 函数设置日志级别和日志文件名。

结论

构建一个全面强大的日志机制对于软件开发至关重要。通过上述示例,你应该已经了解了如何在C语言中实现日志记录的不同方面。这种能力对于调试程序、监控应用程序状态和维护系统的稳定性非常有帮助。

 

相关文章:

C语言中的日志机制:打造全面强大的日志系统

前言 在软件开发中&#xff0c;良好的日志记录机制对于调试、监控程序状态和维护系统的稳定性至关重要。本文将介绍如何在C语言中构建一个全面强大的日志系统&#xff0c;并提供一些示例代码。 1. 日志的基本概念 日志级别&#xff1a;用于分类日志信息的重要性&#xff0c;…...

局域网广域网,IP地址和端口号,TCP/IP 4层协议,协议的封装和分用

前言 在古老的年代&#xff0c;如果我们要实现两台机器进行数据传输&#xff0c; A员工就得去B员工的办公电脑传数据&#xff08;B休息&#xff0c;等A传完&#xff09;&#xff0c;这样就很浪费时间 所以能不能不去B的工位的同时&#xff0c;还能传数据。这时候网络通信就出来…...

LabVIEW项目编码器选择

在LabVIEW项目中&#xff0c;选择增量式&#xff08;Incremental Encoder&#xff09;和绝对式&#xff08;Absolute Encoder&#xff09;编码器取决于项目的具体需求。增量式编码器和绝对式编码器在工作原理、应用场景、精度和成本等方面存在显著差异。以下从多方面详细阐述两…...

Spring Boot实现房产租赁业务逻辑

1 绪论 1.1 研究背景 中国的科技的不断进步&#xff0c;计算机发展也慢慢的越来越成熟&#xff0c;人们对计算机也是越来越更加的依赖&#xff0c;科研、教育慢慢用于计算机进行管理。从第一台计算机的产生&#xff0c;到现在计算机已经发展到我们无法想象。给我们的生活改变很…...

汽车3d动画渲染选择哪个?选择最佳云渲染解决方案

面临汽车3D动画渲染挑战&#xff1f;选择正确的云渲染服务至关重要。探索最佳解决方案&#xff0c;优化渲染效率&#xff0c;快速呈现逼真动画。 汽车3d动画渲染选择哪个&#xff1f; 对于汽车3D动画渲染&#xff0c;选择哪个渲染器取决于你的项目需求、预算和期望的效果。Ble…...

火语言RPA流程组件介绍--网页/元素截图

&#x1f6a9;【组件功能】&#xff1a;对整个网页、可见区域或者某个元素进行截图 &#xff0c;保存至指定文件夹&#xff0c;仅适用于内置浏览器 配置预览 配置说明 截图类型 整个网页/可见区域/元素截图 目标元素 支持T或# 通过自动捕获工具捕获(选择元素工具使用方法)…...

VSCode编程配置再次总结

VScode 中C++编程再次总结 0.简介 1.配置总结 1.1 launch jsion文件 launch.json文件主要用于运行和调试的配置,具有程序启动调试功能。launch.json文件会启用tasks.json的任务,并能实现调试功能。 左侧任务栏的第四个选项运行和调试,点击创建launch.json {"conf…...

银行管理系统

摘 要 伴随着信息技术与互联网技术的不断发展&#xff0c;人们进到了一个新的信息化时代&#xff0c;传统管理技术性没法高效率、容易地管理信息内容。为了实现时代的发展必须&#xff0c;提升管理高效率&#xff0c;各种各样管理管理体系应时而生&#xff0c;各个领域陆续进到…...

极狐GitLab 17.4 重点功能解读【四】

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署极狐GitLab。 学习极狐GitLab 的相关资料&#xff1a; 极狐GitLab 官网极狐…...

[每日一练]利用自连接实现数量查询

该题目来源于力扣&#xff1a; 1731. 每位经理的下属员工数量 - 力扣&#xff08;LeetCode&#xff09; 题目要求&#xff1a; 表&#xff1a;Employees----------------------- | Column Name | Type | ----------------------- | employee_id | int | | name …...

Linux云计算 |【第四阶段】RDBMS1-DAY3

主要内容&#xff1a; 子查询&#xff08;单行单列、多行单列、单行多列、多行多列&#xff09;、分页查询limit、联合查询union、插入语句、修改语句、删除语句 一、子查询 子查询就是指的在一个完整的查询语句之中&#xff0c;嵌套若干个不同功能的小查询&#xff0c;从而一…...

初始MYSQL数据库(8)—— JDBC编程

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a; MYSQL 目录 JDBC的概念 JDBC的使用 加载驱动包 建立连接 创建 statement 对象 定义并执行SQL语句 处理结果集 关闭资源 SQL注入 …...

Vue $router.push打开新窗口

Vue $router.push打开新窗口 最近有粉丝小伙伴问我&#xff1a;$router.push方法用于在当前窗口中跳转路由&#xff0c;但有时候我们需要在新的窗口或标签页中打开一个路由改怎么实现呢&#xff1f; 那么这里就介绍下实现逻辑和代码案例&#xff01; 文章目录 Vue $router.pus…...

SQL进阶技巧:如何利用if语句简化where或join中的条件 | if条件语句的优雅使用方法

目录 0 问题场景 1 数据准备 2 问题分析 2.1 需求一 2.2需求二 3 小结 0 问题场景 有两张表,一张用户下单表user_purchase(用户ID粒度)包含用户ID、订单ID和下单消耗金额和一张用户维表user_info包含用户ID、用户年龄和用户是否实名认证。 user_purchase user_info 需…...

SpringCloud-Alibaba第二代微服务快速入门

1.简介 Spring Cloud Alibaba其实是阿里的微服务解决方案&#xff0c;是阿里巴巴结合自身微服务实践,开源的微服务全家桶&#xff0c;在Spring Cloud项目中孵化成为Spring Cloud的子项目。第一代的Spring Cloud标准中很多组件已经停更,如&#xff1a;Eureak,zuul等。所以Sprin…...

JSON字符串转换成对象

在Java中&#xff0c;将JSON字符串转换成对象是一个常见的操作&#xff0c;特别是在处理Web服务或API时。这通常通过使用第三方库来实现&#xff0c;因为Java标准库&#xff08;Java SE&#xff09;本身并不直接支持JSON的序列化和反序列化。最常用的库之一是Jackson和Gson。下…...

第三十五章 结合加密和签名

文章目录 第三十五章 结合加密和签名使用非对称密钥签名并加密使用非对称密钥加密并签名 第三十五章 结合加密和签名 可以在同一条消息中加密和签名。在大多数情况下&#xff0c;只需组合前面主题中给出的方法即可。本主题讨论了多种场景。 使用非对称密钥签名并加密 要签名…...

FastAPI 第八课 -- 路径操作依赖项

目录 一. 前言 二. 依赖项&#xff08;Dependencies&#xff09; 2.1. 依赖注入 2.2. 依赖项的使用 三. 路径操作依赖项的基本使用 3.1. 预处理&#xff08;Before&#xff09; 3.2. 后处理&#xff08;After&#xff09; 四. 多个依赖项的组合 五. 异步依赖项 一. 前…...

大厂面试真题-说一下Mybatis的缓存

首先看一下原理图 Mybatis提供了两种缓存机制&#xff1a;一级缓存&#xff08;L1 Cache&#xff09;和二级缓存&#xff08;L2 Cache&#xff09;&#xff0c;旨在提高数据库查询的性能&#xff0c;减少数据库的访问次数。注意查询的顺序是先二级缓存&#xff0c;再一级缓存。…...

jQuery UI 工作原理

jQuery UI 工作原理 引言 jQuery UI 是建立在 jQuery 库之上的一个开源 JavaScript 库,它提供了一系列用户界面交互、特效、小部件和主题。它旨在简化 HTML 用户界面的开发,使开发者能够轻松地创建具有丰富交互性和视觉吸引力的网页。本文将深入探讨 jQuery UI 的工作原理,…...

CS 工作笔记:SmartEdit 里创建的是 CMS Component

下图是在 SmartEdit 里创建的 cms Component&#xff0c;在 Back-Office 里的截图&#xff1a; SAP Commerce Cloud 的 CMS Component 是其内容管理系统 (CMS) 的核心组成部分&#xff0c;它提供了对在线商店或平台内容的灵活管理。通过这些组件&#xff0c;用户能够在不涉及复…...

Java面试经验总结之SSM框架+springboot

一、spring 1.Spring 是什么&#xff1f; 答&#xff1a;spring 是一个轻量级的容器框架&#xff0c; ioc 和 aop 是他的核心。spring 将传统的代码以来形式&#xff0c;变为从容器中获取&#xff0c;提高了开发效率&#xff0c;非常的方便。spring 衍生出了很多生态&#x…...

Unity 热更新(HybridCLR+Addressable)-设置打包路径和加载路径、打开Hosting服务、打包

四、设置打包和加载路径 五、打开Hosting服务 六、打包 打包完成后路径在Assets同级目录下的ServerData 但是目前没有资源文件对比 修改上面设置后再次打包 里面多了哈希和JSON文件&#xff0c;这俩个就是用于资源对比...

享元(轻量级)模式

简介 享元模式&#xff08;Flyweight Pattern&#xff09;又叫作轻量级模式&#xff0c;是对象池的一种实现。类似线程池&#xff0c;线程池可以避免不停地创建和销毁多个对象&#xff0c;消耗性能。享元模式提供了减少对象数量从而改善应用所需的对象结构的方式。其宗旨是共享…...

基于php的幸运舞蹈课程工作室管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…...

NLP任务的详细原理与步骤的详细讲解

1. 文本分类 原理&#xff1a; 特征提取&#xff1a;文本分类首先将文本转化为数值特征&#xff0c;常用方法包括词袋模型、TF-IDF、Word Embeddings&#xff08;如Word2Vec、GloVe&#xff09;和BERT等预训练模型。模型训练&#xff1a;模型&#xff08;如SVM、神经网络&…...

Kotlin 处理字符串和正则表达式(二十一)

导读大纲 1.1 处理字符串和正则表达式1.1.1 分割字符串1.1.2 正则表达式和三引号字符串1.1.3 多行三引号字符串IntelliJ IDEA 和 Android Studio 中三重引号字符串内部的语法高亮显示 1.1 处理字符串和正则表达式 Kotlin 字符串与 Java 字符串完全相同 可以将 Kotlin 代码中创建…...

一站式大语言模型API调用:快速上手教程

智匠MindCraft是一个强大的AI工具及开发平台&#xff0c;支持多种大语言模型和多模态AI模型。本文将详细介绍如何通过API调用智匠MindCraft中的大语言模型&#xff0c;帮助开发者快速上手。 注册与登录 访问智匠MindCraft官网&#xff0c;注册并登录账号。 进入开发者平台&…...

【TabBar嵌套Navigation案例-新特性页面-代码位置 Objective-C语言】

一、接下来,我们来说这个新特性页面 1.首先,看一下我们的示例程序,这里改一下,加一个叹号, command + R, 好,首先啊,这里边有一个新特性页面,当我这个程序是第一次安装、第一次运行、还有呢、就是当这个应用程序更新的时候,我应该去加载这个新特性页面, 然后呢,这…...

程序员如何提升并保持核心竞争力?——深入钻研、广泛学习与软技能的培养

一、引言  随着人工智能的不断发展&#xff0c;尤其是AIGC系列大语言模型的涌现&#xff0c;AI辅助编程工具正在日益普及&#xff0c;这对程序员的工作方式产生了深刻的影响。面对这一变革&#xff0c;程序员应如何应对&#xff1f;是专注于某个领域深耕细作&#xff0c;还是…...

企业简介范文大全/谷歌网站推广优化

怎样在VS2008自带的SQl2005里使用sql server身份验证登陆 (转载&#xff09; 相信很多用过vs2005或最近用vs2008的朋友可能有这样的困惑&#xff1a;VS自带的sql server 登陆时默认的是用windows身份验证登陆&#xff0c;而不是用sql server身份验证。因为在这里的sql时集成在v…...

直播推广渠道/seo数据是什么意思

maven下载jar包的默认仓库是http://my.repository.com/repo/path速度较慢&#xff0c;通过配置国内镜像提高下载速度 1.打开eclipse--->Window--->Preferences--->选择Maven下的User Settings 如图找到User Settings路径中的settings.xml文件 2、修改配置文件 OSC的…...

做网站的用处/html做一个简单的网页

NFS相信应该都很熟悉了&#xff0c;但是我们对它的性能一直有所诟病。Oracle在10g版本通过允许对数据库文件直接IO引入ASM。在11g版本中&#xff0c;Oracle对NFS提供了类似的增强&#xff0c;为了改进NFS的性能&#xff0c;开创了DNFS(Direct Network File System)的数据库世界…...

成都网站优化维护/怎么被百度收录

max_children40 , 每个children平均占用20M-30M内存&#xff0c;children越多&#xff0c;可以同时接受的并发数量越多&#xff0c;一般children的值是网站最高并发数浮动值&#xff0c;这值再内存占用&#xff0c;就是你需要用到的内存。max_requests N 是指当每个children接…...

怎样利用网站做推广/优化网站链接的方法

iOS 杂笔&#xff0d;20&#xff08;UIView和CALayer的区别与联系&#xff09; 每个 UIView 内部都有一个 CALayer 在背后提供内容的绘制和显示&#xff0c;并且 UIView 的尺寸样式都由内部的 Layer 所提供。两者都有树状层级结构&#xff0c;layer 内部有 SubLayers&#xff0…...

推广型网站免费建设/百度推广按点击收费

在去吃午饭的路上想到的&#xff0c;总结下来&#xff1a;1 身份证随身带&#xff0c;否则寸步难行。最好办2个身份证&#xff0c;家里一个&#xff0c;随身一个&#xff0c;以防丢失。2 信用卡随身带&#xff0c;所有的消费尽可能用信用卡。最好带招行一个&#xff0c;其他行一…...