1、个人日志系统(1)

本文介绍了作者为模块开发自定义的日志系统,包括接口声明、写文件类的实现,以及如何配置和使用该系统生成日志。讨论了可能的性能问题和后续优化计划。
摘要由CSDN通过智能技术生成

免责声明:以下程序仅供自己参考使用,如果有好的编程建议,可以提出,感激不尽

1、简易日志系统介绍

上级扔给我一个模块的开发任务,我想用自己的日志系统,记录所有有关我的模块的信息,当然这个日志系统存在性能问题,也不够完善,但是对于小项目来说或者对于我来说,也勉强能够使用,后面再考虑性能优化问题

主要有三个文件

  1. com_trace.h 日志接口声明,使用时包含此文件
  2. com_logfile_writer.cpp 相关函数实现
  3. com_logfile_writer.h 写文件的类

2、源码配置及解析

首先是接口,使用该日志记录时应包含此文件头

// com_trace.h

#ifndef COM_TRACE_H
#define COM_TRACE_H

#include <sstream>
#include <string>

#include "com_def.h"

#ifdef __cplusplus
extern "C" {
#endif

	typedef enum
	{
		COM_LOG_NO_OUTPUT = -1,

		COM_LOG_ERROR = 0,
		COM_LOG_LEVEL0 = COM_LOG_ERROR,

		COM_LOG_WARNING = 1,
		COM_LOG_LEVEL1 = COM_LOG_WARNING,

		COM_LOG_INFO = 2,
		COM_LOG_LEVEL2 = COM_LOG_INFO,

		COM_LOG_LEVEL3,
		COM_LOG_LEVEL4,
		COM_LOG_LEVEL5,
		COM_LOG_LEVEL_MAX
	}LogProfile;

	struct LogConfigContext
	{
		unsigned int max_linesize;		// 每行最大字节数
		unsigned long long max_filesize;// 每个文件的最大字节数
		unsigned int max_filecount;		// 日志文件的最大个数
		LogProfile output_limit;		// 仅输出小于等于output_limit等级的日志信息
		const char* path_prefix;		// 日志输出路径前缀 "../output/"
		const char* path_body;			// 日志输出路径文件名		"output_file"
		const char* path_surfix;		// 日志输出路径后缀	".log"
										// "../output/output_file_0.log"
		unsigned int slice_flush;		// 每n条刷新一次
	};


	void InitLogSystem(LogConfigContext* ctx = NULL);

	void WriteLineToFile(
		const char* file,
		const char* func,
		unsigned int line,
		const char* data,
		LogProfile level);

#ifdef __cplusplus
}
#endif

#ifdef DEBUG_DXVA
#define LOG_WRITE_TO_FILE(level, data)		\
{											\
	std::stringstream ss;					\
	ss << data << std::endl;				\
	WriteLineToFile(						\
		__FILE__,							\
		__func__,							\
		__LINE__,							\
		ss.str().c_str(),					\
		level);								\
}											

#else
#define LOG_WRITE_TO_FILE(level, str)
#endif

#define trace_info(str)		LOG_WRITE_TO_FILE(COM_LOG_INFO, str)
#define trace_warning(str)	LOG_WRITE_TO_FILE(COM_LOG_WARNING, str)
#define trace_error(str)	LOG_WRITE_TO_FILE(COM_LOG_ERROR, str)

#endif

然后是具体的写文件类,主要是做一些文件满了重新打开新的文件的操作,以及常规的写入功能

//com_logfile_writer.h

#ifndef COM_LOGFILE_WRITER_H
#define COM_LOGFILE_WRITER_H

#include <string>
#include <sstream>
#include <mutex>

#include "com_trace.h"

 class LogFileWriter
{
public:
	static LogFileWriter& Instance();

	LogFileWriter();

	~LogFileWriter();

	 void InitFileWriter(LogConfigContext* ctx);

	 void WriteLineToFile(const char* str, unsigned int size, LogProfile level);

	 void ResetLevel(LogProfile level);

	 LogProfile GetLevel();

	 const char* TransTypeToStr(LogProfile profile);

private:
	unsigned int max_linesize;		// 每行最大字节数
	unsigned int max_filecount;		// 日志文件的最大个数
	unsigned int filecount;
	unsigned int slice_flush;		// 每n条刷新一次
	unsigned int slices;
	unsigned long long max_filesize;// 每个文件的最大字节数
	unsigned long long filesize;
	unsigned int status;
	
