首页 > 编程语言 >【C/C++】实现高性能日志轮转功能,已实测

【C/C++】实现高性能日志轮转功能,已实测

时间:2024-06-17 23:58:27浏览次数:22  
标签:文件 轮转 log 压缩 C++ file 日志 include

基本实现

在C语言中实现日志文件轮转功能,你需要手动编写代码来处理文件的重命名、压缩和删除。下面是一个简单的C语言程序示例,它演示了如何实现基本的日志文件轮转功能。这个程序会检查日志文件的大小,如果超过预设的大小限制,则将当前日志文件重命名,并创建一个新的日志文件。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>

#define LOG_FILE "myapp.log"
#define MAX_LOG_SIZE 1024 * 1024 // 1MB
#define LOG_FILE_SUFFIX ".log"

void rotate_log_file(const char *log_file) {
    // 获取当前日志文件的大小
    struct stat file_stat;
    if (stat(log_file, &file_stat) == -1) {
        perror("stat");
        return;
    }

    // 如果文件大小超过限制,则进行轮转
    if (file_stat.st_size >= MAX_LOG_SIZE) {
        char new_log_file[1024];
        // 生成新的日志文件名
        snprintf(new_log_file, sizeof(new_log_file), "%s.%ld", log_file, time(NULL));

        // 重命名当前日志文件
        if (rename(log_file, new_log_file) == -1) {
            perror("rename");
            return;
        }

        // 创建新的日志文件
        FILE *new_log = fopen(log_file, "w");
        if (new_log == NULL) {
            perror("fopen");
            return;
        }
        fclose(new_log);
    }
}

int main() {
    // 检查并轮转日志文件
    rotate_log_file(LOG_FILE);

    // 打开日志文件并写入日志信息
    FILE *log = fopen(LOG_FILE, "a");
    if (log == NULL) {
        perror("fopen");
        return 1;
    }

    // 写入日志信息
    fprintf(log, "This is a log message at %s\n", ctime(&time(NULL)));
    fclose(log);

    return 0;
}

这个程序首先定义了日志文件的名称和最大大小限制。rotate_log_file函数负责检查当前日志文件的大小,并在必要时进行轮转。如果当前日志文件的大小超过了预设的限制,它会将当前日志文件重命名为包含当前时间戳的新文件名,并创建一个新的空日志文件。

main函数中,我们调用rotate_log_file来轮转日志文件,然后打开日志文件并写入一条新的日志信息。

实现压缩文件,并删除旧日志文件子功能

在C语言中压缩旧日志文件时,需要考虑读写同步问题,以确保在压缩过程中不会丢失数据或损坏文件。通常,压缩旧日志文件的步骤如下:

  1. 关闭当前日志文件:在压缩之前,确保当前正在写入的日志文件被关闭,以避免在压缩过程中写入数据。

  2. 重命名旧日志文件:将旧日志文件重命名为一个临时名称,这样可以避免在压缩过程中其他进程尝试写入该文件。

  3. 压缩文件:使用压缩工具(如gzipbzip2等)对重命名后的旧日志文件进行压缩。

  4. 删除旧日志文件:压缩完成后,删除原始的旧日志文件。

  5. 重命名压缩文件:将压缩后的文件重命名为旧日志文件的名称。

  6. 重新打开日志文件:重新打开日志文件,以便继续写入新的日志信息。

下面是一个简单的C语言示例,演示了如何压缩旧日志文件:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>

#define LOG_FILE "myapp.log"
#define LOG_FILE_SUFFIX ".log"
#define COMPRESSED_LOG_SUFFIX ".gz"

