53.javaEE-组件-javaLog

本文的架构如下
53.javaEE-组件-javaLog_第1张图片

一.log是什么?

学习java-log之前,我们先回忆下,我们最开始是怎么调试java的代码,是通过System.out.println()输出,定点输出查看代码的输出是否正确.所以我们先从System.out引入log.

1.java-log的介绍

(1)System.out
主要作用:
1.主要是帮我们查看程序的输出
2.帮助我们调试程序.
(2)System.out和log之间的区别

  1. system.out检验程序的输出比log方便,直接输出就可以了,log还需要调用log对象.
  2. system.out调试记录我们程序的注意的地方,log就比system.out强大太多了.log天生能控制输出日志的地方,比如console还是文件,日志的等级,日志输出内容格式等.

(3)产生log的原因
正是由于system.out输出日志有如下方面的弊端:
system.out做为日志的不合适:

  • 不能自由选择输出到文件或者控制台或者数据库等
  • 不能定义标准的输出等级,虽然我们也可以在system.out中通过文本控制,约束我们输出的等级,但是这样的约束太柔性了
  • 日志输出通常需要定位当前执行的线程或者类,还需要时间等等,但是system.out虽然也可以达到,但是需要自己写很多的代码,才能达到如此的功能.
  • 当我们实际开发时,由于开发的人员众多,system.out不能约束我们具体哪些包输出日志等级等等.

就是由于上述的system.out的弊端所以产生了log的需求.

2.自己设计java-log框架

从1得到,我们如果自己设计的框架比需满足我们的需求.
53.javaEE-组件-javaLog_第2张图片

二.java-log的常用框架

由于我们自己去开发这样的框架还是非常的花费时间,所以我们选择市面上的日志框架.

日志框架及组合
在这里插入图片描述
左边选一个门面(抽象层)、右边来选一个实现;
slf4j适配其他日志实现:
53.javaEE-组件-javaLog_第3张图片
遗留问题:
a(slf4j+logback): Spring(commons-logging)、Hibernate(jboss-logging)、MyBatis、xxxx 统一日志记录,即使是别的框架和我一起统一使用slf4j进行输出?
53.javaEE-组件-javaLog_第4张图片

1.JDKLog:日志小刀

JDKLog是JDK官方提供的一个记录日志的方式,直接在JDK中就可以使用。

public class JDKLog
{
     
    public static void main( String[] args )
    {
     
        Logger logger = Logger.getLogger("JDKLog");
        logger.info("Hello World.");
        logger.warning("本行代码有可能出现问题");
        logger.log(Level.ALL,"all日志输出");
    }
}

运行结果:
53.javaEE-组件-javaLog_第5张图片
总结:
JDKLog 的有点是使用非常简单,直接在 JDK 中就可以使用。但 JDKLog 功能比较太过于简单,不支持占位符显示,拓展性比较差,所以现在用的人也很少。

2.Log4J:日志大炮

Log4J 是 Apache 的一个日志开源框架,有多个分级(DEBUG/INFO/WARN/ERROR)记录级别,可以很好地将不同日志级别的日志分开记录,极大地方便了日志的查看。

Log4J 有 1.X 版本和 2.X 版本,现在官方推荐使用 2.X 版本,2.X 版本在架构上进行了一些升级,配置文件也发生了一些变化。但好在官方的配置说明文档非常清楚,通过查阅文档能解决大部分的问题。

步骤:
(1)导入jar包

<!-- 整合log4j -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.6.4</version>
        </dependency>

(2)配置log4j的配置文件

# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

(3)编写代码

package com.gl.jdk_log;


import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

/**
 * @ClassName Log4jLog
 * @Author gl
 * @Date 2020/4/18 15:17
 * @Description
 * Log4J Demo
 *  注意这里是org.apache.log4j下的包
 */
public class Log4jLog {
     

    public static void main(String args[]) {
     
        Logger logger = LogManager.getLogger(Log4jLog.class);
        logger.debug("Debug Level");
        logger.info("Info Level");
        logger.warn("Warn Level");
        logger.error("Error Level");
    }
}

(4)输出结果
单独使用log4j可能会导致log4j日志输出不成功
不成功:

