关于 logger
日志
前言
我是一名后台程序员,接触后台只有一年时间,在这期间一共做过四个项目,分别是:
- 工作室招新系统
- 视频学习网站
- 创客网站
- 打印机项目
由于之前做项目的时候没有好好重视日志,所以导致在开发与维护项目出现了很多问题,现在分享分享我的惨痛经历:
做第一个项目的时候,这个是我第一次开始学习后台时做的第一个项目,使用最原始的 servlet + jsp 技术,当时没有任何经验,没有把系统的需求和实现方式思考清楚就开始动工,做的过程遇到很多问题,但今天的主题不在这些问题上,而是关于日志,当时我们并没有在项目使用日志技术记录日志信息,因为该项目没有进行上线发布,所以后面做完了大部分功能之后就没继续完善和维护,所以没有意识到日志的重要性。
做第二个项目与第三个项目时,这是一个商业项目,由于第一次没有意识到日志的重要性,所以开发时是没有打日志的,等到项目开发完后,我们需要上线测试,部署到服务器时,发现出现了很多个 bug,但以前我们找 bug 都是通过调试或者在控制台输出错误信息来查看,部署到服务器上根本调试不了也看不到错误信息,这就导致一直找不到导致出现 bug 的地方。后面在项目添加了,但只是在 servlet 层后面添加一个全局的try catch,再记录错误信息而已,但这并没起多大作用。
做第四个项目时,当时有要打日志的想法,但是由于之前没做过,所以对于要如何打日志根本不理解,应该在什么地方记录日志,应该使用哪种日志级别。所以最后在项目的时候就随便乱打日志,导致最后输出的日志信息时,也是一团乱。
在基于前面的经历,觉得有必要去好好学习如何使用日志机制。
为什么要使用日志机制
就如我之前所说的,开发以后应用服务时,如果你没有使用日志机制,那么当你将服务部署上去时,系统出 bug 了,因为没有错误信息可以查看,所以你找不到错误出现的地方,这样会不方便测试与维护。使用日志及时记录错误的信息,会更方便我们定位到错误的地方以及错误的原因,方便我们修复系统。
日志机制
日志信息级别
日志信息一般有五种级别,分别是:
DEBUG
DEBUG 级别是最低的级别,一般是为了用于测试应用程序而输出日志信息,它只能用于开发环境与测试环境,不能用于线上环境。INFO
INFO 级别比 DEBUG 级别要高,一般用此级别来记录服务正在开启、从请求接收的信息、响应返回的信息等等WARN
WARN 级别 比 INFO 级别要高,一般是用于记录客户端与服务端连接丢失,数据库连接丢失、Scoket 连接达到限制等一些表示 server 运行时的状态信息ERROR
ERROR 级别 比 WARN 级别要高,一般是用于记录系统出现错误的异常错误信息,在开发时候,通过记录 ERROR 级别的信息,可以方便地定位到系统出错的地方,从而更方便地修复系统FATAL
FATAL 级别的信息一般是用于记录非常严重的错误事件信息,该事件可能会导致应用崩溃或者停止
如何使用日志
- 在输出 DEBUG 级别的日志信息前加一层 isDebugEnabled() 的判断,因为这是为了避免系统发布到运行环境上之后输出过多的日志信息,也避免需要为了发布而删掉或注释掉输出的 DEBUG 信息,因为这会影响日后的系统维护
- 认真考虑好哪些信息要用哪种级别去记录日志。如果在发布环境上记录太多日志信息会影响性能,因为这会产生很多文件 IO ;但如果不记录重要的信息如接收的信息、响应的信息,将会非常困难找出错误的问题和异常在何处
- 使用配置文件来加载日志的信息,这会方便地改变系统的日志记录级别,从而避免重启应用
- 对于记录的日志信息,需要格式化;在高并发的系统时,需要记录当前的线程名以及当前处理类的完全限定名;记录的日志格式应一致、有用,必要的时候还要输出时间
- 使用一系列后缀来区分不同的层次的信息。比如与数据库有关,就记录 DB_LOG,与 Session 有关,记录 SESSION_LOG,这样有利于通过后缀查找匹配出那个层次的所有日志信息,方便管理和差错
- 如果没有为一个日志指定级别,应该让他从他的父类继承,所以我们一般通过配置文件为根日志配置级别为 DEBUG
- 没有日志或过多的日志都是非常不好的,所以在性能和维护差错方面做好一个平衡,仔细选择要用哪些级别记录哪些信息
- 记录的日志信息应当是简单、易懂并且对于团队来说是有效的
Log4j
为系统性能考虑,使用 Log4j 注意下列几点:
- 避免输出 ‘%C’, ‘%f’, ‘%L’, ‘%M’ 等位置信息
- 尽量使用异步
- 为每个模块设置单独的输出文件
- 每次调用前检查 if(logger.isDebugEnabled()) { logger.debug(……) }
解析:
- 避免输出 ‘%C’, ‘%f’, ‘%L’, ‘%M’ 等位置信息
当配置文件中的配置项包含 Location 信息会非常昂贵- %C 输出类名
- %F 输出文件名
- %L 输出行号
- %M 输出函数名
注:当配置为异步输出的时候,以上位置信息可能会显示不出来,因为实在另外的一个线程记录的调用信息。此时,我们可以使用下面的方法来获取类名和函数名:
StackTraceElement se = Thread.currentThread().getStackTrace()[2];
String msg = se.getClassName() + "-[" + se.getMethodName() + "] " + errorMessage;
使用异步
要使用异步在于要在配置文件中配置 appender,为什么要使用异步来记录日志,前面说过记录日志信息会产生文件 IO,这会影响一定的性能,使用异步可以避免因为需要同步记录日志而产生的等待时间。为每个模块设置单独的输出文件
根据模块来区分日志文件,在调试和维护某个模块时,可以更方便。每次调用前检查 if(logger.isDebugEnabled()) { logger.debug(……) }
前面已说过
总结
日志机制对于开发来说是非常重要的,它关系到调试与维护,在开发一个项目前期,应该提前部署好日志环境。同时,在开发的过程中,要想好如何去记录日志信息,要用哪种级别去记录,权衡性能与维护,选择一种较好的日志实施方案。
本文只是个人观点,如有不同意,可以说出来大家一起讨论讨论。之后再补充一篇使用 slf4j + logback 搭建日志机制的博文。
关于 logger的更多相关文章
- ABP源码分析八:Logger集成
ABP使用Castle日志记录工具,并且可以使用不同的日志类库,比如:Log4Net, NLog, Serilog... 等等.对于所有的日志类库,Castle提供了一个通用的接口来实现,我们可以很方 ...
- org.apache.log4j.Logger详解
org.apache.log4j.Logger 详解 1. 概述 1.1. 背景 在应用程序中添加日志记录总的来说基于三个目的 :监视代码中变量的变化情况,周期性的记录到文件中供其他应用进行统计分析工 ...
- Java程序日志:java.util.logging.Logger类
一.Logger 的级别 比log4j的级别详细,全部定义在java.util.logging.Level里面.各级别按降序排列如下:SEVERE(最高值)WARNINGINFOCONFIGFINEF ...
- [LeetCode] Logger Rate Limiter 记录速率限制器
Design a logger system that receive stream of messages along with its timestamps, each message shoul ...
- .Net Core Logger 实现log写入本地文件系统
.net core 自带一个基础的logger框架Microsoft.Extensions.Logging. 微软默认实现了Microsoft.Extensions.Logging.Console.d ...
- Android源码——Logger日志系统
Android的Logger日志系统是基于内核中的Logger日志驱动程序实现的. 日志保存在内核空间中 缓冲区保存日志 分类方法:日志的类型 + 日志的输出量 日志类型: main ...
- java.lang.NoClassDefFoundError: Lorg/slf4j/Logger;
如果你出现类似如下错误 1. Install tomcat7 in my home directory and set up `CATALINA_HOME` environment variable ...
- LeetCode 359 Logger Rate Limiter
Problem: Design a logger system that receive stream of messages along with its timestamps, each mess ...
- 你的日志组件记录够清晰嘛?--自己开发日志组件 Logger
现在现成的日志组件实在是太多太多,为什么我还需要自己实现呢????? 需求来源于java的log4j, [07-31 16:40:00:557:WARN : com.game.engine.threa ...
- log4j2 不使用配置文件,动态生成logger对象
大家平时使用Log4j一般都是在classpath下放置一个log4j的配置文件,比如log4j.xml,里面配置好Appenders和Loggers,但是前一阵想做某需求的时候,想要的效果是每一个任 ...
随机推荐
- C语言编译器,写给萌新们看看。
就我已经经历过的大学课程,仿佛每一门计算机的专业课程的开头,都是在介绍计算机发展的历史,和大名鼎鼎的冯诺依曼结构. 譬如C语言,比较水的计算机导论,c++,数据结构,计算机组成原理,甚至是Linux实 ...
- su
参数选项:-,-l,--login 切换用户的同时,将用户的家目录.系统环境变量等重新按切换后的用户初始化.-c 向shell传递单个命令,仅希望在某个用户下执行命令,而不用直接切换到该用户下来操作. ...
- Vue收藏资料
组件库的全局引用和按需引用:http://www.cnblogs.com/zhuanzhuanfe/p/7516745.html
- vs使用libevent
1.下载最新libevent-2.1.8-stable,并解压 2.使用vs2013 工具这里使用x64,这里更新一下,改为使用x86 进入到libevent目录 运行 nmake /f Makefi ...
- l1 l2 loss
衡量预测值与真实值的偏差程度的最常见的loss: 误差的L1范数和L2范数 因为L1范数在误差接近0的时候不平滑,所以比较少用到这个范数 L2范数的缺点是当存在离群点(outliers)的时候,这些点 ...
- __future__模块
Python提供了__future__模块,把下一个新版本的特性导入到当前版本,于是我们就可以在当前版本中使用一些新版本的特性,比如除法: 在Python 2.x中,对于除法有两种情况,如果是整数相除 ...
- redis安装和简介(2)
承接上篇未完成的配置...此次使用的的 Redis-x64-3.2.100 版本 一.打开redis服务器 方式一:打开 redis-server.exe 显示如下图: 图中: 显示运行进程号.当前运 ...
- FactoryBean的实现原理与作用
FactoryBean与BeanFactory: 这俩货在拼写上很是相似,很多同学在看IOC源码或者其他地方并不能分清有啥区别,前面的IOC源码中我简单说过,现在统一简单来讲一下: FactoryBe ...
- AngularJS简介-起步阶段
AngularJS 是一个为动态WEB应用设计的结构框架,提供给大家一种新的开发应用方式,这种方式可以让你扩展HTML的语法,以弥补在构建动态WEB应用时静态文本的不足,从而在web应用程序中使用HT ...
- Google Guava -缓存cache简单使用
package guavacache; import java.util.concurrent.ExecutionException; import java.util.concurrent.Time ...