	LogProfile output_limit;		// 仅输出小于等于output_limit等级的日志信息
	std::string path_prefix;		// 日志输出路径前缀 "../output/"
	std::string path_body;			// 日志输出路径文件名		"output_file"
	std::string path_surfix;		// 日志输出路径后缀	".log"

	FILE* file_handle;
	std::mutex lock_mutex;

	void OpenFile();
	void CloseFile();
	void CheckFileSize();
};

#endif


最后是所有相关函数体的实现

// com_logfile_writer.cpp

#include "com_logfile_writer.h"
#include "com_trace.h"

LogFileWriter& LogFileWriter::Instance()
{
	static LogFileWriter instance;
	return instance;
}

void InitLogSystem(LogConfigContext* ctx)
{
	LogConfigContext log_context;
	if (!ctx)
	{
		ctx = &log_context;
		ctx->max_filecount = 5;
		ctx->max_filesize = 10 * 1024 * 1024;
		ctx->max_linesize = 4096;
		ctx->output_limit = COM_LOG_INFO;
		ctx->path_prefix = "./test/";
		ctx->path_body = "dxva_internal";
		ctx->path_surfix = ".log";
		ctx->slice_flush = 1;
	}

	LogFileWriter::Instance().InitFileWriter(ctx);
}

void WriteLineToFile(
	const char* file,
	const char* func,
	unsigned int line,
	const char* data,
	LogProfile level)
{
	std::stringstream ss;
	const char* level_text = LogFileWriter::Instance().TransTypeToStr(level);

	ss << level_text
		<< "[FILE]:" << file
		<< ", [FUNC]:" << func
		<< ", [LINE]:" << line
		<< ", "									
		<< data;
	LogFileWriter::Instance().WriteLineToFile(ss.str().c_str(), ss.str().size(), level);
}

LogFileWriter::LogFileWriter()
{

}

LogFileWriter::~LogFileWriter()
{
	CloseFile();
}

void LogFileWriter::InitFileWriter(LogConfigContext* ctx)
{
	max_linesize = ctx->max_linesize;
	max_filecount = ctx->max_filecount;
	slice_flush = ctx->slice_flush;
	max_filesize = ctx->max_filesize;
	output_limit = ctx->output_limit;
	path_prefix = ctx->path_prefix;
	path_body = ctx->path_body;
	path_surfix = ctx->path_surfix;

	filecount = 0;
	filesize = 0;
	status = 0;
	slices = 0;
	file_handle = NULL;

	OpenFile();
}

void LogFileWriter::OpenFile()
{
	if (file_handle == NULL)
	{
		std::string path;
		path += path_prefix;
		path += path_body;
		path += "_";
		path += std::to_string(filecount);
		path += path_surfix;
		filecount++;
		if (filecount > max_filecount)
		{
			status = 1;
			return;
		}
		fopen_s(&file_handle, path.c_str(), "wb");

	}
}

void LogFileWriter::CloseFile()
{
	if (file_handle)
	{
		fclose(file_handle);
		file_handle = NULL;
	}
	filesize = 0;
}

void LogFileWriter::WriteLineToFile(const char* str, unsigned int size, LogProfile level)
{
	std::lock_guard<std::mutex> lock(lock_mutex);

	if (status)
	{
		return;
	}
	if (level > output_limit || level == COM_LOG_NO_OUTPUT)
	{
		return;
	}
	if (size > max_linesize)
	{
		size = max_linesize;
	}
	size_t len = fwrite(str, 1, size, file_handle);
	filesize += len;
	slices++;
	if (slices >= slice_flush)
	{
		slices = 0;
		fflush(file_handle);
	}

	CheckFileSize();
}

void LogFileWriter::ResetLevel(LogProfile level)
{
	if (level >= COM_LOG_NO_OUTPUT && level < COM_LOG_LEVEL_MAX)
	{
		output_limit = level;
	}
}

LogProfile LogFileWriter::GetLevel()
{
	return output_limit;
}

const char* LogFileWriter::TransTypeToStr(LogProfile profile)
{
	const char* str = NULL;
	switch (profile)
	{
	case COM_LOG_ERROR:
		str = "[ERROR] ";
		break;
	case COM_LOG_WARNING:
		str = "[WARNING] ";
		break;
	case COM_LOG_INFO:
		str = "[INFO] ";
		break;
	default:
		str = "";
		break;
	}
	return str;
}


void LogFileWriter::CheckFileSize()
{
	if (filesize > max_filesize)
	{
		const char* end_str = "end of file";
		fwrite(end_str, 1, strlen(end_str), file_handle);
		fflush(file_handle);
		// should change file
		CloseFile();
		OpenFile();
	}
}