log4j:WARN No appenders could be found for logger (com.gl.jdk_log.Log4jLog).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.

成功:

10:16:08.279 [main] INFO com.chanshuyi.Log4jLog - Info Level
10:16:08.280 [main] WARN com.chanshuyi.Log4jLog - Warn Level
10:16:08.280 [main] ERROR com.chanshuyi.Log4jLog - Error 

总结:
从上面的使用步骤可以看出 Log4J 的使用稍微复杂一些,但是条理还是很清晰的。而且因为 Log4J 有多个分级(DEBUG/INFO/WARN/ERROR)记录级别,所以可以很好地记
录不同业务问题。因为这些优点,所以在几年前几乎所有人都使用 Log4J 作为日志记录框架,群众基础可谓非常深厚。

但 Log4J 本身也存在一些缺点,比如不支持使用占位符,不利于代码阅读等缺点。但是相比起 JDKLog,Log4J 可以说是非常好的日志记录框架了。

3.LogBack:日志火箭

LogBack 其实可以说是 Log4J 的进化版,因为它们两个都是同一个人(Ceki Gülcü)设计的开源日志组件。LogBack 除了具备 Log4j 的所有优点之外,还解决了 Log4J 不能使用占位符的问题。

步骤:
1.导入jar包
其实这里可以和上面log4j的配置相同,因为logback是log4j的升级版

<!-- 整合log4j -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.6.4</version>
        </dependency>

2.编写配置文件
其实这里可以和上面log4j的配置相同,因为logback是log4j的升级版

# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

3.代码编写

注意导入的是org.slf4j下的

package com.gl.jdk_log;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @ClassName LogBack
 * @Author gl
 * @Date 2020/4/18 15:59
 * @Description
 * LogBack Demo
 */

public class LogBack {
     
    static final Logger logger = LoggerFactory.getLogger(LogBack.class);
    public static void main(String[] args) {
     
        logger.trace("Trace Level.");
        logger.debug("Debug Level.");
        logger.info("Info Level.");
        logger.warn("Warn Level.");
        logger.error("Error Level.");
    }
}

4.输出结果


DEBUG [main] - Debug Level
 INFO [main] - Info Level
 WARN [main] - Warn Level
ERROR [main] - Error Level

Process finished with exit code 0

LogBack 解决了 Log4J 不能使用占位符的问题,这使得阅读日志代码非常方便。除此之外,LogBack 比 Log4J 有更快的运行速度,更好的内部实现。并且 LogBack 内部集成了 SLF4J 可以更原生地实现一些日志记录的实现。

4.SLF4J:适配器

(1)产生的原因?
由于我们在开发的时候,有各种不同的相同,并且不同的项目有不同的日志框架,所以我们整合项目的时候需要把各种日志框架整合到一起,那怎么办?
一个最死板的方法就是一行行代码修改,把之前用 JDKLog 的日志代码全部修改成 Log4J 的日志接口。但是这种方式不仅效率低下,而且做的工作都是重复性的工作,这怎么能忍呢。
于是迫切需要我们有一种更加方便的框架api能够整合大部分的日志框架,就好比java的JDBC,其他的mysql,oracle只需要实现我们的api接口即可,我们只需要学习使用api就可以了,由此产生了slf4j
(2) slf4j的介绍
SLF4J(Simple Logging Facade for Java,即Java简单日志记录接口集)是一个日志的接口规范,它对用户提供了统一的日志接口,屏蔽了不同日志组件的差异。这样我们在编写代码的时候只需要看 SLF4J 这个接口文档即可,不需要去理会不同日之框架的区别。而当我们需要更换日志组件的时候,我们只需要更换一个具体的日志组件Jar包就可以了。
而整合 SLF4J 和日志框架使用也是一件很简单的事情。

(3)slf4j 整合其他log框架
由于slf4j的作用就是定义统一的api接口,所以只要是slf4j整合的log框架,不论是jdklog还是log4j还是logback,都只是导入的包不同,其配置文件和代码其实都是相同的.
步骤:
slf4j+JDKLog

  • 1.导入依赖

选择一:slf4j+jdklog的依赖

<!-- slf4j-JDKLog -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-jdk14</artifactId>
            <version>1.7.21</version>
        </dependency>

