1.logback日志的使用 2.使用new Throwable打印出当前堆栈 3.Exception的打印方法

最简单版本的logback.xml

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
    <property name="LOG_DIR" value="./logs"/>

    <!--带高亮显示-->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%highlight(%-5level)] [%thread] %logger{30}.%M\(%F:%L\) - %msg%n</pattern>
        </encoder>
    </appender>

    <!--这个会被异步打印里面调用-->
    <appender name="ROLLFILE"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_DIR}/game.log</file>
        <rollingPolicy
                class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_DIR}/game.%d{yyyyMMdd}.log</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>[%-5level][%d{HH:mm:ss.SSS}][%thread][%logger][%L] - %msg%n</pattern>
        </encoder>
    </appender>

    <!--异步打印-->
    <appender name="ASYNC_ROLLFILE" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="ROLLFILE"/>
        <queueSize>1024</queueSize>
        <maxFlushTime>3000</maxFlushTime>
    </appender>


    <root level="debug">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="ASYNC_ROLLFILE"/>
    </root>
</configuration>

=====================

SpringBoot 5.2关服钩子日志打印不出来。 这是因为关服时,有自己的钩子导致日志先于我们的钩子关闭,我们禁用掉,使用自己的钩子。修改: application.properties

logging.register-shutdown-hook=false

==============1.基础知识================

1)基于门面模式的实现。也就是slf4j这种提供接口,logback提供实现。 而且自动查找logback.xml。

2)先配置好输出什么:如 线程、行数、时间、日志级别等。。

    再配置好以什么方式输出:如 控制台、文件。 基本上logback的设计都是基于反射,配置的xml,其实就是调用set方法进行设置。而且设置的有实现类。

3)可以自定义输出格式:如哪个包下,以什么样的日志级别输出。

4)支持文件的切割,比如:以日期来作为文件命名,超过多大后,进行按照0、1、2、3这样子切割。

5)支持压缩,文件过大,可以压缩为:xxx.gz

6)支持异步输出,不阻塞打印线程。 原理是基于BlockingQueue。

===============2.logback的使用================

pom.xml

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

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

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

配置例子:

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

    <!--
        配置集中管理属性
        我们可以直接改属性的 value 值
        格式:${name}
    -->
    <property name="pattern" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n"></property>
    <!--
    日志输出格式:
        %-5level
        %d{yyyy-MM-dd HH:mm:ss.SSS}日期
        %c类的完整名称
        %M为method
        %L为行号
        %thread线程名称
        %m或者%msg为信息
        %n换行
      -->
    <!--定义日志文件保存路径属性-->
    <property name="log_dir" value="/logs"></property>


    <!--控制台日志输出的 appender-->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <!--控制输出流对象 默认 System.out 改为 System.err-->
        <target>System.err</target>
        <!--日志消息格式配置-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
        </encoder>
    </appender>

    <!--日志文件输出的 appender-->
    <appender name="file" class="ch.qos.logback.core.FileAppender">
        <!--日志文件保存路径-->
        <file>${log_dir}/logback.log</file>
        <!--日志消息格式配置-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
        </encoder>
    </appender>

    <!--html 格式日志文件输出 appender-->
    <appender name="htmlFile" class="ch.qos.logback.core.FileAppender">
        <!--日志文件保存路径-->
        <file>${log_dir}/logback.html</file>
        <!--html 消息格式配置-->
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="ch.qos.logback.classic.html.HTMLLayout">
                <pattern>%-5level%d{yyyy-MM-dd HH:mm:ss.SSS}%c%M%L%thread%m</pattern>
            </layout>
        </encoder>
    </appender>


    <!--日志拆分和归档压缩的 appender 对象-->
    <appender name="rollFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--日志文件保存路径-->
        <file>${log_dir}/roll_logback.log</file>
        <!--日志消息格式配置-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
        </encoder>
        <!--指定拆分规则-->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--按照时间和压缩格式声明拆分的文件名-->
            <fileNamePattern>${log_dir}/rolling.%d{yyyy-MM-dd}.log%i.gz</fileNamePattern>
            <!--按照文件大小拆分-->
            <maxFileSize>1MB</maxFileSize>
        </rollingPolicy>
        <!--日志级别过滤器-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!--日志过滤规则-->
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!--异步日志-->
    <appender name="async" class="ch.qos.logback.classic.AsyncAppender">
        <!--指定某个具体的 appender-->
        <appender-ref ref="rollFile"/>
    </appender>


    <!--root logger 配置-->
    <root level="ALL">
        <appender-ref ref="console"/>
        <appender-ref ref="async"/>
    </root>

    <!--自定义 looger 对象
        additivity="false" 自定义 logger 对象是否继承 rootLogger
     -->
    <logger name="com.itheima" level="info" additivity="false">
        <appender-ref ref="console"/>
    </logger>