void compress_old_log_file(const char *log_file) {
    char temp_file[1024];
    char compressed_file[1024];

    // 1. 关闭当前日志文件
    fclose(fopen(log_file, "a"));

    // 2. 重命名旧日志文件
    snprintf(temp_file, sizeof(temp_file), "%s.%ld", log_file, time(NULL));
    if (rename(log_file, temp_file) != 0) {
        perror("Error renaming log file");
        return;
    }

    // 3. 压缩文件
    snprintf(compressed_file, sizeof(compressed_file), "%s%s", temp_file, COMPRESSED_LOG_SUFFIX);
    int ret = system((char *)("gzip " COMPRESSED_LOG_SUFFIX " " temp_file));
    if (ret != 0) {
        perror("Error compressing log file");
        return;
    }

    // 4. 删除旧日志文件
    if (remove(temp_file) != 0) {
        perror("Error removing uncompressed log file");
        return;
    }

    // 5. 重命名压缩文件
    if (rename(compressed_file, log_file) != 0) {
        perror("Error renaming compressed log file");
        return;
    }
}

int main() {
    // 假设这是日志轮转的触发点
    compress_old_log_file(LOG_FILE);

    // 重新打开日志文件
    FILE *log = fopen(LOG_FILE, "a");
    if (log == NULL) {
        perror("Error opening log file");
        return 1;
    }

    // 写入新的日志信息
    fprintf(log, "This is a new log entry after compression.\n");
    fclose(log);

    return 0;
}

在上述代码中,compress_old_log_file函数负责压缩旧日志文件。它首先关闭当前的日志文件,然后重命名旧日志文件,接着调用gzip命令压缩文件,最后删除旧日志文件并重命名压缩后的文件。

请注意,使用system函数调用外部命令(如gzip)可能会带来安全风险,特别是如果日志文件名来自不可信的输入。在生产环境中,应使用更安全的方法来执行压缩,例如使用popenpclose函数,或者直接调用压缩库的API。

此外,压缩操作应该在日志文件不被频繁写入的时候执行,以避免读写同步问题。如果日志文件在压缩过程中仍然被写入,可能会导致压缩后的文件损坏。因此,压缩操作通常在日志文件轮转时执行,此时日志文件被关闭,不再有新的写入操作。

如何确保压缩过程中的数据完整性

确保压缩过程中的数据完整性涉及多个方面,包括文件的完整性、压缩过程的正确性以及压缩后文件的可用性。以下是一些确保数据完整性的最佳实践:

  1. 文件完整性检查

    • 在压缩之前,确保原始日志文件没有损坏。可以使用校验和(如MD5、SHA-1等)来验证文件的完整性。
    • 在压缩过程中,确保没有外部因素(如磁盘错误、电源故障等)导致数据损坏。
  2. 压缩工具的选择

    • 使用可靠的压缩工具,如gzipbzip2xz,这些工具都经过了广泛测试,能够正确地压缩和解压数据。
    • 确保压缩工具的版本是最新的,以避免已知的安全漏洞。
  3. 压缩过程中的错误处理

    • 在压缩过程中,捕获并处理可能出现的错误,例如磁盘空间不足、文件权限问题等。
    • 如果压缩过程中发生错误,应记录错误信息,并采取适当的恢复措施,如重新压缩或通知管理员。
  4. 压缩后的文件验证

    • 压缩完成后,可以使用校验和来验证压缩文件的完整性。
    • 如果压缩工具支持,可以使用内置的校验功能来验证压缩文件的完整性。
  5. 备份和恢复计划

    • 在压缩之前,确保有备份机制,以便在压缩失败或数据损坏时能够恢复数据。
    • 定期测试备份和恢复流程,确保它们在需要时能够正常工作。
  6. 日志记录

    • 在压缩过程中记录详细的日志,包括操作的开始和结束时间、任何发生的错误以及压缩文件的大小等信息。
    • 日志记录有助于事后分析和问题诊断。
  7. 权限和安全

    • 确保压缩过程中的文件和目录具有适当的权限,以防止未授权访问。
    • 如果使用外部压缩工具,确保这些工具的安全性,避免执行恶意代码。
  8. 自动化和监控

    • 将压缩过程自动化,并通过监控工具监控压缩过程的状态。
    • 如果压缩过程失败或长时间未完成,自动触发警报。

