如何在WEB项目中优雅的使用日志

一:常见的日志框架
Log4j、SLF4J、Logback、Log4j 2

一般选用Log4j+SLF4J
或者单独 Logback

1、为什么需要在 Java 中打印日志 ?
在本地环境下,使用 System.out.println() 打印日志是没问题的,可以在控制台看到信息。但如果是在生产环境下的话, System.out.println() 就变得毫无用处了。
2.常见的日志级别
使用 Java 日志的时候,一定要注意日志的级别,比如常见的 DEBUG、INFO、WARN 和 ERROR。
DEBUG 的级别最低,当需要打印调试信息的话,就用这个级别,不建议在生产环境下使用。
INFO 的级别高一些,当⼀些重要的信息需要打印的时候,就用这个。
WARN,用来记录一些警告类的信息,比如说客户端和服务端的连接断开了了,数据库连接丢失了。
ERROR 比 WARN 的级别更高,用来记录错误或者异常的信息。
FATAL,当程序出现致命错误的时候使用,这意味着程序可能非正常中止了了。
OFF,最高级别,意味着所有消息都不会输出了

解释:使用高级别的日志,那么比他低的级别都不会输出

3.日志记录方式是如何影响性能的
1).日志记录的次数越多,意味着执行文件 IO 操
作的次数就越多
2).对于 DEBUG 级别的日志来说,⼀定要使用下面的方式来记录:

  if(logger.isDebugEnabled()){
     
logger.debug("DEBUG 是开启的");
}

3)切记,在生产环境下,一定不要开启 DEBUG 级别的日志,否则程序在大量记录日志的时候会变很慢,还有可能在你不注意的情况下,悄悄地把磁盘空间撑爆
4)慎重选择日志信息的打印级别,所以,该 INFO 的 info() ,该 DEBUG 的 debug() ,不要随便用。
5)使用 Log4j 而不是 System.out 、 System.err 或者 e.printStackTrace() 来打印日志
6)使用 log4j.properties 文件来配置日志,尽管它不是必须项,使用该文件会让程序变得更灵活。
5)不要忘记在打印日志的时候带上类的全名和线程名,在多线程环境下,这点尤为重要,否则定位问题的时候就太难了了。
6)打印日志信息的时候尽量要完整,不要太过于缺省。
7)不要在日志文件中打印密码、银行账号等敏感信息。

二:几种日志框架详解
Log4j
1.优点:
1): Log4j 的另外一个好处就是,不需要重新启动 Java 程序就可以调整日志的记录级别,非常灵活。
2): 可以通过 log4j.properties 文件来配置 Log4j 的日志级别、输出环境、日志文件的记录方式。
3):Log4j 还是线程安全的,可以在多线程的环境下放心使用
2.使用方式
第⼀步,在 pom.xml 文件中引⼊入 Log4j 包:

<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>

第二步,在 resources 目录下创建 log4j.properties 文件,内容如下所示:

### 设置###
log4j.rootLogger = debug,stdout,D,E
### 输出信息到控制台 ###
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 = [%-5p] %d{yyyy-MM-dd
HH:mm:ss,SSS} method:%l%n%m%n
### 输出DEBUG 级别以上的⽇日志到=debug.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = debug.log
log4j.appender.D.Append = true
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
- ### 输出ERROR 级别以上的⽇日志到=error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =error.log
log4j.appender.E.Append = true
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

例子:

public class Log4jDemo {
     
private static final Logger logger =
LogManager.getLogger(Log4jDemo.class);
public static void main(String[] args) {
     
// 记录debug级别的信息
logger.debug("debug.");
// 记录info级别的信息
logger.info("info.");
// 记录error级别的信息
logger.error("error.");
}
}

1)获取 Logger 对象
要使用 Log4j 的话,需要先获取到 Logger 对象,它用来负责日志信息的打印。通常的格式如下所示:

private static final Logger logger = LogManager.getLogger(Log4jDemo.class);

2)打印日志
有了 Logger 对象后,就可以按照不同的优先级打印日志了了。常见的有以下 4 种:

Logger.debug() ;
Logger.info() ;
Logger.warn() ;
Logger.error() ;

SLF4
1.是什么?
SLF4J 是 Simple Logging Facade for Java 的缩写(for≈4),也就是简易的日志门⾯面,以外观模式(Facade pattern,一种设计模式,为子系统中的一组接口提供一个统一的高层接口,使得子系统更容易使用)实现,支持 java.util.logging、Log4J 和 Logback。

日志系统有 JUL、JCL,Ceki Gulcu 自己又写了 2 种,Log4j 和 Logback,各有各的优缺点,再加上使用者千千万,萝卜白菜各有所爱,这就导致不同的应用可能会用不同的日志系统。
假设我们正在开发一套系统,打算用 SLF4J 作为门面,Log4j 作为日志系统,我们在项目中使用了 A 框架,而 A 框架的门面是 JCL,日志系统是JUL,那就相等于要维护两套日志系统
2.阿里巴巴开发
手册有一条「强制」性质的日志规约:
应用中不可以直接使用日志系统(Log4j、Logback)中的 API,而应该使用日志框架中的 API,
比如说 SLF4J,使用门面模式的日志框架,有利于维护和统一各个类的日志处理方式。
优点:
1.帮助我们的应用程序独立于任何特定的日志系统,还有⼀个非常牛逼的功能,
2.SLF4J 在打印日志的时候使用了占位符 {} ,它有点类似于 String 类的 format() 方法
(使用 %s 等填充参数),但更加便捷,这在很大程度上提高了程序的性能。
众所周知,字符串是不可变的,字符串拼接会创建很多不不必要的字符串对象,极大的消耗了内存空间。
但 Log4J 在打印带参数的⽇日志时,只能使用字符串拼接的方式:

