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

[C语言实战]C语言文件操作实战:打造高效日志系统(六)

[C语言实战]C语言文件操作实战:打造高效日志系统(六)

摘要:本文基于C语言标准文件I/O函数,实现支持多级日志、文件轮转、线程安全的轻量级日志系统。包含核心模块源码解析、性能优化技巧及完整测试方案。

一、日志系统核心设计

1.1 功能需求

功能模块实现要点
日志分级DEBUG/INFO/WARN/ERROR等级别
文件写入追加模式+缓冲优化
线程安全互斥锁保护文件操作
日志轮转按大小分割文件
时间戳精确到毫秒的本地时间

1.2 架构设计图

超过阈值
未超过
日志调用接口
过滤日志级别
格式化日志内容
线程安全写入
文件大小检查
创建新文件
追加写入

二、核心代码实现

2.1 头文件定义(logger.h)

#include <stdio.h>
#include <pthread.h>
#include <time.h>// 日志级别枚举
typedef enum {LOG_DEBUG,LOG_INFO,LOG_WARNING,LOG_ERROR
} LogLevel;// 日志配置结构体
typedef struct {LogLevel level;      // 当前日志级别char     path[256];  // 日志文件路径size_t   max_size;   // 单个文件最大大小(MB)int      backup_num; // 保留旧日志数量
} LoggerConfig;// 初始化日志系统
int logger_init(const LoggerConfig *config);// 写入日志接口
void log_write(LogLevel level, const char *file, int line, const char *fmt, ...);// 宏定义简化调用
#define LOG_DEBUG(...)  log_write(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__)
#define LOG_INFO(...)   log_write(LOG_INFO,  __FILE__, __LINE__, __VA_ARGS__)
#define LOG_WARN(...)   log_write(LOG_WARNING, __FILE__, __LINE__, __VA_ARGS__)
#define LOG_ERROR(...)  log_write(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__)

2.2 日志写入模块(logger.c)

