Java日志处理

日志

日志就是Logging,它的目的是为了取代System.out.println()

输出日志,而不是用System.out.println(),有以下几个好处:
(1)可以设置输出样式,避免自己每次都写“ERROR: ” + var
(2)可以设置输出级别,禁止某些级别输出。例如:只输出错误日志
(3)可以被重定向到文件,这样可以在程序运行结束后查看日志
(4)可以按包名控制日志级别,只输出某些包打的日志

日志及分类(三类)

日志根据记录内容不同,分为三类
(1)SQL日志:记录系统执行的SQL语句
(2)异常日志:记录系统运行中发生的异常事件
(3)业务日志:记录系统运行过程,如用户登录、操作记录


JDK Logging(7个级别)

Java标准库内置了日志包java.util.logging,可以直接用

JDK的Logging定义了7个日志级别,从严重到普通:
①server
②warning
③info(默认)
④config
⑤fine
⑥finer
⑦finest

默认级别是INFO。因此,INFO级别以下的日志,不会被打印出来。使用日志级别的好处在于,调整级别,就可以屏蔽掉很多调试相关的日志输出

Logging系统在JVM启动时读取配置文件并完成初始化,一旦开始运行main()方法,就无法修改配置;配置不太方便,需要在JVM启动时传递参数。因此,Java标准库内置的Logging使用并不是非常广泛

Logger logger = Logger.getGlobal();
logger.severe("");
logger.warning("");
logger.info("");
logger.config("");
logger.fine("");
logger.finer("");
logger.finest("");

输出

Mar 02, 2019 6:32:13 PM Hello main
INFO: start process...
Mar 02, 2019 6:32:13 PM Hello main
WARNING: memory is running out...
Mar 02, 2019 6:32:13 PM Hello main
SEVERE: process will be terminated...

使用日志最大的好处是,它自动打印了时间、调用类、调用方法等很多有用的信息

(1)日志是为了替代System.out.println(),可以定义格式,重定向到文件等
(2)日志可以存档,便于追踪问题
(3)日志记录可以按级别分类,便于打开或关闭某些级别
(4)可以根据配置文件调整日志,无需修改代码
(5)Java标准库提供了java.util.logging来实现日志功能


Commons Logging和log4j

(1)通过Commons Logging实现日志,不需要修改代码即可使用Log4j
(2)使用Log4j只需要把log4j2.xml和相关jar放入classpath
(3)如果要更换Log4j,只需要移除log4j2.xml和相关jar
(4)只有扩展Log4j时,才需要引用Log4j的接口(例如,将日志加密写入数据库的功能,需要自己开发)


Commons Logging(6个级别)

和Java标准库提供的日志不同,Commons Logging是一个第三方日志库,它是由Apache创建的日志模块
Commons Logging的特色:可以挂接不同的日志系统,并通过配置文件指定挂接的日志系统。默认情况下,Commons Logging自动搜索并使用Log4j(Log4j是另一个流行的日志系统),如果没有找到Log4j,再使用JDK Logging(需要导入commons logging.jar)

commons-logging有6级日志,但是apache建议使用4级,即 ERROR、WARN、INFO、DEBUG。什么情况下输出日志由程序中写日志的方法决定,输出什么级别以上的日志和输出到哪里由配置文件决定

级别 描述
①FATAL 记录具有致命日志级别的消息
②ERROR 记录具有错误日志级别的消息
③WARN 表明会出现潜在错误的情形
④INFO 使用信息日志级别记录消息(默认)
⑤DEBUG 记录调试日志级别的错误
⑥TRACE 使用跟踪日志级别记录消息

需要和两个类打交道,并且只有两步
第一步,通过LogFactory获取Log类的实例; 第二步,使用Log实例的方法打日志

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

Log log = LogFactory.getLog(Main.class);  // Main为本类
log.info("start...");
log.warn("end.");

