处理程序日志的注意点


李国帅 2018-02-06 qq 9611153

日志记录跟随软件的发展,慢慢的也会演进成为一个日志系统,而不仅仅是一份随时可以抛弃的记录。

最近很希望一句名言,“风起于青蘋之末,浪成于微澜之间”,也许那么不经意间的改变,我们希望的事情,就会像日志系统一样,从一页纸,变成一个不可或缺的部分。

以下内容从2010~2013年间的部分日志中检出,并结合自己的经验作出的总结。


日志的作用

通常情况下,我们编写程序都会用到日志,日志有什么用呢?下面以调试日志和运行日志说明使用日志分析原因。


运行日志:

运行的时候,可以了解到资源消耗,异常操作,用户数据等依次来进行程序优化,复杂均衡,流程改造。

具体操作就是,如果出现非常重要的问题需要使用提醒(messagebox)警告(alert)甚至直接退出程序的方式告知,但依然有迹可寻。

有迹可寻指的是:使用日志,可以看到程序的运行状态,重要和异常操作,出现问题后的处理流程,程序中断或终止的原因,最后的操作,最后的运行状态是什么。


调试日志

开发的时候出现问题,能够快速定位问题出现的确切位置,方便修正和重构。

具体操作就是,记录内存及cpu状态,异常状况,崩溃记录,重要的特定跟踪信息,按重要级别和标记记录不同的信息,需要跟踪到文件名、函数名和行数。


注意点:

下面直接讲自己现在想到的一些注意点,希望对大家有用。


日志级别

日志记录一般都是分级别的,通常还会有一个配置文件专门配置级别,我们对不同的日志级别的重视程度是不同的,这一点不用多讲。

VERBOSE(0), DEBUG(1), INFO(2), WARN(3), ERROR(4), ASSERT(5), OFF(15);

有时候,我们针对不同的程序模块也会使用同步的日志配置,但通常在程序较大的时候使用。


灵活设置输出方式

通常我们可以把日志输出到日志,屏幕/控制台,第三方软件,或是远程网络,不同的方式各有优劣,根据我们的需要和情况选一种即可,没有必要同时实现。


输出格式

选择什么样的输出格式在于希望使用日志做什么?

l 如果你希望仅仅看看,那么记录一句话也行。

l 如果想跟踪,那么就需要更加详细的信息,选择添加时间,标记,类型,级别,用户,操作对象,进度,状态,消息,文件,函数,行数等等内容。

l 如果你希望进行日志的自动化统计分析,那么就需要日志具有严格的格式,甚至要求日志各个字段的长度固定,以便这些日志能够方便的导入对应的数据库。

如果针对开始达到自动统计分析的程度,那日志就真的可以成为日志系统了。


日志种类

对于一个程序,不同的人可能对不同的日志感兴趣,那么日志就可能不止一套。

对于开发者来说,更对程序细节感兴趣,比如(逻辑错误,数据错误,崩溃信息,资源占用,特定信息),就会出用于调试的调试日志。

对于测试,维护,二次开发者来说,他们更感兴趣的是稳定性,安全性,客户情况,希望能得到数据流程,用户行为,资源占用,运行状态等信息,他们需要的是运行日志。

不过记录什么东西完全要看项目和工作的实际需要,因为说到底日志的地位在小项目中是没品的,没有人在乎,只能在需要的时候才会拿出来用用。


同步问题

对于一般的程序,我们不需要考虑同步问题,但是对于类似多媒体这样的应用可就不一样了。参考下例:

同步的日志打印影响了多媒体播放速度。在进行播放之前需要添加时间段,添加的过程使用了近5秒的时间,查询结果发现,写日志出现了阻塞。

[5728] C***Ctrl::*** nRecordId=5074,tBeginTime=2012/12/24 14:7:29 tEndTime=2012/12/24 14:7:35

....持续了5秒钟,因此如果日志处理不好可能影响到应用程序的正常使用。

[5728] C***Ctrl::*** nIndex=0 nRecordId=4917 Url=rtsp://192.168.17.232:554/data1/Rec/000/000/006/238?b=0 fRate=0.00 strSeekTime=2012/12/24 12:14:37

因此,在某些应用,日志必须是异步的,独立线程的。对于记录日志的线程比较多的情况下,日志必须排队进行。

同样,程序退出前,需要记录下所有正在排队异步日志。


日志的安全性

对日志的使用应该保证,在输出到媒介之前,输出缓冲是安全的。如果你输出的内容传入日志系统然后马上销毁了,日志将无法读取到正确的日志内容,从而导致内存访问失败。

如果无法保证,那么需要在进入日志系统之后,保留一份日志内容备份,直到处理完成为止。

在采用自定义日志的时候,如果出现内存失败,也有可能是日志引起的,这一点在实际工作中时遇到的。因为打印日志出现内存错误,可能影响到所在程序的内存堆栈,从而在其他函数出现内存访问失败。


日志过多的处理

任何的日志都会影响到程序执行的效率,所以日志也并不是日志越多越详细越好,不必要的日志就不要写进去了。

在正式发布程序版本的时候,调试日志是不建议保留的。

如果使用控制台打印日志,随着程序的运行,缓存的日志可能越来越多,内存占用越来越大,因此需要对这类日志的缓存大小进行限制。因为限制又影响到了日志的跟踪,因此控制台调试并不适合需要长期调试的情况。

对于文件日志,就不存在内存占用大量增加的情况了,但是时间久了,也是需要进行清理和处理的。

可以设定定期清理那些特定类型的,确定没有问题的,没有价值的日志。

如果日志量过大,应该及时按照时间或者大小进行循环删除。


日志的字符要求

日志打印的时候,注意输入函数对字符类型的要求。

很多输出方式提供了不同的多字节和宽字节函数名,输出的时候需要进行转换。比如OutputDebugString、printf等。

static char temp[2048];
static char * STRTOCHAR(StrPtrLen *theStr)
{
temp[0] = 0;
UInt32 len = theStr->Len < 2047 ? theStr->Len : 2047;
if (theStr->Len > 0 || NULL != theStr->Ptr)
{
memcpy(temp, theStr->Ptr, len);
temp[len] = 0;
}
else
strcpy(temp, "Empty Ptr or len is 0");
return temp;
}

有些输出函数对输出栈的大小有限制,比如OutputDebugString的输入缓冲不能超过2048字节。

va_list args;
va_start(args, format_str);
int len = _vscprintf(format_str, args) + 2;
CHAR* pInfo = new CHAR(len);
try
{
len = vsprintf_s(pInfo, len, format_str, args);//这一行提示buffer too small。估计是temp冲突
OutputDebugStringA(pInfo);
}
catch (...)
{
OutputDebugStringA("log happen a error.");
}
delete[] pInfo;
va_end(args);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

微澜-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值