日志:记录程序的运行轨迹,方便查找关键信息,也方便快速定位解决问题。
通常,Java程序员在开发项目时都是依赖Eclipse/IDEA等集成开发工具的Debug 调试功能来跟踪解决Bug,但项目发布到了测试、生产环境怎么办?你有可能会说可以使用远程调试,但实际并不能允许让你这么做。
所以,日志的作用就是在测试、生产环境没有 Debug 调试工具时开发和测试人员定位问题的手段。日志打得好,就能根据日志的轨迹快速定位并解决线上问题,反之,日志输出不好,不仅无法辅助定位问题反而可能会影响到程序的运行性能和稳定性。
很多介绍 AOP 的地方都采用日志来作为介绍,实际上日志要采用切面的话是极其不科学的!对于日志来说,只是在方法开始、结束、异常时输出一些什么,那是绝对不够的,这样的日志对于日志分析没有任何意义。如果在方法的开始和结束整个日志,那方法中呢?如果方法中没有日志的话,那就完全失去了日志的意义!如果应用出现问题要查找由什么原因造成的,也没有什么作用。这样的日志还不如不用!
不管是使用何种编程语言,日志输出几乎无处不再。总结起来,日志大致有以下几种用途:
日志在应用程序中是非常非常重要的,好的日志信息能有助于我们在程序出现 BUG 时能快速进行定位,并能找出其中的原因。
作为一个有修养的程序猿,对日志这个东西应当引起足够的重视。
log4j、Logging、commons-logging、slf4j、logback,开发的同学对这几个日志相关的技术不陌生吧,为什么有这么多日志技术,它们都是什么区别和联系呢?且看下文分解:
这是 Java 自带的日志工具类,在 JDK 1.5 开始就已经有了,在 java.util.logging 包下。通常情况下,这个基本没什么人用了,了解一下就行。
commons-logging 是日志的门面接口,它也是Apache 最早提供的日志门面接口,用户可以根据喜好选择不同的日志实现框架,而不必改动日志定义,这就是日志门面的好处,符合面对接口抽象编程。现在已经不太流行了,了解一下就行。
slf4j,英文全称为“Simple Logging Facade for Java”,为java提供的简单日志Facade。Facade门面,更底层一点说就是接口。它允许用户以自己的喜好,在工程中通过slf4j接入不同的日志系统。
因此slf4j入口就是众多接口的集合,它不负责具体的日志实现,只在编译时负责寻找合适的日志系统进行绑定。具体有哪些接口,全部都定义在slf4j-api中。查看slf4j-api源码就可以发现,里面除了public final class LoggerFactory类之外,都是接口定义。因此slf4j-api本质就是一个接口定义。
Log4j 是 Apache 的一个开源日志框架,也是市场占有率最多的一个框架。
注意:log4j 在 2015.08.05 这一天被 Apache 宣布停止维护了,用户需要切换到 Log4j2上面去。
下面是官宣原文:
On August 5, 2015 the Logging Services Project Management Committee announced that Log4j 1.x had reached end of life. For complete text of the announcement please see the Apache Blog. Users of Log4j 1 are recommended to upgrade to Apache Log4j 2.
Log4j 2 Apache Log4j 2是apache开发的一款Log4j的升级产品。
Log4j2与Log4j1发生了很大的变化,log4j2不兼容log4j1。
Logback 是 Slf4j 的原生实现框架,同样也是出自 Log4j 一个人之手,但拥有比 log4j 更多的优点、特性和更做强的性能,现在基本都用来代替 log4j 成为主流。
Logback相对于log4j拥有更快的执行速度。基于我们先前在log4j上的工作,logback 重写了内部的实现,在某些特定的场景上面,甚至可以比之前的速度快上10倍。在保证logback的组件更加快速的同时,同时所需的内存更加少。
选项太多了的后果就是选择困难症,我的看法是没有最好的,只有最合适的:
slf4j + logback
.slf4j + log4j2
.在看线上日志的时候,我们可曾陷入到日志泥潭?该出现的日志没有,无用的日志一大堆,或者需要的信息分散在各个角落,特别是遇到紧急的在线bug时,有效的日志被大量无意义的日志信息淹没,焦急且无奈地浪费大量精力查询日志。那什么是记录日志的合适时机呢?
总结几个需要写日志的点:
日志变量往往不变,最好定义成final static,变量名用大写。
1 2 |
<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">Logger</span> log <span class="token operator">=</span> <span class="token class-name">LoggerFactory</span><span class="token punctuation">.</span><span class="token function">getLogger</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token class-name">SimpleClassName</span><span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
通常一个类只有一个 log
对象,如果有父类可以将 log
定义在父类中。
日志变量类型定义为门面接口(如 slf4j 的 Logger),实现类可以是 Log4j、Logback 等日志实现框架,不要把实现类定义为变量类型,否则日志切换不方便,也不符合抽象编程思想。
另外,推荐引入lombok的依赖,在类的头部加上@Slf4j
的注解,之后便可以在程序的任意位置使用log
变量打印日志信息了,使用起来更加简洁一点,在重构代码尤其是修改类名的时候无需改动原有代码。
使用参数化形式{}占位,[]进行参数隔离
1 2 3 |
log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"Save order with order no:[{}], and order amount:[{}]"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"Save order with order no:[{}], and order amount:[{}]"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
这种可读性好,这样一看就知道[]里面是输出的动态参数,{}用来占位类似绑定变量,而且只有真正准备打印的时候才会处理参数,方便定位问题。
如果日志框架不支持参数化形式,且日志输出时不支持该日志级别时会导致对象冗余创建,浪费内存,此时就需要使用 isXXEnabled 判断,如:
1 2 3 4 5 |
<span class="token keyword">if</span><span class="token punctuation">(</span>log<span class="token punctuation">.</span><span class="token function">isDebugEnabled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment">// 如果日志不支持参数化形式,debug又没开启,那字符串拼接就是无用的代码拼接,影响系统性能</span> log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"Save order with order no:"</span> <span class="token operator">+</span> orderNo <span class="token operator">+</span> <span class="token string">", and order amount:"</span> <span class="token operator">+</span> orderAmount<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
至少 debug 级别是需要开启判断的,线上日志级别至少应该是 info 以上的。
这里推荐大家用 SLF4J 的门面接口,可以用参数化形式输出日志,debug 级别也不必用 if 判断,简化代码。
日志输出主要在文件中,应包括以下内容:
1 2 |
11<span class="token punctuation">:</span>44<span class="token punctuation">:</span>44.827 WARN [93ef3E0120160803114444] [main] [ClassPathXmlApplicationContext] Exception encountered during context initialization - cancelling refresh attempt |
作为日志产生的日期和时间,这个数据非常重要,一般精确到毫秒。由于线上一般配置为按天滚动日志文件,日期标识在文件名上,所以可以不放在这个时间中,使用 HH:mm:ss.SSS
格式即可。非要加上也未尝不可,格式推荐:yyyy-MM-dd HH:mm:ss.SSS
。
日志的输出都是分级别的,不同的设置不同的场合打印不同的日志。下面拿最普遍用的 Log4j 日志框架来做个日志级别的说明,这个也比较齐全,其他的日志框架也都大同小异。
主要使用如下的四个级别:
DEBUG级别比INFO低,包含调试时更详细的了解系统运行状态的东西,比如变量的值等等,都可以输出到DEBUG日志里。 INFO是在线日志默认的输出级别,反馈系统的当前状态给最终用户看的。输出的信息,应该对最终用户具有实际意义的。从功能角度上说,Info输出的信息可以看作是软件产品的一部分,所以需要谨慎对待,不可随便输出。尝试记录INFO日志时不妨在头脑中模拟线上运行,如果这条日志会被频繁打印或者大部分时间对于纠错起不到作用,就应当考虑下调为DEBUG级别。
当方法或者功能处理过程中产生不符合预期结果或者有框架报错时可以考虑使用,常见问题处理方法包括:
一般来说,WARN级别不会短信报警,ERROR级别则会短信报警甚至电话报警,ERROR级别的日志意味着系统中发生了非常严重的问题,必须有人马上处理,比如数据库不可用,系统的关键业务流程走不下去等等。错误的使用反而带来严重的后果,不区分问题的重要程度,只要有问题就error记录下来,其实这样是非常不负责任的,因为对于成熟的系统,都会有一套完整的报错机制,那这个错误信息什么时候需要发出来,很多都是依据单位时间内ERROR日志的数量来确定的。因此如果我们不分轻重缓急,一律ERROR对待,就会徒增报错的频率,久而久之,我们的救火队员对错误警报就不会那么在意,这个警报也就失去了原始的意义。
WARN代表可恢复的异常,此次失败不影响下次业务的执行,开发人员会苦恼某些场景下几次失败可容忍,频率高的时候需要提醒,记录ERROR的结果是线上时不时出现容忍范围内的报警,这时报警是无意义的。但反之不记录ERROR日志,真正出现问题则不会有实时报警,错过最佳处理时机。
强调ERROR报警
ERROR日志目标
问题定位:
日志模板
1 2 3 |
log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>“<span class="token punctuation">[</span>接口名或操作名<span class="token punctuation">]</span> <span class="token punctuation">[</span><span class="token class-name">Some</span> <span class="token class-name">Error</span> <span class="token class-name">Msg</span><span class="token punctuation">]</span> happens<span class="token punctuation">.</span> <span class="token punctuation">[</span><span class="token class-name">Probably</span> <span class="token class-name">Because</span><span class="token punctuation">]</span><span class="token punctuation">.</span> <span class="token punctuation">[</span><span class="token class-name">Probably</span> need <span class="token keyword">to</span> <span class="token keyword">do</span><span class="token punctuation">]</span> <span class="token punctuation">[</span>params<span class="token punctuation">]</span> <span class="token punctuation">.</span>”<span class="token punctuation">)</span><span class="token punctuation">;</span> log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>“<span class="token punctuation">[</span>接口名或操作名<span class="token punctuation">]</span> <span class="token punctuation">[</span><span class="token class-name">Some</span> <span class="token class-name">Error</span> <span class="token class-name">Msg</span><span class="token punctuation">]</span> happens<span class="token punctuation">.</span> <span class="token punctuation">[</span><span class="token class-name">Probably</span> <span class="token class-name">Because</span><span class="token punctuation">]</span><span class="token punctuation">.</span> <span class="token punctuation">[</span>please contact xxx<span class="token annotation punctuation">@xxx</span><span class="token punctuation">]</span> <span class="token punctuation">[</span>params<span class="token punctuation">]</span> <span class="token punctuation">.</span>”<span class="token punctuation">)</span><span class="token punctuation">;</span> |
在分布式应用中,用户的一个请求会调用若干个服务完成,这些服务可能还是嵌套调用的,因此完成一个请求的日志并不在一个应用的日志文件,而是分散在不同服务器上不同应用节点的日志文件中。该标识是为了串联一个请求在整个系统中的调用日志。
调用链标识格式:
调用链标识作为可选项,无该数据时只输出 [] 即可。
输出该日志的线程名称,一般在一个应用中一个同步请求由同一线程完成,输出线程名称可以在各个请求产生的日志中进行分类,便于分清当前请求上下文的日志。
日志记录器名称一般使用类名,日志文件中可以输出简单的类名即可,看实际情况是否需要使用包名和行号等信息。主要用于看到日志后到哪个类中去找这个日志输出,便于定位问题所在。
1 2 3 4 5 6 |
<span class="token comment">// 不推荐</span> log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span> <span class="token string">"Load student(id={}), name: {}"</span> <span class="token punctuation">,</span> id <span class="token punctuation">,</span> student<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 推荐</span> log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span> <span class="token string">"Load student(id={}), student: {}"</span> <span class="token punctuation">,</span> id <span class="token punctuation">,</span> student <span class="token punctuation">)</span><span class="token punctuation">;</span> |
对于一些一定需要进行拼接字符串,或者需要耗费时间、浪费内存才能产生的日志内容作为日志输出时,应使用 log.isXxxxxEnable() 进行判断后再进行拼接处理,比如:
1 2 3 4 5 6 7 8 9 |
<span class="token keyword">if</span> <span class="token punctuation">(</span>log<span class="token punctuation">.</span><span class="token function">isDebugEnable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> StringBuilder builder <span class="token operator">=</span> <span class="token builtin">new</span> <span class="token function">StringBuilder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>Student student <span class="token punctuation">:</span> students<span class="token punctuation">)</span> <span class="token punctuation">{</span> builder<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">"student: "</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>student<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> builder<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">"value: "</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>JSON<span class="token punctuation">.</span><span class="token function">toJSONString</span><span class="token punctuation">(</span>object<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span> <span class="token string">"debug log example, detail: {}"</span> <span class="token punctuation">,</span> builder <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
异常堆栈一般会出现在 ERROR 或者 WARN 级别的日志中,异常堆栈含有方法调用链的系统,以及异常产生的根源。异常堆栈的日志属于上一行日志的,在日志收集时需要将其划至上一行中。
日志文件放置于固定的目录中,按照一定的模板进行命名,推荐的日志文件名称:
1 2 3 |
当前正在写入的日志文件名:<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>应用名</span><span class="token punctuation">></span></span>[-<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>功能名</span><span class="token punctuation">></span></span>].log 已经滚入历史的日志文件名:<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>应用名</span><span class="token punctuation">></span></span>[-<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>功能名</span><span class="token punctuation">></span></span>].log.<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>yyyy-MM-dd</span><span class="token punctuation">></span></span> |
根据不同的环境配置不同的日志输出方式:
logback 日志工具可以在日志文件滚动后将前一文件进行压缩,以减少磁盘空间占用,若使用 logback 对于日志量庞大的应用建议开启该功能。
具体的配置示例,由于篇幅较长,单独开一篇介绍。详情可移步:日志使用项目实战
1 2 |
<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">Logger</span> log <span class="token operator">=</span> <span class="token class-name">LoggerFactory</span><span class="token punctuation">.</span><span class="token function">getLogger</span><span class="token punctuation">(</span><span class="token class-name">Main</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
1 2 |
<span class="token class-name">InterfaceImpl</span> <span class="token keyword">interface</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">InterfaceImpl</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
这段代码大家都看得懂吧?应该面向接口的对象编程,而不是面向实现,这也是软件设计模式的原则,正确的做法应该是。
1 2 |
<span class="token class-name">Interface</span> <span class="token keyword">interface</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">InterfaceImpl</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
日志框架里面也是如此,上面也说了,日志有门面接口,有具体实现的实现框架,所以大家不要面向实现编程。
log.error(msg)
和log.error(msg,e.getMessage())
这样的日志输出方法会丢失掉最重要的StackTrace信息。
1 2 3 4 5 6 7 8 9 10 |
<span class="token keyword">void</span> <span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">try</span><span class="token punctuation">{</span> <span class="token comment">//do somehing </span> <span class="token punctuation">}</span><span class="token keyword">catch</span><span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span><span class="token punctuation">{</span> log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//错误示范</span> log<span class="token punctuation">.</span><span class="token function">erroe</span><span class="token punctuation">(</span><span class="token string">"Bad Things"</span><span class="token punctuation">,</span>e<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//错误示范</span> log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"Bad Things"</span><span class="token punctuation">,</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//正确演示</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
1 2 3 4 5 6 7 8 9 |
<span class="token keyword">void</span> <span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">LogException</span><span class="token punctuation">{</span> <span class="token keyword">try</span><span class="token punctuation">{</span> <span class="token comment">//do somehing </span> <span class="token punctuation">}</span><span class="token keyword">catch</span><span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span><span class="token punctuation">{</span> log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"Bad Things"</span><span class="token punctuation">,</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//正确</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">LogException</span><span class="token punctuation">(</span><span class="token string">"Bad Things"</span><span class="token punctuation">,</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
包括System.out.println()
和System.error.println()
语句。因为这个只会打印到控制台,而不会记录到日志文件中,不方便管理日志。此外,标准输出不会显示类名和行号信息,一旦代码中大量出现标准输出的代码,且日志中打印有标准输出的内容,很难定位日志内容和日志打印的位置,根本无法排查问题,想删除无用日志输出也改不动,这个是笔者在重构古董代码的时候亲自踩过的一个坑。
1 2 3 4 5 6 7 8 9 10 |
<span class="token keyword">void</span> <span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">try</span><span class="token punctuation">{</span> <span class="token comment">//do somehing </span> <span class="token punctuation">}</span><span class="token keyword">catch</span><span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token class-name">Syste</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//错误</span> <span class="token class-name">System</span><span class="token punctuation">.</span>error<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//错误</span> log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"Bad Things"</span><span class="token punctuation">,</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//正确</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
1 2 3 4 5 6 7 8 9 |
<span class="token keyword">void</span> <span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">try</span><span class="token punctuation">{</span> <span class="token comment">//do somehing </span> <span class="token punctuation">}</span><span class="token keyword">catch</span><span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span><span class="token punctuation">{</span> e<span class="token punctuation">.</span><span class="token function">printStacktrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//错误</span> log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"Bad Things"</span><span class="token punctuation">,</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//正确</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
来看一下它的源码:
1 2 3 4 |
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token class-name">System</span><span class="token punctuation">.</span>err<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
它其实也是利用 System.err
输出到了Tomcat控制台。
出于日志性能的考虑,如果代码为核心代码,执行频率非常高,则输出日志建议增加判断,尤其是低级别的输出<debug、info、warn>。
一是因为项目本身 debug 日志太多,二是各种框架中也大量使用 debug 的日志,线上开启 debug 不久就会打满磁盘,影响业务系统的正常运行。
如果你的框架使用了性能不高的 Log4j 框架,那就不要在上千个 for 循环中打印日志,这样可能会拖垮你的应用程序,如果你的程序响应时间变慢,那要考虑是不是日志打印的过多了。
1 2 3 4 |
<span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">int</span> i<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">;</span> i<span class="token operator"><</span><span class="token number">2000</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span> log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"XX"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
最好的办法是在循环中记录要点,在循环外面总结打印出来。
通常情况下在程序日志里记录一些比较有意义的状态数据:程序启动,退出的时间点;程序运行消耗时间;耗时程序的执行进度;重要变量的状态变化。
作者:GeekerLou
链接:https://www.jianshu.com/p/546e9aace657
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。