主要提供以下接口:
1、设置写日志的级别 2、写关键日志信息 3、写错误日志信息 4、写警告日志掘清信息 5、写一般日志信息
#ifndef COMMAND_DEFINE_H#define COMMAND_DEFINE_H//日志级别的提示信息static const char * KEYINFOPREFIX = " Key: n"static const char * ERRORPREFIX = "帆散行 Error: n"static const char * WARNINGPREFIX = " Warning: n"static const char * INFOPREFIX = " Info: n"static const int MAX_STR_LEN = 1024//日志级别枚举typedef enum EnumLogLevel{ LogLevelAll = 0, //所有信息都写日志 LogLevelMid, //写错误、警告信息 LogLevelNormal, //只写错误信息 LogLevelStop //不写日志}#endif
#ifndef LOGGER_H_#define LOGGER_H_#include#include#include "CommandDefine.h"/* * 类名:Logger * 作用:提供写日志功能,支持多线程,支持可变形参数 *** 作,支持写日志级别的设置 * 接口:SetLogLevel:设置写日志级别 TraceKeyInfo:忽略日志级别,写关键信息 TraceError:写错误信息 TraceWarning:写警告信息 TraceInfo:写一般信息*/class Logger{public: //默认构造函数 Logger()//构造函数 Logger(const char * strLogPath, EnumLogLevel nLogLevel = EnumLogLevel::LogLevelNormal)//析构函数 virtual ~Logger()public: //写关键信息 void TraceKeyInfo(const char * strInfo, ...)//写错误信息 void TraceError(const char* strInfo, ...)//写警告信息 void TraceWarning(const char * strInfo, ...)//写一般信息 void TraceInfo(const char * strInfo, ...)//设置写日志级别 void SetLogLevel(EnumLogLevel nLevel)private: //写文件 *** 作 void Trace(const char * strInfo)//获取当前系统时间 char * GetCurrentTime()//创建日志文件名称 void GenerateLogName()//创建日志路径 void CreateLogPath()private: //写日志文件流 FILE * m_pFileStream//写日志级别 EnumLogLevel m_nLogLevel//日志的路径 char m_strLogPath[MAX_STR_LEN]//日志的名称 char m_strCurLogName[MAX_STR_LEN]//线程同步的临界区变量 CRITICAL_SECTION m_cs}#endif
#include "Logger.h"#include#include#include#include#pragma comment(lib, "DbgHelp.lib") //默认构造函数Logger::Logger(){ //初始化 memset(m_strLogPath, 0, MAX_STR_LEN)memset(m_strCurLogName, 0, MAX_STR_LEN)m_pFileStream = NULL//设置默认的写日志级别 m_nLogLevel = EnumLogLevel::LogLevelNormal//初始化临界区变量 InitializeCriticalSection(&m_cs)//创建日志文件名 GenerateLogName()} //构造函数Logger::Logger(const char * strLogPath, EnumLogLevel nLogLevel):m_nLogLevel(nLogLevel){ //初始化 m_pFileStream = NULLstrcpy(m_strLogPath, strLogPath)InitializeCriticalSection(&m_cs)CreateLogPath()GenerateLogName()} //析构函数Logger::~Logger(){ //释放临界区 DeleteCriticalSection(&m_cs)//关闭文件流 if(m_pFileStream) fclose(m_pFileStream)} //写关键信息接口void Logger::TraceKeyInfo(const char * strInfo, ...){ if(!strInfo) returnchar pTemp[MAX_STR_LEN] = {0}strcpy(pTemp, GetCurrentTime())strcat(pTemp, KEYINFOPREFIX)//获取可变形参 va_list arg_ptr = NULLva_start(arg_ptr, strInfo)vsprintf(pTemp + strlen(pTemp), strInfo, arg_ptr)va_end(arg_ptr)//写日志文件 Trace(pTemp)arg_ptr = NULL} //写错误信息void Logger::TraceError(const char* strInfo, ...){ //判断当前的写日志级别,若设置为不写日志则函数返回 if(m_nLogLevel >= EnumLogLevel::LogLevelStop) returnif(!strInfo) returnchar pTemp[MAX_STR_LEN] = {0}strcpy(pTemp, GetCurrentTime())strcat(pTemp, ERRORPREFIX)va_list arg_ptr = NULLva_start(arg_ptr, strInfo)vsprintf(pTemp + strlen(pTemp), strInfo, arg_ptr)va_end(arg_ptr)Trace(pTemp)arg_ptr = NULL} //写警告信息void Logger::TraceWarning(const char * strInfo, ...){ //判断当前的'写日志级别,若设置为只写错误信息则函数返回 if(m_nLogLevel >= EnumLogLevel::LogLevelNormal) returnif(!strInfo) returnchar pTemp[MAX_STR_LEN] = {0}strcpy(pTemp, GetCurrentTime())strcat(pTemp, WARNINGPREFIX)va_list arg_ptr = NULLva_start(arg_ptr, strInfo)vsprintf(pTemp + strlen(pTemp), strInfo, arg_ptr)va_end(arg_ptr)Trace(pTemp)arg_ptr = NULL} //写一般信息void Logger::TraceInfo(const char * strInfo, ...){ //判断当前的写日志级别,若设置只写错误和警告信息则函数返回 if(m_nLogLevel >= EnumLogLevel::LogLevelMid) returnif(!strInfo) returnchar pTemp[MAX_STR_LEN] = {0}strcpy(pTemp, GetCurrentTime())strcat(pTemp,INFOPREFIX)va_list arg_ptr = NULLva_start(arg_ptr, strInfo)vsprintf(pTemp + strlen(pTemp), strInfo, arg_ptr)va_end(arg_ptr)Trace(pTemp)arg_ptr = NULL} //获取系统当前时间char * Logger::GetCurrentTime(){ time_t curTimestruct tm * pTimeInfo = NULLtime(&curTime)pTimeInfo = localtime(&curTime)char temp[MAX_STR_LEN] = {0}sprintf(temp, "%02d:%02d:%02d", pTimeInfo->tm_hour, pTimeInfo->tm_min, pTimeInfo->tm_sec)char * pTemp = tempreturn pTemp} //设置写日志级别void Logger::SetLogLevel(EnumLogLevel nLevel){ m_nLogLevel = nLevel} //写文件 *** 作void Logger::Trace(const char * strInfo){ if(!strInfo) returntry { //进入临界区 EnterCriticalSection(&m_cs)//若文件流没有打开,则重新打开 if(!m_pFileStream) { char temp[1024] = {0}strcat(temp, m_strLogPath)strcat(temp, m_strCurLogName)m_pFileStream = fopen(temp, "a+")if(!m_pFileStream) { return} } //写日志信息到文件流 fprintf(m_pFileStream, "%sn", strInfo)fflush(m_pFileStream)//离开临界区 LeaveCriticalSection(&m_cs)} //若发生异常,则先离开临界区,防止死锁 catch(...) { LeaveCriticalSection(&m_cs)}} //创建日志文件的名称void Logger::GenerateLogName(){ time_t curTimestruct tm * pTimeInfo = NULLtime(&curTime)pTimeInfo = localtime(&curTime)char temp[1024] = {0}//日志的名称如:2013-01-01.log sprintf(temp, "%04d-%02d-%02d.log", pTimeInfo->tm_year+1900, pTimeInfo->tm_mon + 1, pTimeInfo->tm_mday)if(0 != strcmp(m_strCurLogName, temp)) { strcpy(m_strCurLogName,temp)if(m_pFileStream) fclose(m_pFileStream)char temp[1024] = {0}strcat(temp, m_strLogPath)strcat(temp, m_strCurLogName)//以追加的方式打开文件流 m_pFileStream = fopen(temp, "a+")} } //创建日志文件的路径void Logger::CreateLogPath(){ if(0 != strlen(m_strLogPath)) { strcat(m_strLogPath, "")} MakeSureDirectoryPathExists(m_strLogPath)}
以上就是本文的全部内容,希望对大家的学习C++有所帮助。
日志的作用非常重要,日志可以记录用户的码罩 *** 作、程序的异常,还可以为数据分析提供依据,日志的存在意义就是为了能够在程序在运行过程中记录错误,方便维护和调试,键模运能够快速定位出错的地方,减少维护成本。每个程序员都应该知道,不是为了记录日志而记录日志,日志也不是随意记的。要实现能够只通过日志文件还原整个程序执行的过程,达到能透明地看到程序里执行情况,每个线程、每个过程到底执行到哪的目的。日志就像飞机的黑匣子一样,应当能够复原异常的整个现场乃至细节!
最常见的是把输出函数 print() 当作日志记录的方式,直接打印各种提示信息,常稿梁见于个人练习项目里,通常是懒得单独配置日志,而且项目太小不需要日志信息,不需要上线,不需要持续运行,完整的项目不推荐直接打印日志信息,现实中也几乎没有人这么做。
我们可以在不少小项目里面看到作者自己写了一个日志模板,通常利用 print() 或者 sys.stdout 稍微封装一下即可实现简单的日志输出,这里的 sys.stdout 是 Python 中的标准输出流, print() 函数是对 sys.stdout 的高级封装,当我们在 Python 中打印对象调用 print(obj) 时候,事实上是调用了 sys.stdout.write(obj+'\n') , print() 将内容打印到了控制台,然后追加了一个换行符 \n 。
自写日志模板适合比较小的项目,可以按照自己的喜好编写模板,不需要太多复杂配置,方便快捷,但是这种记录日志的方式并不是很规范,有可能你自己觉得阅读体验不错,但是别人在接触你的项目的时候往往需要花费一定的时间去学习日志的逻辑、格式、输出方式等,比较大的项目同样不推荐这种方法。
一个简单的自写日志模板举例:
日志模板 log.py:
调用日志模块:
日志输出:
在一个完整的项目中,大多数人都会引入专门的日志记录库,而 Python 自带的标准库 logging 就是专门为日志记录而生的,logging 模块定义的函数和类为应用程序和库的开发实现了一个灵活的事件日志系统。由标准库模块提供日志记录 API 的关键好处是所有 Python 模块都可以使用这个日志记录功能。所以,你的应用日志可以将你自己的日志信息与来自第三方模块的信息整合起来。
logging 模块虽然强大,但是其配置也是比较繁琐的,在大型项目中通常需要单独初始化日志、配置日志格式等等,K哥在日常使用中通常都会对 logging 做如下的封装写法,使日志可以按天保存,保留15天的日志,可以配置是否输出到控制台和文件,如下所示:
输出日志:
它在控制台中是这样的:
当然,如果你不需要很复杂的功能,希望简洁一点,仅仅需要在控制台输出一下日志的话,也可以只进行简单的配置:
对于 logging 模块,即便是简单的使用,也需要自己定义格式,这里介绍一个更加优雅、高效、简洁的第三方模块:loguru,官方的介绍是:Loguru is a library which aims to bring enjoyable logging in Python. Loguru 旨在为 Python 带来愉快的日志记录。这里引用官方的一个 GIF 来快速演示其功能:
Loguru 仅支持 Python 3.5 及以上的版本,使用 pip 安装即可:
Loguru 的主要概念是只有一个:logger
控制台输出:
可以看到不需要手动设置,Loguru 会提前配置一些基础信息,自动输出时间、日志级别、模块名、行号等信息,而且根据等级的不同,还自动设置了不同的颜色,方便观察,真正做到了开箱即用!
如果想自定义日志级别,自定义日志格式,保存日志到文件该怎么办?与 logging 模块不同,不需要 Handler,不需要 Formatter,只需要一个 add() 函数就可以了,例如我们想把日志储存到文件:
我们不需要像 logging 模块一样再声明一个 FileHandler 了,就一行 add() 语句搞定,运行之后会发现目录下 test.log 里面同样出现了刚刚控制台输出的 debug 信息。
与 add() 语句相反, remove() 语句可以删除我们添加的配置:
此时控制台会输出两条 debug 信息:
而 test.log 日志文件里面只有一条 debug 信息,原因就在于我们在第二条 debug 语句之前使用了 remove() 语句。
Loguru 对输出到文件的配置有非常强大的支持,比如支持输出到多个文件,分级别分别输出,过大创建新文件,过久自动删除等等。 下面我们来详细看一下 add() 语句的详细参数:
基本语法:
基本参数释义:
当且仅当 sink 是协程函数时,以下参数适用:
当且仅当 sink 是文件路径时,以下参数适用:
这么多参数可以见识到 add() 函数的强大之处,仅仅一个函数就能实现 logging 模块的诸多功能,接下来介绍几个比较常用的方法。
add() 函数的 rotation 参数,可以实现按照固定时间创建新的日志文件,比如设置每天 0 点新创建一个 log 文件:
设置超过 500 MB 新创建一个 log 文件:
设置每隔一个周新创建一个 log 文件:
add() 函数的 retention 参数,可以设置日志的最长保留时间,比如设置日志文件最长保留 15 天:
设置日志文件最多保留 10 个:
也可以是一个 datetime.timedelta 对象,比如设置日志文件最多保留 5 个小时:
add() 函数的 compression 参数,可以配置日志文件的压缩格式,这样可以更加节省存储空间,比如设置使用 zip 文件格式保存:
其格式支持: gz 、 bz2 、 xz 、 lzma 、 tar 、 tar.gz 、 tar.bz2 、 tar.xz
Loguru 在输出 log 的时候还提供了非常友好的字符串格式化功能,相当于 str.format() :
输出:
在 Loguru 里可以直接使用它提供的装饰器就可以直接进行异常捕获,而且得到的日志是无比详细的:
日志输出:
在控制台的输出是这样的:
相比 Logging,Loguru 无论是在配置方面、日志输出样式还是异常追踪,都远优于 Logging,使用 Loguru 无疑能提升开发人员效率。本文仅介绍了一些常用的方法,想要详细了解可参考 Loguru 官方文档 或关注 Loguru GitHub 。
如果你的文件有包含中文字符那应该这样写StreamReader myr = new StreamReader(@"文件路径",Encoding.GetEncoding("GB18030"))
string str = myr.ReadToEnd()
textBox1.AppendText(str + "\r\n"纤顷)
其中GB18030是国家标准
Gb18030详细信息:http://www.znwb.com/gb18030.html
如果文件中告竖不含有中文字符应该袜竖大这样写
StreamReader myr = new StreamReader(@"文件路径")
string str = myr.ReadToEnd()
textBox1.AppendText(str + "\r\n")
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)