</configuration>

===============3.zfoo下的logback================

zfoo项目中的调试环境下的logback.xml配置

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

<configuration scan="false" debug="false">
    <property name="LOG_HOME" value="log/"/>
    <property name="PATTERN_FILE"
              value="%d{yyyy-MM-dd HH:mm:ss} [%-5level] [%thread] %logger.%M\\(%F:%line\\) - %msg%n"/>
    <property name="PATTERN_CONSOLE"
              value="%d{yyyy-MM-dd HH:mm:ss} [%highlight(%-5level)] [%thread] %logger.%M\\(%F:%line\\) - %msg%n"/>
    <!-- 负责写日志,控制台日志,会打印所有的包的所有级别日志 -->
    <appender name="zfoo_console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${PATTERN_CONSOLE}</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!-- debug日志,只有一个文件,只收集debug级别日志,每次启动会覆盖以前的debug日志 -->
    <appender name="zfoo_debug" class="ch.qos.logback.core.FileAppender">
        <file>${LOG_HOME}/debug.log</file>
        <!-- append: true,日志被追加到文件结尾; false,清空现存文件;默认是true -->
        <append>false</append>
        <encoder>
            <pattern>${PATTERN_FILE}</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>debug</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- info,warn,error级别的日志都会添加在info.log日志中 -->
    <!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 -->
    <appender name="zfoo_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_HOME}/info.log</file>

        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- rollover daily -->
            <fileNamePattern>${LOG_HOME}/info.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <!-- each file should be at most 100MB, keep 30 days worth of history, but at most 40GB -->
            <maxFileSize>100MB</maxFileSize>
            <maxHistory>30</maxHistory>
            <totalSizeCap>40GB</totalSizeCap>
        </rollingPolicy>

        <encoder>
            <Pattern>${PATTERN_FILE}</Pattern>
            <charset>UTF-8</charset>
        </encoder>

        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>info</level>
        </filter>
    </appender>

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

    <!-- 只收集error级别的日志 -->
    <appender name="zfoo_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_HOME}/error.log</file>

        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${LOG_HOME}/error.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <maxFileSize>100MB</maxFileSize>
            <maxHistory>30</maxHistory>
            <totalSizeCap>20GB</totalSizeCap>
        </rollingPolicy>

        <encoder>
            <Pattern>${PATTERN_FILE}</Pattern>
            <charset>UTF-8</charset>
        </encoder>

        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>error</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!--step1:指定想要输出的类型-->
    <!-- 根logger -->
    <root level="info">
        <!--控制台-->
        <appender-ref ref="zfoo_console"/>
<!--        <appender-ref ref="zfoo_debug"/>-->
        <appender-ref ref="zfoo_async_info"/>
<!--        <appender-ref ref="zfoo_error"/>-->
    </root>

    <logger name="ch.qos.logback" level="info"/>
    <logger name="org.springframework" level="info"/>
    <logger name="io.netty" level="info"/>
</configuration>

思考:

必然线上使用的话,是使用基于文件大小 和 文件拆分的方式。 比如:知道大概啥时出的问题,这样子快速定位这一天的日志。 不可能1天几个G的输出,肯定要缩小问题的范围。

===============4.自己对于logback的思考和各个标签================

