项目简介:
在软件运行中都需要使用日志模块,该模块主要负责记录软件运行状态,记录软件出错的信息提示,方便开发人员对软件运行状态和出错信息进行分,日志记录就是将一些软件信息记录到文件中。
=========================================================================
设计一个日志记录模块具备以下功能:
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