C语言 服务器编程-日志系统

引言

日志系统是通过文件来记录项目的 调试信息,运行状态,访问记录,产生的警告和错误的一个系统,是项目中非常重要的一部分. 程序员可以通过日志文件观测项目的运行信息,方便及时对项目进行调整.

最简单的日志类 demo

日志类一般使用单例模式实现:

Log.h:

class Log
{
private:
	
	Log() {};
	~Log();
public:
	bool init(const char* file_name);

	void write_log(const char* str);

	static Log* getinstance();

private:
	FILE* file;
};

Log.cpp:

Log::~Log()
{
	if (file != NULL)
    {
	   fflush(file);
	   fclose(file);
    }
}

Log* Log::getinstance()
{
	static Log instance;
	return &instance;
}

bool Log::init(const char * file_name)
{
	file = fopen(file_name,"a");
	if (file == NULL)
	{
		return false;
	}
	return true;
}

void Log::write_log(const char* str)
{
	if (file == NULL)
		return;

	fputs(str, file);
}

main.cpp:

#include"Log.h"

int main()
{
	Log::getinstance()->init("log.txt");
	Log::getinstance()->write_log("Hello World");
}

这个日志类实现了最简单的写日志的功能,但是实际应用时,需要在日志系统上开发出许多额外的功能来满足工作需要,有些时候还要进行日志的分类操作,因为你不能将所有的日志信息都塞到一个日志文件中,这样会大大降低可读性,接下来讲一下在这个最简单的日志类的基础上,怎么添加一些新功能.

按天日志分类和超行日志分类

先说两个比较简单的
按天分类和超行分类

按天分类:每一个日志按照天来分类(日志前加上当前的日期作为日志的前缀) 并且写日志前检查日志的创建时间,如果日志创建时间不是今天,那么就额外新创建一个日志,更新创建时间和行数,然后向新日志中写日志信息

超行分类:写日志前检查本次程序写入日志的行数,如果当前本次程序写入日志的行数已经到达上限,那么额外创建新的日志,更新创建时间,然后向新日志中写日志信息

为了实现这两个小功能,我们需要先向日志类中添加以下成员:

  1. 程序本次启动,写入日志文件的最大行数
  2. 程序本次启动,已经写入日志的行数
  3. 日志的创建时间
  4. 日志的路径名+文件名(创建新日志的时候,命名要跟之前的命名标准一样,最好是标准日志名+后缀的形式,这样便于标识)

更新后的日志类:

Log.h:

#pragma once
#include<stdio.h>
#include<string.h>
#include<string>
#include<time.h>
using namespace std;

class Log
{
private:
	
	Log() ;
	~Log();
	
public:
	//初始化文件路径,文件最大行数
	bool init(const char* file_name,int split_lines= 5000000);

	void write_log(const char* str);

	static Log* getinstance();

private:
	FILE* file;
	char dir_name[128];//路径名
	char log_name[128];//日志名

	int m_split_lines; //日志文件最大行数(之前的日志行数不计,只记录本次程序启动写入的行数)
	long long m_count; //已经写入日志的行数
	int m_today;       //日志的创建时间
};

Log.cpp

#define _CRT_SECURE_NO_WARNINGS
#include"Log.h"

Log::Log()
{
	m_count = 0;
}

Log::~Log()
{
	if (file != NULL)
	{
		fflush(file);
		fclose(file);
	}
}

Log* Log::getinstance()
{
	static Log instance;
	return &instance;
}

bool Log::init(const char * file_name,int split_lines)
{
	m_split_lines = split_lines;       //设置最大行数

	time_t t = time(NULL);
	struct tm* sys_tm = localtime(&t);
	struct tm  my_tm  = *sys_tm;       //获取当前的时间

	const char* p = strrchr(file_name, '/');//这里需要注意下,windows和linux的路径上的 斜杠符浩方向是不同的,windows是\,linux是 / ,而且因为转义符号的原因,必须是 \\
	char log_full_name[256] = { 0 };

	if (p == NULL)  //判断是否输入了完整的路径+文件名,如果只输入了文件名
	{
	    strcpy(log_name, file_name);
		snprintf(log_full_name, 255, "%d_%02d_%02d_%s", my_tm.tm_year + 1900, my_tm.tm_mon + 1, my_tm.tm_mday, file_name);
	}
	else            //如果输入了完整的路径名+文件名
	{
		strcpy(log_name, p + 1);
		strncpy(dir_name, file_name, p - file_name + 1);
		                              //规范化命名
		snprintf(log_full_name,255, "%s%d_%02d_%02d_%s", dir_name, my_tm.tm_year + 1900, my_tm.tm_mon + 1, my_tm.tm_mday, log_name);
	}

	m_today = my_tm.tm_mday;          //更新时间

	file = fopen(log_full_name,"a");  //打开文件,打开方式:追加
	if (file == NULL)
	{
		return false;
	}
	return true;
}

void Log::write_log(const char* str)
{
    if (file == NULL)
	   return;
	   
	time_t t = time(NULL); 
	struct tm* sys_tm = localtime(&t); 
	struct tm  my_tm = *sys_tm;       //获取当前的时间,用来后续跟日志的创建时间作对比

	m_count++;                        //日志行数+1

	if (m_today != my_tm.tm_mday || m_count % m_split_lines == 0) //如果创建时间!=当前时间或者本次写入行数达到上限
	{ 
		char ne
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值