====20220725(实战:真正理解logger、root、CONSOLE中的level配置)=====

LogServer.java

package com.example.log;

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

public class LogServer {
    public static Logger GAME = LoggerFactory.getLogger("GAME");
    public static Logger CONF = LoggerFactory.getLogger("CONF");
}

logback.xml

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

<configuration scan="false" debug="false">
    <property name="LOG_HOME" value="log/"/>

    <property name="PATTERN_CONSOLE"
              value="%d{yyyy-MM-dd HH:mm:ss} [%highlight(%-5level)] [%thread] %logger.%M\\(%F:%line\\) - %msg%n"/>

    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>info</level>
        </filter>
        <encoder>
            <pattern>${PATTERN_CONSOLE}</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <logger name="GAME" level="error"/>

    <root level="info">
        <appender-ref ref="CONSOLE"/>
    </root>

</configuration>

Application.java

package com.example;

import com.example.log.LogServer;

public class Application {
    public static void main(String[] args) {
        LogServer.GAME.info("game");
        LogServer.CONF.info("conf");
    }
}

/*
2022-07-25 14:53:33 [INFO ] [main] CONF.main(Application.java:8) - conf
 */

原因:

由于CONF没有再logback中指定,因此是:采用root的,是info级别,info >= CONSOLE的,因此输出conf。

而 GAME,指定的是error级别,输出时采用的是 info,info < error,因此轮不到CONSOLE了,不会输出。

总结:在使用的地方如写成:LogServer.GAME.xx("...") 这里的xx:

        1.先要突破 logback中的级别限制(先看指定的这个模块配置没有【如:<logger name="GAME" level="..."/>,先看这里的level是啥】,没配置,则采用root的,因为我们默认是继承的root的日志级别)。

        2.其次,再突破CONSOLE中的级别限制,才会输出出来。

===============5.打印代码当前堆栈================

-----------------------------使用new Throwable() 打印出当前堆栈

package org.example.testPredicate;

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

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class Main {
	private static Logger LOG = LoggerFactory.getLogger(Main.class);

	public static void main(String[] args) {
//		Predicate<Long> isLess = age -> age < 18;
//
//
//		System.out.println(isLess.test(3L));

		Map<Integer, Integer> map = new HashMap<>();
		map.put(1, 1);
		map.put(2, 2);
		map.put(3, 3);
		map.put(4, 4);

		Iterator<Integer> iterator = map.keySet().iterator();

		while (iterator.hasNext()) {
			int f = iterator.next();

			if (f < 3) {
				iterator.remove();
			}

			call(f);

			System.out.println();
		}

		System.out.println(map);
	}

	public static void call(int f){
		LOG.error("f={}", f, new Throwable());
	}

}

/*
2023-04-23 18:09:47 [ERROR] [main] org.example.testPredicate.Main.call(Main.java:43) - f=1
java.lang.Throwable: null
	at org.example.testPredicate.Main.call(Main.java:43)
	at org.example.testPredicate.Main.main(Main.java:34)

2023-04-23 18:09:47 [ERROR] [main] org.example.testPredicate.Main.call(Main.java:43) - f=2
java.lang.Throwable: null
	at org.example.testPredicate.Main.call(Main.java:43)
	at org.example.testPredicate.Main.main(Main.java:34)

2023-04-23 18:09:47 [ERROR] [main] org.example.testPredicate.Main.call(Main.java:43) - f=3
java.lang.Throwable: null
	at org.example.testPredicate.Main.call(Main.java:43)
	at org.example.testPredicate.Main.main(Main.java:34)

2023-04-23 18:09:47 [ERROR] [main] org.example.testPredicate.Main.call(Main.java:43) - f=4
java.lang.Throwable: null
	at org.example.testPredicate.Main.call(Main.java:43)
	at org.example.testPredicate.Main.main(Main.java:34)
 */

哪个方法调用的,在哪一行出现的这个问题都轻松看出来。

==============6.Exception的打印===================

Exception的打印方式

有些未知的异常我们需要打印,则这样子就可以了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值