C语言项目:利用文件操作实现日志记录的功能

本文描述了一个软件日志模块的设计,包括日志初始化、级别控制、文件结构、不同级别的日志格式以及代码示例。它强调了每天生成新文件、按级别记录和文件路径管理的功能。
摘要由CSDN通过智能技术生成

项目简介:

        在软件运行中都需要使用日志模块,该模块主要负责记录软件运行状态,记录软件出错的信息提示,方便开发人员对软件运行状态和出错信息进行分,日志记录就是将一些软件信息记录到文件中。

=========================================================================

设计一个日志记录模块具备以下功能:

1.基本功能,封装三个函数:  

        int LogInit(const char *plogpath);
        日志初始化,打开一个日志文件

        int LogWrite(int level, char *pcontent);
        按照日志文件格式,向日志文件中写入信息
            1.如何写入时间
            2.如何写入告警级别
            3.如何写入用户信息
            4.是否需要切换当前写入的文件

        int LogDeinit(void)
        关闭日志文件

        int LogSetLevel(int level);
        设定日志的级别,如果用户打印的日志级别超过设定日志级别,则写入文件中,如果没有超过则不写入

        int LogTreePrint(void)
        将所有日志文件路径信息打印在终端界面上(目录的遍历)

2.每天一个文件记录日志信息,分文件夹对日志信息存储

    Log-----20231130
        |   |---debug_20231130.log
        |---20231201 
        |   |---debug_20231201.log
        |---20231202 
            |---debug_20231202.log

        debug_日期.log 

 3.要求日志分级别:
        严重错误
        告警
        通知
        信息

4.日志文件中要求格式为:
        [年-月-日 时-分-秒][日志级别]用户打印内容

5.可以通过函数接口查看所有日志文件的文件名及路径信息

=========================================================================

代码示例:日志(itea_log.c)

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

char warn[128] = {0};
FILE *fp = NULL;
char logfilepath[1024] = {0};

/* 日志初始化 */
int LogInit(const char *plogpath)
{
    int net = 0;
    char tmpbuff[1024] = {0};
    char pathname[1024] = {0};
    time_t t;
    struct tm *ptm = NULL;
   
    time(&t);
    ptm = localtime(&t);
    sprintf(tmpbuff, "%04d%02d%02d", ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday);  
    sprintf(pathname, "%s/%s", plogpath, tmpbuff);
    
    if (!access(plogpath, F_OK))
    {
        printf("目录%s已存在\n", plogpath);
    }
    else
    {
        net = mkdir(plogpath, 0777);
        if (0 == net)
        {
            printf("日志目录%s创建成功\n", plogpath);
        }
        else
        {
            printf("日志目录%s创建失败\n", plogpath);
        }
    }
    
    if (!access(pathname, F_OK))
    {
        printf("目录%s已存在\n", pathname);
    }
    else
    {
        net = mkdir(pathname, 0777);
        if (0 == net)
        {
            printf("日志目录%s创建成功\n", pathname);
        }
        else
        {
            printf("日志目录%s创建失败\n", pathname);
        }
    }
    
    sprintf(logfilepath, "%s/debug_%s.log", pathname, tmpbuff);
    fp = fopen(logfilepath, "w");
    if (NULL == fp)
    {
        perror("fail to fopen");
        return -1;
    }

    fprintf(fp, "=========================================================\n");
    fprintf(fp, "+                                                       +\n");
    fprintf(fp, "+                                                       +\n");
    fprintf(fp, "+                      日志开始执行!                    +\n");
    fprintf(fp, "+                                                       +\n");
    fprintf(fp, "+                                                       +\n");
    fprintf(fp, "=========================================================\n");

    fclose(fp);
    return 0;
}

/* 日志级别设置 */
int LogSetLevel(int level)
{
    switch (level)
    {
        case 0:
            strcpy(warn, "信息"); 
            break;
        case 1:
            strcpy(warn, "通知!"); 
            break;
        case 2:
            strcpy(warn, "告警!!"); 
            break;
        case 3:
            strcpy(warn, "严重警告!!!"); 
            break;
        default:
            strcpy(warn, "!!!---未知信号---!!!");
            break;
    }
    return 0;
}

/* 日志写入 */
int LogWrite(int level, char *pcontent)
{
    time_t t;
    struct tm *ptm = NULL;

    time(&t);    
    ptm = localtime(&t);
    
    fp = fopen(logfilepath, "a");
    if (NULL == fp)
    {
        perror("fail to fopen");
        return -1;
    }
    
    LogSetLevel(level);

    if (-1 < level)  // 通过调整比较参数,调节写入范围
    {
        fprintf(fp, "【%04d-%02d-%02d %02d:%02d:%02d】[%s]%s\n", ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, warn, pcontent);
    }
    return 0;
}

/* 关闭日志文件 */
int LogDeinit(void)
{
    fclose(fp);
    return 0;
}

/* 日志目录打印  */
int LogTreePrint(char *pfilepath)
{
    DIR *dp = NULL;
    struct dirent *pp = NULL;
    char tmpbuff[1024] = {0};

    dp = opendir(pfilepath);
    if (NULL == dp)
    {
        perror("fail to opendir");
        return -1;
    }

    while (1)
    {
        pp = readdir(dp);
        if (NULL == pp)
        {
            break;
        }

        if ('.' == *pp->d_name)
        {
            continue;
        }

        sprintf(tmpbuff, "%s/%s", pfilepath, pp->d_name);
        printf("%s\n", tmpbuff);
        
        if (DT_DIR == pp->d_type)
        {
            LogTreePrint(tmpbuff);  //递归调自身
        }
    }

    closedir(dp);
    return 0;
}