最后简单演示一下如何使用

// 首先包含头文件
#include "com_trace.h"	

// 然后在主程序中初始化,如果LogConfigContext
int main()
{
    //1、如果什么都不填,或者填NULL,那么会走默认的配置选项,详情参看上面的源码
    InitLogSystem();
    
    //2、也可以填写配置结构体,按照需求配置参数
    //LogConfigContext conf_ctx;
    //conf_ctx.max_filecount = 5;
    //conf_ctx.max_filesize = 10 * 1024 * 1024;
    //conf_ctx.max_linesize = 4096;
    //conf_ctx.output_limit = COM_LOG_INFO;
    //conf_ctx.path_prefix = "./file_path/";
    //conf_ctx.path_body = "log_name";
    //conf_ctx.path_surfix = ".log";
    //conf_ctx.slice_flush = 1;
    //InitLogSystem(&conf_ctx);
    
    // 然后就可以正常调用了,例如:
    int a = 10;
    double b = 3.14;
    std::string str="string str";
    trace_error("error find!");
    trace_info("hello world" << a << b);
    trace_warning("");
    trace_info("a=" << a << ",b=" << b);
    return 0;
}

最后放一些我使用输出的日志:

[INFO] [FILE]:f:\desktop\project\matest_multi_slice\src\backend\windows\com_dxva2.cpp, [FUNC]:DecodeFrame, [LINE]:432, [DXVA] time cost:15
[INFO] [FILE]:f:\desktop\project\matest_multi_slice\src\backend\windows\com_dxva2.cpp, [FUNC]:DecodeFrame, [LINE]:432, [DXVA] time cost:16
[INFO] [FILE]:f:\desktop\project\matest_multi_slice\src\backend\windows\com_dxva2.cpp, [FUNC]:DecodeFrame, [LINE]:432, [DXVA] time cost:16
[INFO] [FILE]:f:\desktop\project\matest_multi_slice\src\backend\windows\com_dxva2.cpp, [FUNC]:DecodeFrame, [LINE]:432, [DXVA] time cost:16
[INFO] [FILE]:f:\desktop\project\matest_multi_slice\src\backend\windows\com_dxva2.cpp, [FUNC]:DecodeFrame, [LINE]:432, [DXVA] time cost:15
[INFO] [FILE]:f:\desktop\project\matest_multi_slice\src\backend\windows\com_dxva2.cpp, [FUNC]:DecodeFrame, [LINE]:432, [DXVA] time cost:15
[INFO] [FILE]:f:\desktop\project\matest_multi_slice\src\backend\windows\com_dxva2.cpp, [FUNC]:DecodeFrame, [LINE]:432, [DXVA] time cost:16
[INFO] [FILE]:f:\desktop\project\matest_multi_slice\src\backend\windows\com_dxva2.cpp, [FUNC]:DecodeFrame, [LINE]:432, [DXVA] time cost:15
[INFO] [FILE]:f:\desktop\project\matest_multi_slice\src\backend\windows\com_dxva2.cpp, [FUNC]:DecodeFrame, [LINE]:432, [DXVA] time cost:15
[INFO] [FILE]:f:\desktop\project\matest_multi_slice\src\backend\windows\com_dxva2.cpp, [FUNC]:DecodeFrame, [LINE]:432, [DXVA] time cost:15
[INFO] [FILE]:f:\desktop\project\matest_multi_slice\src\backend\windows\com_dxva2.cpp, [FUNC]:DecodeFrame, [LINE]:432, [DXVA] time cost:15
[INFO] [FILE]:f:\desktop\project\matest_multi_slice\src\backend\windows\com_dxva2.cpp, [FUNC]:DecodeFrame, [LINE]:432, [DXVA] time cost:15
[INFO] [FILE]:f:\desktop\project\matest_multi_slice\src\backend\windows\com_dxva2.cpp, [FUNC]:DecodeFrame, [LINE]:432, [DXVA] time cost:14
[INFO] [FILE]:f:\desktop\project\matest_multi_slice\src\backend\windows\com_dxva2.cpp, [FUNC]:DecodeFrame, [LINE]:432, [DXVA] time cost:15
[INFO] [FILE]:f:\desktop\project\matest_multi_slice\src\backend\windows\com_dxva2.cpp, [FUNC]:DecodeFrame, [LINE]:432, [DXVA] time cost:16
[INFO] [FILE]:f:\desktop\project\matest_multi_slice\src\backend\windows\com_dxva2.cpp, [FUNC]:DecodeFrame, [LINE]:432, [DXVA] time cost:16
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值