选择二:slf4j+log4j的依赖

<!-- slf4j-log4j -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.6.4</version>
        </dependency>

选择三:slf4j+logback的依赖

<properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <logback.version>1.2.3</logback.version>
        <slf4j.version>1.7.21</slf4j.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${
     slf4j.version}</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>${
     logback.version}</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>${
     logback.version}</version>
        </dependency>
    </dependencies>
  • 2.书写配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
    <!-- 1、Appenders -->
    <!--日志输出到控制台-->
    <appender name="console" class="org.apache.log4j.ConsoleAppender">
        <param name="Target" value="System.out"/>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c - %m%n"/>
        </layout>
    </appender>
    <!--日志输出到文件中-->
    <!--每天产生一个日志文件,文件所在位置为项目目录下面的logs文件夹中,文件名为server.log-->
    <appender name="file" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="File" value="logs/server.log"/>
        <param name="DatePattern" value="'.'yyyy-MM-dd'.log'"/>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss.SSS\} %-5p] [%t] %c{3\} - %m%n"/>
        </layout>
    </appender>
    <!--2、Application Logs-->
    <logger name="com.zhoujie">
        <level value="info"/>
    </logger>
    <!-- 3rdparty Loggers -->
    <logger name="org.springframework.core">
        <level value="info"/>
    </logger>
    <logger name="org.springframework.beans">
        <level value="info"/>
    </logger>
    <logger name="org.springframework.context">
        <level value="info"/>
    </logger>
    <logger name="org.springframework.web">
        <level value="info"/>
    </logger>
    <logger name="org.springframework.jdbc">
        <level value="info"/>
    </logger>
    <logger name="org.mybatis.spring">
        <level value="info"/>
    </logger>
    <logger name="java.sql">
        <level value="info"/>
    </logger>
    <logger name="java.sql">
        <level value="info"/>
    </logger>
    <logger name="net.sf.ehcache.store.disk.Segment">
        <level value="warn"/>
    </logger>
    <!--Root Logger-->
    <root>
        <priority value="debug"/>
        <appender-ref ref="console"/>
        <!--<appender-ref ref="file"/>-->
    </root>
</log4j:configuration>
  • 3.编写代码
package com.gl.jdk_log;

/**
 * @ClassName Slf4jJDKLog
 * @Author gl
 * @Date 2020/4/18 16:25
 * @Description
 *
 * SLF4J + JDKLog
 */

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class Slf4jJDKLog {
     

    final static Logger logger = LoggerFactory.getLogger(Slf4jJDKLog.class);

    public static void main(String[] args) {
     
        logger.trace("Trace Level.");
        logger.info("Info Level.");
        logger.warn("Warn Level.");
        logger.error("Error Level.");
    }
}

  • 测试结果
2020-04-18 16:34:43 INFO  com.gl.jdk_log.Slf4jJDKLog - Info Level.
2020-04-18 16:34:43 WARN  com.gl.jdk_log.Slf4jJDKLog - Warn Level.
2020-04-18 16:34:43 ERROR com.gl.jdk_log.Slf4jJDKLog - Error Level.

三.使用日志的注意事项

我们选择一个日志,到使用日志是由非常大的讲究的,每一个日志框架都关系着以后程序的bug调试.所以我们考虑log有以下三个方面也要考虑.

1.选择框架

选择slf4j+logback的原因:

  1. LogBack 自身实现了 SLF4J 的日志接口,不需要 SLF4J 去做进一步的适配。
  2. LogBack 自身是在 Log4J 的基础上优化而成的,其运行速度和效率都比 LOG4J 高。
  3. SLF4J + LogBack 支持占位符,方便日志代码的阅读,而 LOG4J 则不支持。

从上面几点来看,SLF4J + LogBack是一个较好的选择。

LogBack 被分为3个组件:logback-core、logback-classic 和 logback-access。

  • logback-core 提供了 LogBack 的核心功能,是另外两个组件的基础。
  • logback-classic 则实现了 SLF4J 的API,所以当想配合 SLF4J 使用时,需要将 logback-classic
    引入依赖中。
  • logback-access 是为了集成Servlet环境而准备的,可提供HTTP-access的日志接口。

