1.系统为什么要有日志?
一个合格的系统不仅要运行高效、计算准确,同时又必须兼顾稳定性、可靠性。其次从开发角度看,又必须有可拓展性和可维护性。各方面都必须很完善,这样的一个系统才能称得上是一个合格完美的系统。
说到可维护性,不得不涉及到系统监控和Bug的快速定位。在开发阶段还比较容易对系统进行监控,一般都会在本机上对系统的运行进行实时监控。而对于bug的定位,开发者也会熟练使用debug功能进行bug定位,更有甚者有的开发者凭着多年的开发经验通过对系统的异常信息能直接分析出Bug产生的原因、位置以及解决方案。但是,系统毕竟是人开发的,我们无法保证一个严格测试通过的系统一旦投入生产,在运行中会不会出现一些意想不到的问题。而且有些问题生产存在,但在本机由于场景比较复杂等原因难以复现,我们又该如何快速、准确地对bug进行定位分析和解决呢?
我们多么希望存在一个好的工具可以实时记录系统的运行状况,并快速查找关键词进行定位与分析,在这种背景下日志系统应运而生。我们可以通过日志工具在系统设计、开发和实现的过程中注意有效Log的输出,方便我们日后对系统监控和异常分析。
2.系统的那些系统的哪些运行信息需要进行日志记录?
- 功能模块的启动和结束(完整的系统由多个功能模块组成,每个模块负责不同的功能,因此需要对模块的启动和结束进行监控。是否在需要的时机正常加载该模块?又是否在退出结束的时候正常完成结束操作,正常退出?)
- 用户的登录和退出(哪位用户在什么时间通过什么IP登录或退出了系统)
- 系统的关键性操作(数据库链接信息、网络通信的成功与失败等)
- 系统运行期间的异常信息(NPE、OOM以及其他的超时、转换异常等)
- 关键性方法的进入和退出(一些重要业务处理的方法,在进入和结束的时候需要有日志信息进行输出)
3.什么格式的日志有助于开发者进行明确的分析?
日志信息要求必须精简,过多的无用信息不但对系统分析起不到什么作用,反而会增加系统的运行压力、消耗系统的运行资源。这里有个日志模板,可供参考。
时间-[线程名][日志等级]-日志输出位置(全类名,可以精确到方法名):日志信息
2013-09-04 10:49:20.296-[Thread-initRedis21504][INFO]-com.shanghai.LoginController.initLogInfo:LingMing[User] is logining
日志信息的内容可以根据不同的情况进行设计,但是前面的时间到日志输出位置必须要保证完整性,这样才有利于日志的分析。
4.如何对不同的日志信息进行等级划分?
日志等级通常分为四种:DEBUG、INFO、WARN、ERROR
- DEBUG:系统调试信息,通常用于开发过程中对系统运行情况的监控,在实际运行环境中不进行输出。
- INFO:系统运行的关键性信息,通常用于对系统运行情况的监控。
- WARN:告警信息,系统存在潜在的问题,有可能引起运行异常,但此时并未产生异常。
- ERROR:系统错误信息,需要进行及时处理和优化。
- FATAL:非常严重的错误,导致系统中止。
这里列出来了各种等级的日志信息,在开发过程中哪些信息需要设置为哪种等级有赖于开发者的自己判断,这里只是给个建议。
5.日志有哪些实现方式?
- 使用common-loggi ng和log4j
Apache为了让众多的日志工具有一个相同操作方式,实现了一个通用日志工具包:commons-logging。而Log4j基本上是Java平台上最好的日志组件了。
使用ommons-logging的Log接口,并由commons-logging在运行时决定使用哪种日志架构(如Log4j)。现在,Apache通用日志工具commons-logging和Log4j已经成为Java日志的标准工具。
1)Maven/Jar包
需要使用commons-logging.jar和log4j.jar包。如果使用Maven,则需要在pom中添加:
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2)目录结构
注意要添加对应的属性文件
common-logging.properties:用于指定具体的实现方案;log4j.properties:用于指定日志输出格式以及对应终端
3)配置common-logging.properties文件
只需要一行即可,放在classpath下,如果是Maven中就在src/resources下:
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger
4)配置log4j.properties文件
放在classpath下,如果是Maven中就在src/resources下。具体意义看注释。
### set log levels ###
log4j.rootLogger = debug , stdout , D , E
### 输出到控制台 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
## 输出INFO级别以上的日志
log4j.appender.stdout.Threshold = INFO
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %d{ABSOLUTE} %5p %c{1}:%L - %m%n
### 输出到日志文件 ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = D:/logs/log.log
log4j.appender.D.Append = true
## 输出DEBUG级别以上的日志
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
### 保存异常信息到单独文件 ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
## 异常日志文件名
log4j.appender.E.File = D:/logs/error.log
log4j.appender.E.Append = true
## 只输出ERROR级别以上的日志!!!
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
5)测试
package com.zzkun;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Created by kun on 2016/5/13.
*/
public class LogTest {
private static Log logger = LogFactory.getLog(LogTest.class);
public static void main(String[] args) {
logger.trace("我是trace信息");
logger.debug("我是debug信息");
logger.info("我是info信息");
logger.warn("我是warn信息");
logger.error("我是error信息");
logger.fatal("我是fatal信息");
}
}