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

局域网广域网,IP地址和端口号,TCP/IP 4层协议,协议的封装和分用
前言 在古老的年代,如果我们要实现两台机器进行数据传输, A员工就得去B员工的办公电脑传数据(B休息,等A传完),这样就很浪费时间 所以能不能不去B的工位的同时,还能传数据。这时候网络通信就出来…...

LabVIEW项目编码器选择
在LabVIEW项目中,选择增量式(Incremental Encoder)和绝对式(Absolute Encoder)编码器取决于项目的具体需求。增量式编码器和绝对式编码器在工作原理、应用场景、精度和成本等方面存在显著差异。以下从多方面详细阐述两…...
Spring Boot实现房产租赁业务逻辑
1 绪论 1.1 研究背景 中国的科技的不断进步,计算机发展也慢慢的越来越成熟,人们对计算机也是越来越更加的依赖,科研、教育慢慢用于计算机进行管理。从第一台计算机的产生,到现在计算机已经发展到我们无法想象。给我们的生活改变很…...

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

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

VSCode编程配置再次总结
VScode 中C++编程再次总结 0.简介 1.配置总结 1.1 launch jsion文件 launch.json文件主要用于运行和调试的配置,具有程序启动调试功能。launch.json文件会启用tasks.json的任务,并能实现调试功能。 左侧任务栏的第四个选项运行和调试,点击创建launch.json {"conf…...
银行管理系统
摘 要 伴随着信息技术与互联网技术的不断发展,人们进到了一个新的信息化时代,传统管理技术性没法高效率、容易地管理信息内容。为了实现时代的发展必须,提升管理高效率,各种各样管理管理体系应时而生,各个领域陆续进到…...
极狐GitLab 17.4 重点功能解读【四】
GitLab 是一个全球知名的一体化 DevOps 平台,很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版,专门为中国程序员服务。可以一键式部署极狐GitLab。 学习极狐GitLab 的相关资料: 极狐GitLab 官网极狐…...
[每日一练]利用自连接实现数量查询
该题目来源于力扣: 1731. 每位经理的下属员工数量 - 力扣(LeetCode) 题目要求: 表:Employees----------------------- | Column Name | Type | ----------------------- | employee_id | int | | name …...

Linux云计算 |【第四阶段】RDBMS1-DAY3
主要内容: 子查询(单行单列、多行单列、单行多列、多行多列)、分页查询limit、联合查询union、插入语句、修改语句、删除语句 一、子查询 子查询就是指的在一个完整的查询语句之中,嵌套若干个不同功能的小查询,从而一…...

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

Vue $router.push打开新窗口
Vue $router.push打开新窗口 最近有粉丝小伙伴问我:$router.push方法用于在当前窗口中跳转路由,但有时候我们需要在新的窗口或标签页中打开一个路由改怎么实现呢? 那么这里就介绍下实现逻辑和代码案例! 文章目录 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其实是阿里的微服务解决方案,是阿里巴巴结合自身微服务实践,开源的微服务全家桶,在Spring Cloud项目中孵化成为Spring Cloud的子项目。第一代的Spring Cloud标准中很多组件已经停更,如:Eureak,zuul等。所以Sprin…...
JSON字符串转换成对象
在Java中,将JSON字符串转换成对象是一个常见的操作,特别是在处理Web服务或API时。这通常通过使用第三方库来实现,因为Java标准库(Java SE)本身并不直接支持JSON的序列化和反序列化。最常用的库之一是Jackson和Gson。下…...
第三十五章 结合加密和签名
文章目录 第三十五章 结合加密和签名使用非对称密钥签名并加密使用非对称密钥加密并签名 第三十五章 结合加密和签名 可以在同一条消息中加密和签名。在大多数情况下,只需组合前面主题中给出的方法即可。本主题讨论了多种场景。 使用非对称密钥签名并加密 要签名…...
FastAPI 第八课 -- 路径操作依赖项
目录 一. 前言 二. 依赖项(Dependencies) 2.1. 依赖注入 2.2. 依赖项的使用 三. 路径操作依赖项的基本使用 3.1. 预处理(Before) 3.2. 后处理(After) 四. 多个依赖项的组合 五. 异步依赖项 一. 前…...

大厂面试真题-说一下Mybatis的缓存
首先看一下原理图 Mybatis提供了两种缓存机制:一级缓存(L1 Cache)和二级缓存(L2 Cache),旨在提高数据库查询的性能,减少数据库的访问次数。注意查询的顺序是先二级缓存,再一级缓存。…...
jQuery UI 工作原理
jQuery UI 工作原理 引言 jQuery UI 是建立在 jQuery 库之上的一个开源 JavaScript 库,它提供了一系列用户界面交互、特效、小部件和主题。它旨在简化 HTML 用户界面的开发,使开发者能够轻松地创建具有丰富交互性和视觉吸引力的网页。本文将深入探讨 jQuery UI 的工作原理,…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...

循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...

如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...

用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...

图表类系列各种样式PPT模版分享
图标图表系列PPT模版,柱状图PPT模版,线状图PPT模版,折线图PPT模版,饼状图PPT模版,雷达图PPT模版,树状图PPT模版 图表类系列各种样式PPT模版分享:图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...

人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...

Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...