2.配置文件的配置

logback的配置文件(其实不仅仅是logback,所有的slf4j的配置文件都可以用)
这是配置文件的架构图.如咱们自己设想的日志框架应该满足的,这里都能满足.
53.javaEE-组件-javaLog_第6张图片
LogBack配置文件可以分为几个节点,其中 Configuration 是根节点,Appender、Logger、Root是Configuration的子节点。
1)appender节点
是的子节点,是负责写日志的组件。

主要作用:
1.定义输出地方,控制台还是文件
2.控制是否异步
3.控制输出的log语句的格式

appender有两个必要属性name、class 。name指定appender的名称,class指定appender的全限定名class,主要包括:

  • ch.qos.logback.core.ConsoleAppender 控制台输出

  • ch.qos.logback.core.FileAppender 文件输出

  • ch.qos.logback.core.RollingFileAppender 文件滚动输出

  • ch.qos.logback.classic.AsyncAppender异步输出

(1)ConsoleAppender
把日志添加到控制台,有如下节点:
encoder : 对日志进行格式化。
target : 字符串System.out 或者 System.err, 默认 System.out;
pattern:定义输出的格式-详情请参考官网

  <?xml version="1.0" encoding="utf-8"?>
<configuration>
	<!-- conf consoel out -->
	<appender name ="console_out" class="ch.qos.logback.core.ConsoleAppender">
		<encoder>
		<pattern>%date [%thread] %-5level %logger - %message%newline</pattern>
		</encoder>
	</appender>

	<root level="INFO">
		<appender-ref ref="console_out" />
	</root>
</configuration>

(2)FileAppender
把日志添加到文件,有如下节点:
file:被写入的文件名,可以是相对目录 , 也可以是绝对目录 , 如果目录不存在则会自动创建。
append:如果是true , 日志被追加到文件结尾 , 如果是false,清空现存文件 , 默认是true。
encoder:对日志进行格式化 [具体的转换符说明请参见官网.]

<?xml version="1.0" encoding="utf-8"?>
<configuration>
	<appender name="file_out" 	class="ch.qos.logback.core.FileAppender">
		<file>logs/debug.log</file>
		<encoder>
		<pattern>%date [%thread] %-5level %logger - %message%newline</pattern>
		</encoder>
	</appender>
</configuration>

(3)rollingFileAppender
滚动纪录文件,先将日志记录到指定文件,当符合某种条件时,将日志记录到其他文件,有如下节点:

 <appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <encoder>
            <pattern>%d -- %msg%n</pattern>
        </encoder>
        <!--滚动策略-->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--路径-->
            <fileNamePattern>e:/info-%d.log</fileNamePattern>
        </rollingPolicy>
    </appender>
https://blog.csdn.net/duguxiaobiao/article/details/78988409

(4)AsyncAppender

<!-- 异步输出 -->  
21     <appender name ="ASYNC" class= "ch.qos.logback.classic.AsyncAppender">  
22         <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->  
23         <discardingThreshold>0</discardingThreshold>  
24         <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->  
25         <queueSize>256</queueSize>  
26         <!-- 添加附加的appender,最多只能添加一个 -->  
27         <appender-ref ref ="ROLLING-FILE-1"/>  
28     </appender>

2)logger节点

logger是的子节点,来设置某一个包或者具体的某一个类的日志打印级别,以及指定。

logger节点的作用: 指定特定包下或者类的日志输出级别.

logger仅有一个name属性,两个可选属性 level/addtivity。
name:用来指定受此loger约束的某一个包或者具体的某一个类。
level:用来设置打印级别,大小写无关。可选值有TRACE、DEBUG、INFO、WARN、ERROR、ALL和OFF。还有一个特俗值INHERITED 或者 同义词NULL,代表强制执行上级的级别。如果未设置此属性,那么当前logger将会继承上级的级别。
addtivity:是否向上级logger传递打印信息,默认为true;
可以包含零个或多个元素,表示这个appender将会添加到logger。

 	 <logger name="java" additivity="false" />
     <logger name="java.lang" level="DEBUG">
         <appender-ref ref="STDOUT" />
     </logger>