#include <stdarg.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <string.h>
#include <stdio.h>
#include <pthread.h>
#include "logger.h"static pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
static LoggerConfig current_config;
static FILE *log_fp = NULL;
static unsigned long current_size = 0;// 检查并执行日志轮转
static void rotate_log() {if (current_size < current_config.max_size * 1024 * 1024) return;fclose(log_fp);// 重命名旧日志文件for (int i = current_config.backup_num-1; i > 0; --i) {char old_name[256], new_name[256];snprintf(old_name, sizeof(old_name), "%s.%d", current_config.path, i);snprintf(new_name, sizeof(new_name), "%s.%d", current_config.path, i+1);rename(old_name, new_name);}// 修复文件名拼接char rotated_name[256];snprintf(rotated_name, sizeof(rotated_name), "%s.1", current_config.path);rename(current_config.path, rotated_name);// 创建新日志文件log_fp = fopen(current_config.path, "a");current_size = 0;
}// 获取当前时间字符串
static void get_timestamp(char *buffer, size_t len) {struct timeval tv;gettimeofday(&tv, NULL);struct tm *tm = localtime(&tv.tv_sec);strftime(buffer, len, "%Y-%m-%d %H:%M:%S", tm);sprintf(buffer + strlen(buffer), ".%03ld", tv.tv_usec / 1000);
}// 初始化日志系统
int logger_init(const LoggerConfig *config) {pthread_mutex_lock(&log_mutex);memcpy(&current_config, config, sizeof(LoggerConfig));log_fp = fopen(config->path, "a");if (!log_fp) {pthread_mutex_unlock(&log_mutex);return -1;}// 获取当前文件大小struct stat st;stat(config->path, &st);current_size = st.st_size;pthread_mutex_unlock(&log_mutex);return 0;
}// 核心写入函数
void log_write(LogLevel level, const char *file, int line, const char *fmt, ...) {if (level < current_config.level) return;pthread_mutex_lock(&log_mutex);// 格式化日志头char timestamp[32], log_header[256];get_timestamp(timestamp, sizeof(timestamp));const char *level_str[] = {"DEBUG", "INFO", "WARN", "ERROR"};int header_len = snprintf(log_header, sizeof(log_header), "[%s] [%s] [%s:%d] ", timestamp, level_str[level], file, line);// 格式化可变参数char log_body[1024];va_list args;va_start(args, fmt);vsnprintf(log_body, sizeof(log_body), fmt, args);va_end(args);// 组合完整日志并写入fprintf(log_fp, "%s%s\n", log_header, log_body);current_size += header_len + strlen(log_body) + 1;// 刷新缓冲区并检查轮转fflush(log_fp);rotate_log();pthread_mutex_unlock(&log_mutex);
}int main() {LoggerConfig config = {.level = LOG_DEBUG,.path = "app.log",.max_size = 1,   // 1MB.backup_num = 3};// 修复条件判断if (logger_init(&config) != 0) {fprintf(stderr, "Failed to initialize logger\n");return 1;}// 生成测试日志for (int i = 0; i < 1000; ++i) {LOG_DEBUG("User %d login, session_id: %s", i, "ABCDEFG123456");LOG_INFO("Processed %d requests", i*10);if (i % 100 == 0) {LOG_WARN("High latency detected: %dms", rand()%500);}}LOG_ERROR("Connection timeout");return 0;
}  // 确保大括号正确闭合

三、测试验证方案

3.1 基础功能测试

int main() {LoggerConfig config = {.level = LOG_DEBUG,.path = "app.log",.max_size = 1,   // 1MB.backup_num = 3};// 修复条件判断if (logger_init(&config) != 0) {fprintf(stderr, "Failed to initialize logger\n");return 1;}// 生成测试日志for (int i = 0; i < 1000; ++i) {LOG_DEBUG("User %d login, session_id: %s", i, "ABCDEFG123456");LOG_INFO("Processed %d requests", i*10);if (i % 100 == 0) {LOG_WARN("High latency detected: %dms", rand()%500);}}LOG_ERROR("Connection timeout");return 0;
}  // 确保大括号正确闭合

3.2 验证步骤

  1. 编译运行

    gcc -o logger_test logger.c -lpthread
    ./logger_test
    
  2. 检查生成文件

    ls -lh app.log*
    

    预期输出:

    -rw-r--r-- 1 user group 1.0M Jul 10 15:30 app.log
    
  3. 查看日志内容

    tail -n 5 app.log
    

    预期输出:

    [2023-07-10 15:30:23.456] [DEBUG] [test.c:25] User 999 login...
    [2023-07-10 15:30:23.457] [INFO] [test.c:26] Processed 9990 requests
    [2023-07-10 15:30:23.458] [ERROR] [test.c:30] Connection timeout
    

在这里插入图片描述

四、性能优化技巧

4.1 缓冲策略优化

// 修改fprintf为块写入
char full_log[2048];
int len = snprintf(full_log, sizeof(full_log), "%s%s\n", log_header, log_body);
fwrite(full_log, 1, len, log_fp);
current_size += len;

4.2 异步日志写入

// 添加任务队列
void async_log(const char *msg) {pthread_mutex_lock(&queue_mutex);enqueue(log_queue, msg);pthread_cond_signal(&queue_cond);pthread_mutex_unlock(&queue_mutex);
}// 独立写线程
static void *write_thread(void *arg) {while (1) {pthread_mutex_lock(&queue_mutex);while (queue_empty(log_queue)) {pthread_cond_wait(&queue_cond, &queue_mutex);}char *msg = dequeue(log_queue);pthread_mutex_unlock(&queue_mutex);fputs(msg, log_fp);free(msg);}
}

五、扩展功能建议

  1. 网络日志支持:通过UDP将日志发送到远程服务器
  2. 日志过滤:根据文件名、函数名动态过滤日志
  3. 性能统计:记录每秒日志写入量、平均延迟
  4. 崩溃日志:通过signal handler捕获段错误并记录堆栈

最佳实践:生产环境建议设置max_size=10MBbackup_num=10
性能对比:同步写入 vs 异步写入吞吐量测试数据

希望本教程对您有帮助,请点赞❤️收藏⭐关注支持!欢迎在评论区留言交流技术细节!

相关文章:

  • 成立软件公司seo型网站
  • 南浔城乡建设局网站seo网站优化方案案例
  • 做网站要写代码吗优化seo是什么意思
  • 休闲食品网站建设东莞网站推广哪里找
  • WordPress是静态吗武汉seo公司
  • 哪有做网站的公司培训方案模板
  • 《Shell脚本实战:打造交互式多级菜单与LAMP/LNMP环境配置指南》
  • GPU基础知识
  • 字符集和字符编码
  • 创建dummy
  • 2025年第八届广西大学生程序设计大赛(正式赛)题解(更新中)
  • 第五十一节:增强现实基础-单应性矩阵计算
  • Java NPE为什么不会导致进程崩溃(CoreDump)
  • ModbusRTU转profibusDP网关与RAC400通讯报文解析
  • 动态规划---路径问题
  • 【分库分表】理论基础
  • 基于python 实现的对一系列给定点进行 Akima 插值
  • 确定性推理 归结
  • Python类与对象:面向对象编程的基础
  • Ollama学习1:安装、命令、API
  • LLM基础-什么是大模型推理(LLM Inferencing)
  • 鸿蒙开发:了解$$运算符
  • STL的map和set(关联式容器深度解析)
  • C语言指针进阶
  • Python类属性与实例属性的覆盖机制:从Vector2d案例看灵活设计
  • 力扣HOT100之回溯:78. 子集