javaWeb项⽬打印⽇志
关于⽇志打印的⼏点建议以及⾮最佳实践
⽇志的打印在软件开发过程中必不可少,⼀般分为两个⼤类:
操作⽇志
系统⽇志
操作⽇志,主要针对的是⽤户,例如在Photoshop软件中会记录⾃⼰操作的步骤,便于⽤户⾃⼰查看。
系统⽇志,主要针对的是软件开发⼈员(包括测试、维护⼈员),也就是说这部分的⽇志⽤户是看不到的,也就是我们通常所说的debug⽇志。
在⼤学中所谓的实践项⽬或者⽼师布置的作⽤中,通常是不会在意⽇志,除⾮在作业中有特别的需要,往往在开发过程中直接打印控制台语句来调试程序,这是极为不专业的调试开发过程。所以这也就导致了⼀个问题,⼤学毕业和⼯作时衔接不上最⼤的问题不在于技术上的难度,⽽是⽇志打印的问题。这个看似不起眼的问题对于应届⽣来说往往是“恶梦”,操作⽇志相对⽐较好理解,⽤户做了什么就记录什么;⽽打印系统⽇志则⽆从下⼿,往往⼀般有下⾯⼏个⽅⾯——3W:
Where:不清楚在何处打印⽇志
Who:不清楚打印什么级别的⽇志
What:不清楚⽇志应该包含什么内容
本篇着重讲解系统⽇志,所以以下“⽇志”均为“系统⽇志”的简称。我将针对这⼏个⽅⾯对系统⽇志的打印做⼀个简要的总结。另外对Java中常⽤的⽇志打印框架(log4j)的⼏种使⽤⽅式做⼀个⽰范。
WHERE
1.程序⼊⼝
在⼊⼝打印⽇志是因为这个时候传递进来的参数没有经过任何处理,将它打印在⽇志⽂件中能⼀眼就知道程序的原始数据是否符合我们的预期,是不是传递进来的原始数据就出现 的问题。
2.异常捕获
在异常打印出详细的⽇志能让你快速定位错误在哪⾥,例如在程序抛出异常捕获时,在平时我们经常就是直接在控制台打印出堆栈信息
e.printStackTrace(),但在实际的⽣产环境更加艰苦,更别说有IDE来让你查看控制台信息,此时就需要我们将堆栈信息记录在⽇志中,以便发⽣异常时我们能准确定位程序在哪⾥出错。
3.重要信息
这⼀点可能很宽泛,因为不同的业务逻辑重点可能并不⼀样,例如在有的重要参数不能为空,此时就需要判断是否为空,如果为空则记录到⽇志中;还有的例如传递进来的参数经过⼀系列的算法处理过后,此时也需要打印⽇志来查看是否计算正确。但切记,尽量不要直接在for 循环中打印⽇志,特别是for循环特别⼤时,这样你的⽇志可能分分钟被冲得不见踪迹,甚⾄带来性能上的影响。
WHO
⽇志打印通常有四种级别,从⾼到底分别是:ERROR、WARN、INFO、DEBUG。应该选⽤哪种级别就是个很重要的问题。
⾸先明确⽇志级别中的优先级是什么意思,在你的系统中如果开启了某⼀级别的⽇志后,就不会打印⽐它级别低的⽇志。例如,程序如果开启了INFO级别⽇志,DEBUG⽇志就不会打印,但不打印不代表不产⽣,这在后⾯会提到。通常在⽣产环境中开启INFO⽇志。
那么应该打印什么级别的⽇志呢?⾸先我们应该明确谁在看⽇志。
通常来说,系统出了问题客户不会进到系统对着⿊黢黢的控制台查看⽇志输出,所以⽇志所⾯对的主体对象必然是软件开发⼈员(包括测试测试、维护⼈员)。
下⾯我们假设⼏种场景来帮助我们理解⽇志级别。
⾸先,程序开发结束后交由给测试⼈员进⾏测试,测试⼈员根据测试⽤例发现某个⽤例的输出和预期不符,此时他的第⼀反应该是查看⽇志。此时的⽇志是INFO级别⽇志不会出现DEBUG级别的⽇志,现在就需要根据⽇志打印分为两种情况决定他下⼀步操作:
1. 通过查看INFO⽇志发现是由于⾃⼰操作失误,造成了程序结果和预期不符合,这种情况不是程序出错,所以并不是bug,不需要开发
⼈员到场。
2. 通过查看INFO⽇志发现⾃⼰的操作正确,根据INFO⽇志查看并不是操作失误造成,这个时候就需要开发⼈员到场确认。
3. 以上两种情况是理想情况,测试⼈员仅根据INFO级别的⽇志就能判断出程序的输出结果与预期不符是因为⾃⼰操作失误还是程序
bug。更为现实的情况实际是测试⼈员并不能根据INFO级别的⽇志判断是否是⾃⼰失误还是程序bug。
综上,INFO级别的⽇志应该是能帮助测试⼈员判断这是否是⼀个真正的bug,⽽不是⾃⼰操作失误造成的。
假设测试⼈员现在已经初步判断这是⼀个bug,并且这个bug不那么明显,此时就需要开发⼈员到场确认。
开发⼈员到达现场后,第⼀步应该是查看INFO⽇志初步作初步判断验证测试⼈员的看法,接着如果不能判断出问题所在则应该是将⽇志级别调整⾄DEBUG级别,打印出DEBUG级别的⽇志,通过DEBUG⽇志来分析定位bug出在哪⾥。
所以,DEBUG级别的⽇志应该是能帮助开发⼈员分析定位bug所在的位置。
ERROR和WARN的级别都⽐INFO要⾼,所以在设定⽇志级别在INFO时,这两者的⽇志也会被打印。根据上⾯INFO和DEBUG级别的区别以及适⽤⼈员可以知道,ERROR和WARN是同时给测试和开发观察的。
WARN级别称之为“警告”,这个“警告”实际上就有点含糊了,它不算错,你可以选择忽视它,但也可以选择重视它。例如,现在⼀个WARN⽇志打出这么⼀条⽇志“系统有崩溃的风险”,这个时候就需要引起⾜够的重视,它代表现在不会崩溃,但是它有崩溃的风险。或者出现“某⽤户在短时间内将密码输出很多次
过后才进⼊了系统”,这个时候是不是系统被暴⼒破解了呢?等等,这个级别⽇志如同它的字⾯含义,给你⼀个警告,你可以选择忽视,也可以重视,但⾄少它现在不会给系统带来其他影响。
ERROR级别称之为“错误”,这个含义就更明显了,就是系统出现了错误,需要处理。最为常见的就是捕获异常时所打印的⽇志。
上⾯我们介绍了四种⽇志级别的区别,特别需要注意的是INFO级别和DEBUG级别所适⽤的⼈员。那么我们该如何选择哪个级别的⽇志输出呢?
以下是我的个⼈理解:
INFO
程序⼊⼝,这能让开发⼈员确认参数是否为⾃⼰所为。
计算结果,测试关⼼的程序的输出结果是否符合预期,那么对于计算过程不应该关⼼,仅给出计算结果就能判断是否符合预期。
DEBUG
对于DEBUG级别,我认为更关⼼的是过程,以及更为具体的相关信息,因为帮助它的定位在于帮助开发⼈员定位bug,定位bug就需要较为详细的参数信息才能定位。例如对于某个具体的算法过程,可以使⽤DEBUG打印,开发⼈员不仅关⼼结果,同时在结果不正确时应该能根据DEBUG⽇志查询计算过程是否出现偏差
WARN
某个不常⾛到的分⽀,对于常规的操作是不应该打印WARN⽇志的,只有在满⾜某个条件才能⾛到的分⽀,且这个分⽀引起了“警觉”,此时就应该打印WARN⽇志。
ERROR
毫⽆疑问出现错误,程序不能继续运⾏下去就应该打印ERROR⽇志,这个错误并不是业务上的错误。例如,新增某个⽤户发现已经存在时,此时虽然新增失败,但不能说程序出现错误就打印ERROR⽇志;在删除某个⽤户发现⽤户已经被锁定时,此时也不能说因为程序不能按照删除的逻辑继续运⾏下去就应该打印ERROR⽇志。
WHAT
应该打印什么内容?打印的内容⼀定要从实际出发。也就是说如果在实际的⽣产环境中,你的⽤户量很
⼤,⽇志在不停地刷新,如何定位某个⽤户的整个登录以及后续的操作呢?当然就是根据⽤户名来跟踪。所以打印内容的第⼀要素就是要能便于定位;定位过后也许⽤户在好⼏个模板中进⾏操作,还是定位,这个时候定的是模块的位;还有⼀点当然就是⽤户操作时的具体参数;最后⼀点就是⽤户⼲了什么。
l中的依赖如下:
<?xml version="1.0" encoding="UTF-8"?>
<!--⽇志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration后⾯的status,这个⽤于设置log4j2⾃⾝内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出--> <!--monitorInterval:Log4j能够⾃动检测修改配置⽂件和重新配置本⾝,设置间隔秒数-->
<!--设置log4j2的⾃⾝log级别为DEBUG-->
<configuration status="DEBUG " monitorInterval="30">
<appenders>
log4j2不打印日志<!--控制台输出-->
<console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %contextName [%thread] %-5level %logger{36} [%file : %line] - %msg%n"/> </console>
<!-- fileName:输出路径 filePattern:命名规则-->
<RollingFile name="RollingFileInfo" fileName="D:\\WebLogs\\libLog.log"
filePattern="D:\\WebLogs\\$${date:yyyy-MM-dd}/allOut-%d{yyyy-MM-dd}-%">
<Filters>
<!--控制台如果只输出info及以上级别的信息(onMatch),level=info,其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="Debug" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
<!--输出格式-->
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %contextName [%thread] %-5level %logger{36} [%file : %line] - %msg%n"/> <Policies>
<TimeBasedTriggerzingPolicy interval="1"/>
<!-- SizeBasedTriggeringPolicy单个⽂件的⼤⼩限制-->
<SizeBasedTriggeringPolicy size="20 MB"/>
</Policies>
<!-- DefaultRolloverStrategy同⼀个⽂件下的最⼤⽂件数,默认为最多同⼀⽂件夹下7个⽂件-->
<DefaultRolloverStrategy max="50"/>
</RollingFile>
</appenders>
<loggers>
<!--过滤掉spring和hibernate的⼀些⽆⽤的debug信息-->
<logger name="org.springframework" level="INFO">
</logger>
<logger name="batis" level="INFO">
</logger>
<root level="trace">
<appender-ref ref="Console"/>
<appender-ref ref="RollingFileInfo"/>
<!--<appender-ref ref="RollingFileWarn"/>
<appender-ref ref="RollingFileError"/>-->
</root>
</loggers>
</configuration>
在l中添加
<context-param>
<param-name>isLog4jAutoInitializationDisabled</param-name>
<param-value>true</param-value>
</context-param>
由于原⽂是log4j1.x版本,⾃⼰参考其他博客做了以上配置,具体配置解析参考了以下的博⽂和其他的⼀些博⽂。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论