3)root节点
元素配置根logger。其实就是相当于所有路劲的根路径,指定配置全局的日志输出,如果其子节点中也就是logger中已经配置了包下的输出级别,则以logger为准,没有配置则以root为准.
该元素有一个level属性,没有name属性,因为已经被命名 为root。Level属性的值大小写无关,其值为下面其中一个字符串:TRACE、DEBUG、INFO、 WARN、ERROR、ALL 和 OFF。如果 root 元素没 有引用任何 appender,就会失去所有 appender。

	 <root level="INFO">
         <appender-ref ref="STDOUT" />
     </root>

4)filter过滤节点

级别过滤器(LevelFilter)
LevelFilter 根据记录级别对记录事件进行过滤。如果事件的级别等于配置的级别,过滤 器会根据 onMatch 和 onMismatch 属性接受或拒绝事件。下面是个配置文件例子:

<filter class="ch.qos.logback.classic.filter.LevelFilter">
	<!-- 过滤掉非INFO级别 -->
	<level>INFO</level>
	<onMatch>ACCEPT</onMatch>
	<onMismatch>DENY</onMismatch>
</filter>

临界值过滤器(ThresholdFilter)
ThresholdFilter过滤掉低于指定临界值的事件。

<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
	<!-- 过滤掉TRACE和DEBUG级别的日志 -->
	<level>INFO</level>
</filter>

求值过滤器(EvaluatorFilter)
评估是否符合指定的条件

<filter class="ch.qos.logback.classic.filter.EvaluatorFilter">
	<evaluator>
		<!--过滤掉所有日志中不包含hello字符的日志-->
		<expression>
			message.contains("hello")
		</expression>
		<onMatch>NEUTRAL</onMatch>
		<onMismatch>DENY</onMismatch>
	</evaluator>
</filter>

匹配器(Matchers)

<matcher>
	<Name>odd</Name>
	<!-- 过滤掉序号为奇数的语句-->
	<regex>statement [13579]</regex>
</matcher>

参考配置文件:

<?xml version="1.0" encoding="UTF-8"?>

<!-- 从高到地低 OFF 、 FATAL 、 ERROR 、 WARN 、 INFO 、 DEBUG 、 TRACE 、 ALL -->
<!-- 日志输出规则  根据当前ROOT 级别,日志输出时,级别高于root默认的级别时  会输出 -->
<!-- 以下  每个配置的 filter 是过滤掉输出文件里面,会出现高级别文件,依然出现低级别的日志信息,通过filter 过滤只记录本级别的日志-->