int main(void)
{
    LogInit("Log");
    LogWrite(0, "LogInit.................ok");
    LogDeinit();
    LogWrite(0, "LogDeinit.................ok");
    LogTreePrint("Log");
    LogWrite(0, "LogTreePrint.................ok");
    return 0;
}

=========================================================================

代码优化:(Log.c) + (Log.h) + (main.c) + (makefile)

[ Log.c ]

#include"Log.h"

static FILE *fp = NULL;
Loglevel_t gCurLoglevel = LOG_MESSAGE;
Data_t FileDate;

/* 日志初始化 */
int LogInit(void)
{
    time_t t;
    struct tm *ptm = NULL;
    char dirpath[1024] = {0};
    char filepath[1024] = {0};
    char tmpbuff[1024] = {0};
    
    time(&t);
    ptm = localtime(&t);
    
    sprintf(tmpbuff, "%04d%02d%02d", ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday);  
    sprintf(dirpath, "%s/%s", LOG_PATH, tmpbuff); 
    sprintf(filepath, "%s/debug_%s.log", dirpath, tmpbuff);
   
    mkdir(LOG_PATH, 0777);  //创建目录
    mkdir(dirpath, 0777);   //创建子目录
    
    FileDate.year = ptm->tm_year + 1900;
    FileDate.mon = ptm->tm_mon + 1;
    FileDate.day = ptm->tm_mday;
    
    fp = fopen(filepath, "a");
    if (NULL == fp)
    {
        return -1;
    }

    fprintf(fp, "+=======================================================+\n");
    fprintf(fp, "+                                                       +\n");
    fprintf(fp, "+                                                       +\n");
    fprintf(fp, "+                      日志开始执行!                    +\n");
    fprintf(fp, "+                                                       +\n");
    fprintf(fp, "+                                                       +\n");
    fprintf(fp, "+=======================================================+\n\n\n");

    return 0;
}

/* 关闭日志文件 */
int LogDeinit(void)
{
    fprintf(fp, "+=======================================================+\n");
    fprintf(fp, "                  +---------------------+                \n");
    fprintf(fp, "+                 |                     |               +\n");
    fprintf(fp, "------------------+    日志记录结束!    +----------------\n");
    fprintf(fp, "+                 |                     |               +\n");
    fprintf(fp, "                  +---------------------+                \n");
    fprintf(fp, "+=======================================================+\n\n\n");
    if (NULL != fp)
    {
        fclose(fp);
        fp = NULL;
    }

    return 0;
}

/* 日志写入 */
int LogWrite(Loglevel_t level, char *pcontent, ...)
{
    time_t t;
    struct tm *ptm = NULL;
    va_list ap;
    char *perrorstr[4] = {"严重警告", "错误", "告警", "消息"};

    if (NULL == fp)
    {
        return 0;
    }

    if (level > gCurLoglevel)
    {
        return 0;
    }

    time(&t);    
    ptm = localtime(&t);

    if (FileDate.year != ptm->tm_year + 1900 | FileDate.mon != ptm->tm_mon + 1 | FileDate.day != ptm->tm_mday)
    {
        LogDeinit();
        LogInit();
    }

    fprintf(fp, "【%04d-%02d-%02d %02d:%02d:%02d】【%s】", ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, perrorstr[level]);
    
    va_start(ap, pcontent);
    vfprintf(fp, pcontent, ap);
    va_end(ap); 
    fflush(fp);
    return 0;
}

/* 日志级别设置 */
int LogSetLevel(Loglevel_t level)
{
    LogWrite(LOG_FATAL, "日志等级切换为:%d -> %d\n", gCurLoglevel, level);
    gCurLoglevel = level;
    
    return 0;
}

[ Log.h ]

#ifndef _LOG_H
#define _LOG_H

#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<dirent.h>
#include<sys/stat.h>
#include<stdarg.h>
#include<time.h>

#define LOG_PATH "./Log"

/* 日志级别 */
typedef enum Loglevel
{
    LOG_FATAL,        //严重错误(0)
    LOG_ERROR,        //错误(1)
    LOG_WARNING,      //告警(2)
    LOG_MESSAGE       //消息(3)
}Loglevel_t;

/* 日期记录
 * 考虑到程序可能长时间运行,用于比对更新日志
 */
typedef struct data
{
    int year;
    int mon;
    int day;
}Data_t;

extern int LogInit(void);
extern int LogWrite(Loglevel_t level, char *pcontent, ...);
extern int LogDeinit(void);
extern int LogSetLevel(Loglevel_t level);

#endif

[ main.c ]

#include <stdio.h>
#include "Log.h"

int main(int argc, const char *argv[])
{
	int ret = 0;
	int Num = 100;
    int count = 0;

	ret = LogInit();
	if (-1 == ret)
	{
		fprintf(stderr, "log system init failed\n");
	}
	
	while (1)
	{
		LogWrite(LOG_MESSAGE, "软件开始运行\n");
		sleep(1);
        count++;
		LogWrite(LOG_MESSAGE, "Num = %d\n", Num);
		sleep(1);
        count++;
		LogWrite(LOG_WARNING, "CPU温度过高\n");
		sleep(1);
        count++;
		LogWrite(LOG_FATAL, "CPU温度超过200度,软件关闭\n");
		sleep(1);
        count++;

        if (4 == count)
        {
            break;
        }
	}

	LogDeinit();

	return 0;
}

[ makefile ]

app:main.c Log.c 
    gcc main.c Log.c -o app 

.PHONY:  
clean:   
    rm app
 

  • 9
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值