类名 描述
LogFactory 抽象类,日志工厂,获取日志类
LogFactoryImpl LogFactory的实现类,真正获取日志对象的地方
Log4JLogger 对log4j的日志对象封装
Jdk14Logger 对JDK1.4的日志对象封装
Jdk13LumberjackLogger 对JDK1.3以及以前版本的日志对象封装
SimpleLog commons-logging自带日志对象

使用Commons Logging时,如果在静态方法中引用Log,通常直接定义一个静态类型变量
在静态方法中引用Log

public class Main {
	static final Log log = LogFactory.getLog(Main.class);
	
	static void foo() {
		log.info("foo");
	}
}

在实例方法中引用Log,通常定义一个实例变量
在实例方法中引用Log

public class Person {
	protected final Log log = LogFactory.getLog(getClass());
	
	void foo() {
		log.info("foo");
	}
}

注意到实例变量log的获取方式是LogFactory.getLog(getClass()),虽然也可以用LogFactory.getLog(Person.class),但是前一种方式有个非常大的好处,就是子类可以直接使用该log实例

父类使用getLog(getClass()),子类可以直接使用log实例
在子类中使用父类实例化的log

public class Student extends Person {
	void bar() {
		log.info("bar");
	}
}

由于Java类的动态特性,子类获取的log字段实际上相当于LogFactory.getLog(Student.class),但却是从父类继承而来,并且无需改动代码

Commons Logging的日志方法,例如info(),除了标准的info(String)外,还提供了一个非常有用的重载方法:info(String, Throwable),这使得记录异常更加简单:

try {
} catch (Exception e) {
	log.error("got exception!", e);
}

log4j

Commons Logging,可以作为“日志接口”来使用。而真正的“日志实现”可以使用Log4j。
Log4j是一种非常流行的日志框架,是一个组件化设计的日志系统,它的架构大致如下
Java日志处理_第1张图片

使用Log4j输出一条日志时,Log4j自动通过不同的Appender把同一条日志输出到不同的目的地
(1)console:输出到屏幕
(2)file:输出到文件
(3)socket:通过网络输出到远程计算机
(4)jdbc:输出到数据库

Log4j也是一个第三方库,需要从这里下载Log4j
在这里插入图片描述

下载jar文件:https://logging.apache.org/log4j/2.x/download.html

以XML配置为例,使用Log4j的时候,把一个log4j2.xml的文件放到classpath下就可以让Log4j读取配置文件并按照我们的配置来输出日志



	
		
		%d{MM-dd HH:mm:ss.SSS} [%t] %-5level
			%logger{36}%n%msg%n%n
		
		log/err.log
		log/err.%i.log.gz
	
	
	
		
		
			
			
		
		
		
			
			
				
				
			
			
			
		
	
	
		
			
			
			
			
		
	

虽然配置Log4j比较繁琐,但一旦配置完成,使用起来就非常方便。对上面的配置文件,凡是INFO级别的日志,会自动输出到屏幕,而ERROR级别的日志,不但会输出到屏幕,还会同时输出到文件。并且,一旦日志文件达到指定大小(1MB),Log4j就会自动切割新的日志文件,并最多保留10份

在开发阶段,始终使用Commons Logging接口来写入日志,并且开发阶段无需引入Log4j。如果需要把日志写入文件, 只需要把正确的配置文件和Log4j相关的jar包放入classpath,就可以自动把日志切换成使用Log4j写入,无需修改任何代码

log4j.properties

在CLASSPATH 下建立log4j.properties
log4j.appender.stdout=org.apache.log4j.ConsoleAppender  
log4j.appender.stdout.Target=System.out  
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout  
log4j.appender.stdout.layout.ConversionPattern=%d %5p %c{1}:%L - %m%n