<!-- 属性描述 scan:性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
    debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false-->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <!-- 定义日志文件 输入位置 -->
    <property name="log_dir" value="${sky.rest.log.dir}" />
    <!-- 日志最大的历史 30-->
    <property name="maxHistory" value="30"/>
    <!-- ConsoleAppender 控制台输出日志 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 对日志进行格式化 -->
        <encoder>
            <pattern>%d{
     yyyy-MM-dd HH:mm:ss} %X{
     threadId} %-5level %logger %msg%n</pattern>
        </encoder>
    </appender>
    <!--<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">-->

    <!--&lt;!&ndash;<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">&ndash;&gt;-->
    <!--<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.QTracePatternLogbackLayout">-->
    <!--&lt;!&ndash; 对日志进行格式化 &ndash;&gt;-->
    <!--<pattern>%d{
     yyyy-MM-dd HH:mm:ss} - %app %tid %host %X{
     type} [%thread] %-5level %logger %msg%n</pattern>-->
    <!--</layout>-->
    <!--</appender>-->

    <!-- ERROR级别日志 -->
    <!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 RollingFileAppender-->
    <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录WARN级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!-- 最常用的滚动策略,它根据时间来制定滚动策略.既负责滚动也负责出发滚动 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志输出位置  可相对、和绝对路径 -->
            <fileNamePattern>${
     log_dir}/%d{
     yyyy-MM-dd}/error.log</fileNamePattern>
            <!-- 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件假设设置每个月滚动,且<maxHistory>6,
            则只保存最近6个月的文件,删除之前的旧文件。注意,删除旧文件是,那些为了归档而创建的目录也会被删除-->
            <maxHistory>${
     maxHistory}</maxHistory>
        </rollingPolicy>

        <encoder>
            <pattern>%d{
     yyyy-MM-dd HH:mm:ss.SSS} %X{
     threadId} %-5level %logger %msg%n</pattern>
        </encoder>
    </appender>

    <!-- WARN级别日志 appender -->
    <appender name="WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录WARN级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>WARN</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 按天回滚 daily -->
            <fileNamePattern>${
     log_dir}/%d{
     yyyy-MM-dd}/warn.log
            </fileNamePattern>
            <!-- 日志最大的历史 60-->
            <maxHistory>${
     maxHistory}</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d{
     yyyy-MM-dd HH:mm:ss.SSS} %X{
     threadId} %-5level %logger %msg%n</pattern>
        </encoder>
    </appender>

    <!-- INFO级别日志 appender -->
    <appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录INFO级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 按天回滚 daily -->
            <fileNamePattern>${
     log_dir}/%d{
     yyyy-MM-dd}/info.log
            </fileNamePattern>
            <!-- 日志最大的历史 60-->
            <maxHistory>${
     maxHistory}</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d{
     yyyy-MM-dd HH:mm:ss.SSS} %X{
     threadId} %-5level %logger %msg%n</pattern>
        </encoder>
    </appender>

    <!-- DEBUG级别日志 appender -->
    <appender name="DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录DEBUG级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>DEBUG</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 按天回滚 daily -->
            <fileNamePattern>${
     log_dir}/%d{
     yyyy-MM-dd}/debug.log
            </fileNamePattern>
            <!-- 日志最大的历史 60-->
            <maxHistory>${
     maxHistory}</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d{
     yyyy-MM-dd HH:mm:ss.SSS} %X{
     threadId} %-5level %logger %msg%n</pattern>
        </encoder>
    </appender>

    <!-- TRACE级别日志 appender -->
    <!--<appender name="TRACE" class="ch.qos.logback.core.rolling.RollingFileAppender">  -->
    <!--&lt;!&ndash; 过滤器,只记录ERROR级别的日志 &ndash;&gt;  -->
    <!--<filter class="ch.qos.logback.classic.filter.LevelFilter">  -->
    <!--<level>TRACE</level>  -->
    <!--<onMatch>ACCEPT</onMatch>  -->
    <!--<onMismatch>DENY</onMismatch>  -->
    <!--</filter>  -->
    <!--<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  -->
    <!--&lt;!&ndash; 按天回滚 daily &ndash;&gt;  -->
    <!--<fileNamePattern>${
     log_dir}/%d{
     yyyy-MM-dd}/trace-log.log  -->
    <!--</fileNamePattern>  -->
    <!--&lt;!&ndash; 日志最大的历史 60&ndash;&gt;  -->
    <!--<maxHistory>${
     maxHistory}</maxHistory>  -->
    <!--</rollingPolicy>  -->
    <!--<encoder>  -->
    <!--<pattern>%d{
     yyyy-MM-dd HH:mm:ss.SSS} %X{
     threadId} %-5level %logger %msg%n</pattern>  -->
    <!--</encoder>  -->
    <!--</appender>  -->

    <!-- DEBUG级别日志 appender -->
    <appender name="ROOT" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 按天回滚 daily -->
            <fileNamePattern>${
     log_dir}/%d{
     yyyy-MM-dd}/root.log
            </fileNamePattern>
            <!-- 日志最大的历史 60-->
            <maxHistory>${
     maxHistory}</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d{
     yyyy-MM-dd HH:mm:ss.SSS} %X{
     threadId} %-5level %logger %msg%n</pattern>
        </encoder>
    </appender>

    <logger name="java.sql.PreparedStatement" level="DEBUG" />
    <logger name="java.sql.Connection" level="DEBUG" />
    <logger name="java.sql.Statement" level="DEBUG" />
    <logger name="com.ibatis" level="DEBUG" />
    <logger name="com.ibatis.common.jdbc.SimpleDataSource" level="DEBUG" />
    <logger name="com.ibatis.common.jdbc.ScriptRunner" level="DEBUG"/>
    <logger name="com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate" level="DEBUG" />
    <logger name="com.qihoo" level="DEBUG" additivity="true">
        <appender-ref ref="INFO" />
    </logger>

    <!-- root级别   DEBUG -->
    <root level="INFO">
        <!-- 控制台输出 -->
        <appender-ref ref="STDOUT" />
        <appender-ref ref="ROOT" />
        <!-- 文件输出 -->
        <appender-ref ref="DEBUG" />
        <appender-ref ref="WARN" />
        <appender-ref ref="ERROR" />
    </root>
