免责声明:以下程序仅供自己参考使用,如果有好的编程建议,可以提出,感激不尽
1、简易日志系统介绍
上级扔给我一个模块的开发任务,我想用自己的日志系统,记录所有有关我的模块的信息,当然这个日志系统存在性能问题,也不够完善,但是对于小项目来说或者对于我来说,也勉强能够使用,后面再考虑性能优化问题
主要有三个文件
- com_trace.h 日志接口声明,使用时包含此文件
- com_logfile_writer.cpp 相关函数实现
- 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