log4j.appender.file=org.apache.log4j.RollingFileAppender  
log4j.appender.file.File=${catalina.home}/logs/ddoMsg.log  
#log4j.appender.file.File=D:/SmgpAppService/logs/smgpApp.log  
log4j.appender.file.MaxFileSize=1024KB  
log4j.appender.file.MaxBackupIndex=100  
log4j.appender.file.layout=org.apache.log4j.PatternLayout  
log4j.appender.file.layout.ConversionPattern= %d{yyyy-MM-dd HH:mm:ss} %5p %c %t: - %m%n  
  
#INFO WARN ERROR DEBUG  
log4j.rootLogger=WARN, file, stdout  
#log4j.rootLogger=INFO,stdout  
org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog  
#org.apache.commons.logging.simplelog.log.org.apache.commons.digester.Digester=debug  
#org.apache.commons.logging.simplelog.log.org.apache.commons.digester.ObjectCreateRule=debug  
#org.apache.commons.logging.simplelog.log.org.apache.commons.digester.Digester.sax=info 
log4j.logger.com.jason.ddoMsg=debug 

logger配置说明

log4j.rootLogger=INFO, stdout , R
此句为将等级为INFO的日志信息输出到stdout和R这两个目的地,stdout和R的定义在下面的代码,可以任意起名。
等级可分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL,如果配置OFF则不打出任何信息,如果配置为INFO这样只显示INFO, WARN, ERROR的log信息,而DEBUG信息不会被显示

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
此句为定义名为stdout的输出端是哪种类型,可以是

org.apache.log4j.ConsoleAppender(控制台),
org.apache.log4j.FileAppender(文件),
org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件),
org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)
org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)

log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
此句为定义名为stdout的输出端的layout是哪种类型,可以是

org.apache.log4j.HTMLLayout(以HTML表格形式布局)
org.apache.log4j.PatternLayout(可以灵活地指定布局模式)
org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串)
org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)

log4j.appender.stdout.layout.ConversionPattern= [QC] %p [%t] %C.%M(%L) | %m%n
如果使用pattern布局就要指定的打印信息的具体格式ConversionPattern,打印参数如下:

格式 描述
[QC] log信息的开头,可以为任意字符,一般为项目简称
%m 输出代码中指定的消息
%p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
%r 输出自应用启动到输出该log信息耗费的毫秒数
%c 输出所属的类目,通常就是所在类的全名
%t 输出产生该日志事件的线程名
%n 输出一个回车换行符,Windows平台为“rn”,Unix平台为“n”
%d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,921
%l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数

输出的信息
[TS] DEBUG [main] AbstractBeanFactory.getBean(189) | Returning cached instance of singleton bean ‘MyAutoProxy’

log4j.appender.R=org.apache.log4j.DailyRollingFileAppender
此句与第3行一样。定义名为R的输出端的类型为每天产生一个日志文件

log4j.appender.R.File=D:\Tomcat 5.5\logs\qc.log
此句为定义名为R的输出端的文件名为D:\Tomcat 5.5\logs\qc.log可以自行修改

log4j.appender.R.layout=org.apache.log4j.PatternLayout
与第4行相同

log4j.appender.R.layout.ConversionPattern=%d-[TS] %p %t %c - %m%n
与第5行相同

log4j.logger.com. neusoft =DEBUG
指定com.neusoft包下的所有类的等级为DEBUG。
可以把com.neusoft改为自己项目所用的包名。

log4j.logger.com.opensymphony.oscache=ERROR
log4j.logger.net.sf.navigator=ERROR

这两句是把这两个包下出现的错误的等级设为ERROR,如果项目中没有配置EHCache,则不需要这两句

log4j.logger.org.apache.commons=ERROR
log4j.logger.org.apache.struts=WARN

这两句是struts的包

log4j.logger.org.displaytag=ERROR
这句是displaytag的包。(QC问题列表页面所用)

log4j.logger.org.springframework=DEBUG
此句为spring的包

log4j.logger.org.hibernate.ps.PreparedStatementCache=WARN
log4j.logger.org.hibernate=DEBUG