String name = "高小秋";
int age = 18;
logger.debug(name + ",年年纪:" + age + ",是个非常不要脸的程序员");

非常笨重,但加入了 SLF4J 后,这个问题迎刃而解。我们来看一下在 Log4j 项目中加入 SLF4J 的详细的
步骤:
第一步,把 log4j 的依赖替换为 slf4j-log4j12(Maven 会自动引⼊入 slf4j-api.jar 和 log4j.jar)

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>

第二步,在 resources 目录下创建 log4j.properties 文件,

### 设置###
log4j.rootLogger = debug,stdout,D,E
### 输出信息到控制台 ###
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 = [%-5p] %d{
     yyyy-MM-dd
HH:mm:ss,SSS} method:%l%n%m%n
### 输出DEBUG 级别以上的⽇日志到=debug.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = debug.log
log4j.appender.D.Append = true
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
### 输出ERROR 级别以上的日志到=error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =error.log:
看到了吧,使用占位符要比“+”操作符方便的多。并且此时不再需要  isDebugEnabled() 先进行判
断, debug() ⽅法会在字符串拼接之前执行。
如果只是 Log4J 的话,会先进行字符串拼接,再执行  debug() ⽅法,来看示例例代码:
在调试这段代码的时候,你会发现的,如下图所示:
log4j.appender.E.Append = true
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

第三步,新建测试类:

package com.itwanger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author 
*/
public class Log4jSLF4JDemo {
     
private static final Logger logger =
LoggerFactory.getLogger(Log4jSLF4JDemo.class);
public static void main(String[] args) {
     
logger.debug("{},是个非常不要脸的程序员","高小秋");
}
}

logger.debug("高小秋,{}岁", 18);

1)在使⽤日志系统的时候,⼀定要使用 SLF4J 作为门面担当。
2)SLF4J 可以统一日志系统,作为上层的抽象接口,不需要关注底层的日志实现,可以是 Log4j,也可以是 Logback,或者 JUL、JCL。
3)SLF4J 在打印日志的时候可以使用占位符,既提高了了程序性能(临时字符串少了,垃圾回收的工作量就小),又让代码变得美观统一。

Logback

1.优点:
1)非常自然地实现了 SLF4J,不需要像 Log4j 和 JUL 那样加⼀个适配层
如何在WEB项目中优雅的使用日志_第1张图片
2)Spring Boot 的默认日志框架使用的是 Logback。
3)支持自动重新加载配置文件,不要另外创建扫描线程来监视。
使用步骤:
第⼀步,在 pom.xml 文件中添加 Logback 的依赖:

<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>

第二步,来个最简单的测试用例

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author
*/
public class Test {
     
static Logger logger = LoggerFactory.getLogger(Test.class);
public static void main(String[] args) {
     
logger.debug("logback");
}
}

Logger 和 LoggerFactory 都来自 SLF4J,所以如果项⽬目是从 Log4j + SLF4J 切换到 Logback 的话,此时
的代码是零改动的。

在没有配置文件的情况下,一切都是默认的,Logback 的日志信息会输出到控制台。可以通过
StatusPrinter 来打印 Logback 的内部信息

LoggerContext lc = (LoggerContext)LoggerFactory.getILoggerFactory();
StatusPrinter.print(lc);

Logback 会在 classpath 路径下先寻找 logback-test.xml 文件,没有找到的话,寻找
logback.groovy 文件,还没有的话,寻找 logback.xml ⽂件,都找不到的话,就输出到控制台。
⼀般来说,我们会在本地环境中配置 logback-test.xml,在生产环境下配置 logback.xml。

第三步,在 resource 目录下增加 logback-test.xml 文件,内容如下所示:

<configuration debug="true">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{
     HH:mm:ss.SSS} %relative [%thread] %-5level %logger{
     36}
- %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>
1)配置 appender,也就是配置日志的输出目的地,通过 name 属性指定名字,通过 class 属性指定
目的地:
ch.qos.logback.core.ConsoleAppender:输出到控制台。
ch.qos.logback.core.FileAppender:输出到文件。
ch.qos.logback.core.rolling.RollingFileAppender:文件⼤小超过阈值时产生⼀个新文件。
除了了输出到本地,还可以通过 SocketAppender 和 SSLSocketAppender 输出到远程设备,通过
SMTPAppender 输出到邮件。甚⾄至可以通过 DBAppender 输出到数据库中。
encoder 负责把日志信息转换成字节数组,并且把字节数组写到输出流。
pattern ⽤来指定⽇志的输出格式:
%d :输出的时间格式。
%thread :日志的线程名。
%-5level :日志的输出级别,填充到 5 个字符。比如说 info 只有 4 个字符,就填充一个空格,
这样⽇志信息就对齐了了。```
2)配置 root,它只⽀支持⼀一个属性——level,值可以为:TRACE、DEBUG、INFO、WARN、ERROR、
ALL、OFF。
3)⾃动重载配置。
之前提到 Logback 很强的⼀个功能就是支持自动重载配置,那想要启⽤用这个功能也非常简单,只需要在
configuration 元素上添加  scan=true 即可。

默认情况下,扫描的时间间隔是⼀分钟一次。如果想要调整时间间隔,可以通过 scanPeriod 属性进行
调整,单位可以是毫秒(milliseconds)、秒(seconds)、分钟(minutes)或者小时(hours)。
下⾯这个示例指定的时间间隔是 30 秒:
<configuration scan="true" scanPeriod="30 seconds"
...
</configuration>

03、把 log4j.properties 转成 logback-test.xml
如果你的项目以前用的 Log4j,那么可以通过下面这个⽹网址把 log4j.properties 转成 logback-
test.xml:
http://logback.qos.ch/translator/

你可能感兴趣的:(Java)