标签:文件,轮转,log,压缩,C++,file,日志,include
From: https://blog.csdn.net/qq_37286579/article/details/139757378

相关文章

  • LeetCode 算法: 环形链表 c++
    原题链接......
  • C++的动态内存管理
    C++的new和delete一、C与C++的内存管理以及分配二、C++中的new和delete1、new/new[]和delete/delete[]的用法2、new和delete对于内置类型和自定义类型的区别三、new和delete的底层原理1、全局的operatornew和全局的operatordelete2、对于内置类型和自定义类型两个全局......
  • [C++][数据结构][红黑树]详细讲解
    目录1.红黑树的概念2.红黑树的性质3.红黑树节点的定义4.红黑树的结构5.红黑树的插入操作1.cur为红,p为红,g为黑,u存在且为红2.cur为红,p为红,g为黑,u不存在/u存在且为黑--单旋+变色3.cur为红,p为红,g为黑,u不存在/u存在且为黑--双旋+变色6.红黑树的迭代器1.begin()与end()2.o......
  • c# 调用 c++代码
    摘要需要三个项目c++代码CPPProjectc++包装器CPPWrapc#包装器CSharpWrapCPPWrap创建c++动态链接库项目配置属性-高级-C+/CLI属性,依次设置公共语言运行时支持、.NET目标框架(设置为需要的.net环境对应的版本即可)调整公共语言运行时调整项目属性-C/C++-语......
  • 埃氏筛+欧拉筛 (c++)
    求出从2到n的素数埃氏筛方法:筛2的倍数,3的倍数,4的倍数......时间复杂度:O(n·loglogn)缺点:一个数筛了多次,比如6会被2筛,被3筛,被6筛,浪费时间下面的代码中,f是是否是素数的标记数组,N是要筛的个数f[1]=1;for(inti=2;i*i<=N;i++)if(f[i]==0){for(intj=i+i;......
  • c++万能头文件
    一、问题出现c/C++使用首先就是要开头头文件的引用,没有写头文件的程序基本都不会成功运行得到想要的结果,因为每个程序基本都避免不了一定的输入与输出,而输入与输出却在头文件#include/#include<stdio.h>中大量的库函数扑面而来,随之产生了一个很令人头疼的问题,每一种类型的函......
  • C++11智能指针 unique_ptr、shared_ptr、weak_ptr与定制删除器
    目录智能指针场景引入-为什么需要智能指针?内存泄漏什么是内存泄漏内存泄漏的危害内存泄漏分类如何避免内存泄漏智能指针的使用及原理RAII简易例程智能指针的原理智能指针的拷贝问题智能指针的发展历史std::auto_ptr模拟实现auto_ptr例程:这种方案存在的问题:Boost库中的智能指针......
  • UE4 C++ AI实现跳跃(上下平台)
    NavLinkProxyPointLink:点对点,不提供可处理的事件SmartLink:提供可处理的事件,当AI到达Link位置时,可以接受函数通过ReceiveSmartLinkReached事件进行绑定函数操作实现简单的跳跃通过接口,定义函数,在AI基类中进行实现。主要通过两个函数实现UGameplayStatics::SuggestPro......
  • 跟我从零开始学C++(C++代码基础)
    引言小伙伴们是不是都等不及了,来啦来啦它来啦,在经历过前边那么多乱七八糟的但又重要的知识后,终于迎来了有关C++代码的这一步,真是不容易呀,小伙伴们,本章小雨会带着大家去从下载软件到一些简单的基础知识,放轻松~不过本章全程干货一点都不能错过呀,而且附带的Visualstudio的详......
  • 跟我从零开始学C++(C++代码基础)3
    引言小伙伴们大家好呀,又到了每日学习的时候了,今天小杨同学给大家带来了新的知识点哟,大家准备好了么,昨天学习的任务有没有消化好呢,昨天的课后练习怎么样了呢,有没有费了一番功夫弄出来呢。没有把基础打好的小伙伴们千万不要着急呀,毕竟根基不牢是要出大事情的,小伙伴们加油呀,跟......