此两句是hibernate的包


以上这些包的设置可根据项目的实际情况而自行定制

log4j.rootLogger=DEBUG,console  

#以下是rootLogger的配置,子类默认继承,但是子类重写下面配置=rootLogger+自己配置
#输出到控制台     
log4j.appender.console=org.apache.log4j.ConsoleAppender    
#设置输出样式     
log4j.appender.console.layout=org.apache.log4j.PatternLayout   
#日志输出信息格式为  
log4j.appender.console.layout.ConversionPattern=[%-d{yyyy-MM-dd HH:mm:ss}]-[%t-%5p]-[%C-%M(%L)]: %m%n   

SLF4J和Logback

Commons Logging和Log4j(Simple logging这一对好基友,它们一个负责充当日志API,一个负责实现日志底层,搭配使facade for Java)用非常便于开发
SLF4J类似于Commons Logging,也是一个日志接口,而Logback类似于Log4j,是一个日志的实现

SLF4J对Commons Logging的接口有何改进。在Commons Logging中,要打印日志,有时候得这么写:

Log log = LogFactory.getLog(Main.class);  // Main为本类
int score = 99;
p.setScore(score);
log.info("Set score " + score + " for Person " + p.getName() + " ok.");

拼字符串是一个非常麻烦的事情,所以SLF4J的日志接口改进成这样了:

Logger log = LoggerFactory.getLogger(Main.class);  // Main为本类
int score = 99;
p.setScore(score);
logger.info("Set score {} for Person {} ok.", score, p.getName());

SLF4J的日志接口传入的是一个带占位符的字符串,用后面的变量自动替换占位符,所以看起来更加自然


SLF4J的接口实际上和Commons Logging几乎一模一样

Commons Logging SLF4J
org.apache.commons.logging.Log org.slf4j.Logger
org.apache.commons.logging.LogFactory org.slf4j.LoggerFactory
不同之处就是Log变成了Logger,LogFactory变成了LoggerFactory

logback同log4j相比具有众多优势
(1)更快的实现
(2)自动重新装载日志配置文件
(3)更好的过滤器(filter)
(4)自动压缩归档的日志文件
(5)堆栈跟踪里包括了Java包(jar文件)的信息
(6)自动删除旧日志归档文件

SLF4J:http://www.slf4j.org/download.html
Logback:https://logback.qos.ch/download.html

Java日志处理_第2张图片

使用SLF4J的Logger和LoggerFactory即可。和Log4j类似,仍然需要一个Logback的配置文件,把logback.xml放到classpath下




	
		
			%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
		
	

	
		
			%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
			utf-8
		
		log/output.log
		
			log/output.log.%i
		
		
			1MB
		
	

	
		
		
	

从目前的趋势来看,越来越多的开源项目从Commons Logging加Log4j转向了SLF4J加Logback

(1)SLF4J和Logback可以取代Commons Logging和Log4j
(2)始终使用SLF4J的接口写入日志,使用Logback只需要配置,不需要修改代码

  
  
  
      
      
      
          
          
              
            DEBUG  
              
            ACCEPT  
              
            DENY  
          
          
          
              
            %d{HH:mm:ss.SSS}[%-5level][%thread][%logger{20}]-%msg%n  
          
      
  
      
        
          
        logFile.log  
          
        true  
          
          %-4r [%thread] %-5level %logger{35} - %msg%n  
          
      
  
      
      
  
          
          
              
            INFO  
          
  
          
          
              
            E:/demo-%d{yyyy-MM-dd}.log  
              
            90  
          
  
          
            %d{HH:mm:ss.SSS}[%-5level][%thread][%logger{20}]-%msg%n  
              
            false  
          
      
  
      
      
          
          
          
      
  
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
 




上一篇:异常(throwable)                        下一篇:IDEA中使用SVN




你可能感兴趣的:(Java,java,jvm,开发语言)