</configuration>

3.代码中怎样书写log语句

(1)logger对象的获取方式

  • 使用继承抽象类的方式,获取logger对象

父类代码

public class AbstractLogger {
     
    //只有自己和子类才能获取logger对象,getclass(),是调用本类的getclass()方法.
    protected Logger logger = LoggerFactory.getLogger(getClass());
}

子类代码

public class Slf4jJDKLog  extends AbstractLogger{
     

    //这个logger对象就是继承自抽象类中的属性logger
    @Test
    public void testLogger(){
     
        logger.info("你好中国");
    }
}

  • 使用@slf4j注解的方式自动生成logger对象
@Slf4j //这是生成logger对象
@Service
public class CompanyService {
     
    @Autowired
    private CompanyDao companyDao;

    @Autowired
    private IdWorker idWorker;
    /**
     * 保存企业
     *  1.配置idwork到工程
     *  2.在service中注入idwork
     *  3.通过idwork生成id
     *  4.保存企业
     */
    public void add(Company company) {
     
    	//使用logger对象
        log.info("这是slf4j生成的logger对象");
        //基本属性的设置
        String id = idWorker.nextId()+"";
        company.setId(id);
        //默认的状态
        company.setAuditState("0");//0:未审核,1:已审核
        company.setState(1); //0.未激活,1:已激活
        companyDao.save(company);
    }
}

(2)项目中使用log日志的注意事项

1、tomcat配置access日志,记录每次http请求相关信息

2、dubbo配置access日志,记录dubbo consumer和provider的每次请求调用和处理

3、在系统里调用外部的地方,记录请求的接口、参数、返回结果、花费时间、遇到的异常等

4、在系统里出现异常的地方,记录异常的堆栈,如果可以,尽量通过异常的日志能还原当时的情景,比如当时受影响的是哪个用户、传入的变量是什么、处理哪些核心数据引发的异常等等

5、有些代码在编写时就知道很难被执行到或者不希望被执行到、以及一些基本不会走到的else块,这些地方需要记录下核心日志

6、禁止使用 System.out 或 System.error

7、禁止使用 Apache Commons Logging , Java Util
Logging,推荐使用slf4j,推荐使用Logback,代码中使用Slf4j记录日志

8、业务日志使用独立的日志配置,不能采用className。举个例子,我之前在qunar做项目时,涉及打通许多第三方管理系统,和每一个第三方的交互的日志都会单独存储到一个日志文件中

9、INFO及以上的系统日志统一输出到Console。在生产环境中如果将系统log切分成多个文件, 是非常不利于问题排查的.
不仅要同时追找多个文件, 还要匹配问题发生的时间点. 最要命的是, 有些异常是被print到 console里的。

10、日志配置Rolling,可以根据实际情况配置按天、按小时进行轮转,生成新的日志文件

11、记录程序状态需要包含发生时间(一般框架里就会带上)、大数据量更新的进度、关键变量及正在做哪些重要事情。

12、不同的日志文件尽量使用同样的格式输出(logback配置同样的pattern), 这样方便脚本通用及第三方解析

四.项目中出现问题怎么使用log定义错误

一般我们的项目都是发布在linux系统的服务器上,一般log文件夹在项目的目录下,我们直接进入项目目录下就行.
步骤:
1.进入log文件目录下

[root@XX db]# cd log/

2.vim 进入文件

[root@XX db]# vim 20200419.app.txt 

3.命令模式下
/全局跟踪号
根据全局跟踪号,查找我们想要查找的日志文件,根据日志查看我们的请求报文,相应报文等.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
/201213123     

或者
:全局跟踪号?

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
:201213123?  

你可能感兴趣的:(javaEE,框架)