Logback:SpringBoot 2.0 整合 Logback (kafaka es)

1. 规范了日志的打印格式   

2. 增加了彩色日志输出  

3. 支持异步推送kafka  

4. 日志文件压缩功能

我们无需关心 Logback 版本,只需关注 Boot 版本即可,Parent 工程自动集成了 Logback。Springboot 本身就可以打印日志,为什么还需要规范日志?

  • 日志统一,方便查阅管理。

  • 日志归档功能。

  • 日志持久化功能。

  • 分布式日志查看功能(ELK),方便搜索和查阅。

关于 Logback 的介绍就略过了,下面进入代码阶段。本文主要有以下几个功能:

  • 重新规定日志输出格式。

  • 自定义指定包下的日志输出级别。

  • 按模块输出日志。

  • 日志异步推送 Kafka

POM 文件

如果需要将日志持久化到磁盘,则引入如下两个依赖(不需要推送 Kafka 也可以引入)

<properties>
    <logback-kafka-appender.version>0.2.0-RC1</logback-kafka-appender.version>
    <janino.version>2.7.8</janino.version>
</properties>
<!-- 将日志输出到Kafka -->
<dependency>
    <groupId>com.github.danielwegener</groupId>
    <artifactId>logback-kafka-appender</artifactId>
    <version>${logback-kafka-appender.version}</version>
    <scope>runtime</scope>
</dependency>

<!-- 在xml中使用<if condition>的时候用到的jar包 -->
<dependency>
    <groupId>org.codehaus.janino</groupId>
    <artifactId>janino</artifactId>
    <version>${janino.version}</version>
</dependency>

配置文件

在 项目中resource 文件夹下有三个配置文件

  • logback-defaults.xml

  • logback-pattern.xml

  • logback-spring.xml

logback-spring.xml 

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

<configuration>
    <include resource="logging/logback-pattern.xml"/>
    <include resource="logging/logback-defaults.xml"/>
</configuration>

 logback-defaults.xml

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

<included>

	<!-- spring日志 -->
	<property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}/spring.log}"/>

	<!-- 定义日志文件的输出路径 -->
	<property name="LOG_HOME" value="${LOG_PATH:-/tmp}"/>

	<!--
	将日志追加到控制台(默认使用LogBack已经实现好的)
	进入文件,其中<logger>用来设置某一个包或者具体的某一个类的日志打印级别
	-->
	<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
	<include resource="logback-pattern.xml"/>

	<!--定义日志文件大小 超过这个大小会压缩归档 -->
	<property name="INFO_MAX_FILE_SIZE" value="100MB"/>
	<property name="ERROR_MAX_FILE_SIZE" value="100MB"/>
	<property name="TRACE_MAX_FILE_SIZE" value="100MB"/>
	<property name="WARN_MAX_FILE_SIZE" value="100MB"/>

	<!--定义日志文件最长保存时间 -->
	<property name="INFO_MAX_HISTORY" value="9"/>
	<property name="ERROR_MAX_HISTORY" value="9"/>
	<property name="TRACE_MAX_HISTORY" value="9"/>
	<property name="WARN_MAX_HISTORY" value="9"/>

	<!--定义归档日志文件最大保存大小,当所有归档日志大小超出定义时,会触发删除 -->
	<property name="INFO_TOTAL_SIZE_CAP" value="5GB"/>
	<property name="ERROR_TOTAL_SIZE_CAP" value="5GB"/>
	<property name="TRACE_TOTAL_SIZE_CAP" value="5GB"/>
	<property name="WARN_TOTAL_SIZE_CAP" value="5GB"/>

	<!-- 按照每天生成日志文件 -->
	<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
		<!-- 当前Log文件名 -->
		<file>${LOG_HOME}/info.log</file>
		<!-- 压缩备份设置 -->
		<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
			<fileNamePattern>${LOG_HOME}/backup/info/info.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
			<maxHistory>${INFO_MAX_HISTORY}</maxHistory>
			<maxFileSize>${INFO_MAX_FILE_SIZE}</maxFileSize>
			<totalSizeCap>${INFO_TOTAL_SIZE_CAP}</totalSizeCap>
		</rollingPolicy>
		<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
			<pattern>${FILE_LOG_PATTERN}</pattern>
		</encoder>
		<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
			<level>INFO</level>
		</filter>
	</appender>

	<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
		<!-- 当前Log文件名 -->
		<file>${LOG_HOME}/warn.log</file>
		<!-- 压缩备份设置 -->
		<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
			<fileNamePattern>${LOG_HOME}/backup/warn/warn.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
			<maxHistory>${WARN_MAX_HISTORY}</maxHistory>
			<maxFileSize>${WARN_MAX_FILE_SIZE}</maxFileSize>
			<totalSizeCap>${WARN_TOTAL_SIZE_CAP}</totalSizeCap>
		</rollingPolicy>
		<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
			<pattern>${FILE_LOG_PATTERN}</pattern>
		</encoder>
		<filter class="ch.qos.logback.classic.filter.LevelFilter">
			<level>WARN</level>
			<onMatch>ACCEPT</onMatch>
			<onMismatch>DENY</onMismatch>
		</filter>
	</appender>

	<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
		<!-- 当前Log文件名 -->
		<file>${LOG_HOME}/error.log</file>
		<!-- 压缩备份设置 -->
		<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
			<fileNamePattern>${LOG_HOME}/backup/error/error.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
			<maxHistory>${ERROR_MAX_HISTORY}</maxHistory>
			<maxFileSize>${ERROR_MAX_FILE_SIZE}</maxFileSize>
			<totalSizeCap>${ERROR_TOTAL_SIZE_CAP}</totalSizeCap>
		</rollingPolicy>
		<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
			<pattern>${FILE_LOG_PATTERN}</pattern>
		</encoder>
		<filter class="ch.qos.logback.classic.filter.LevelFilter">
			<level>ERROR</level>
			<onMatch>ACCEPT</onMatch>
			<onMismatch>DENY</onMismatch>
		</filter>
	</appender>

	<!-- Kafka的appender -->
	<appender name="KAFKA" class="com.github.danielwegener.logback.kafka.KafkaAppender">
		<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
			<pattern>${FILE_LOG_PATTERN}</pattern>
		</encoder>
		<topic>${kafka_env}applog_${spring_application_name}</topic>
		<keyingStrategy class="com.github.danielwegener.logback.kafka.keying.HostNameKeyingStrategy" />
		<deliveryStrategy class="com.github.danielwegener.logback.kafka.delivery.AsynchronousDeliveryStrategy" />
		<producerConfig>bootstrap.servers=${kafka_broker}</producerConfig>
		<!-- don't wait for a broker to ack the reception of a batch. -->
		<producerConfig>acks=0</producerConfig>
		<!-- wait up to 1000ms and collect log messages before sending them as a batch -->
		<producerConfig>linger.ms=1000</producerConfig>
		<!-- even if the producer buffer runs full, do not block the application but start to drop messages -->
		<producerConfig>max.block.ms=0</producerConfig>
		<!-- Optional parameter to use a fixed partition -->
		<partition>8</partition>
	</appender>

	<appender name="KAFKA_ASYNC" class="ch.qos.logback.classic.AsyncAppender">
		<appender-ref ref="KAFKA" />
	</appender>

	<root level="INFO">
		<appender-ref ref="CONSOLE"/>
		<appender-ref ref="INFO_FILE"/>
		<appender-ref ref="WARN_FILE"/>
		<appender-ref ref="ERROR_FILE"/>
		<if condition='"true".equals(property("kafka_enabled"))'>
			<then>
				<appender-ref ref="KAFKA_ASYNC"/>
			</then>
		</if>
	</root>

</included>

 注意:

  • 上面的 <partition>8</partition> 指的是将消息发送到哪个分区,如果你主题的分区为 0~7,那么会报错,解决办法是要么去掉这个属性,要么指定有效的分区。

  • HostNameKeyingStrategy 是用来指定 key 的生成策略,我们知道 kafka 是根据 key 来判定将消息发送到哪个分区上的,此种是根据主机名来判定,这样带来的好处是每台服务器生成的日志都是在同一个分区上面,从而保证了时间顺序。但默认的是 NoKeyKeyingStrategy,会随机分配到各个分区上面,这样带来的坏处是,无法保证日志的时间顺序,不推荐这样来记录日志。

logback-pattern.xml 

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

<included>

	<!-- 日志展示规则,比如彩色日志、异常日志等 -->
	<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
	<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
	<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />

	<!-- 自定义日志展示规则 -->
	<conversionRule conversionWord="ip" converterClass="com.ryan.utils.IPAddressConverter" />
	<conversionRule conversionWord="module" converterClass="com.ryan.utils.ModuleConverter" />

	<!-- 上下文属性 -->
	<springProperty scope="context" name="spring_application_name" source="spring.application.name" />
	<springProperty scope="context" name="server_port" source="server.port" />
	<!-- Kafka属性配置 -->
	<springProperty scope="context" name="spring_application_name" source="spring.application.name" />
	<springProperty scope="context" name="kafka_enabled" source="ryan.web.logging.kafka.enabled"/>
	<springProperty scope="context" name="kafka_broker" source="ryan.web.logging.kafka.broker"/>
	<springProperty scope="context" name="kafka_env" source="ryan.web.logging.kafka.env"/>

	<!-- 日志输出的格式如下 -->
	<!-- appID | module | dateTime | level | requestID | traceID | requestIP | userIP | serverIP | serverPort | processID | thread | location | detailInfo-->

	<!-- CONSOLE_LOG_PATTERN属性会在console-appender.xml文件中引用 -->
	<property name="CONSOLE_LOG_PATTERN" value="%clr(${spring_application_name}){cyan}|%clr(%module){blue}|%clr(%d{ISO8601}){faint}|%clr(%p)|%X{requestId}|%X{X-B3-TraceId:-}|%X{requestIp}|%X{userIp}|%ip|${server_port}|${PID}|%clr(%t){faint}|%clr(%.40logger{39}){cyan}.%clr(%method){cyan}:%L|%m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>

	<!-- FILE_LOG_PATTERN属性会在logback-defaults.xml文件中引用 -->
	<property name="FILE_LOG_PATTERN" value="${spring_application_name}|%module|%d{ISO8601}|%p|%X{requestId}|%X{X-B3-TraceId:-}|%X{requestIp}|%X{userIp}|%ip|${server_port}|${PID}|%t|%.40logger{39}.%method:%L|%m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>

	<!--
	将 org/springframework/boot/logging/logback/defaults.xml 文件下的默认logger写过来
	-->
	<logger name="org.apache.catalina.startup.DigesterFactory" level="ERROR"/>
	<logger name="org.apache.catalina.util.LifecycleBase" level="ERROR"/>
	<logger name="org.apache.coyote.http11.Http11NioProtocol" level="WARN"/>
	<logger name="org.apache.sshd.common.util.SecurityUtils" level="WARN"/>
	<logger name="org.apache.tomcat.util.net.NioSelectorPool" level="WARN"/>
	<logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="ERROR"/>
	<logger name="org.hibernate.validator.internal.util.Version" level="WARN"/>

</included>

 自定义获取 moudle

/**
 * <b>Function: </b> 获取日志模块名称
 *
 * @program: ModuleConverter 
 * @Package: com.kingbal.king.dmp
 * @author: songjianlin
 * @date: 2024/04/17
 * @version: 1.0
 * @Copyright: 2024 www.kingbal.com Inc. All rights reserved.
 */
public class ModuleConverter extends ClassicConverter {

	private static final int MAX_LENGTH = 20;

	@Override
	public String convert(ILoggingEvent event) {
		if (event.getLoggerName().length() > MAX_LENGTH) {
			return "";
		} else {
			return event.getLoggerName();
		}
	}
}

 自定义获取 ip

/**
 * <b>Function: </b> 获取ip地支
 *
 * @program: IPAddressConverter 
 * @Package: com.kingbal.king.dmp
 * @author: songjianlin
 * @date: 2024/04/17
 * @version: 1.0
 * @Copyright: 2024 www.kingbal.com Inc. All rights reserved.
 */
@Slf4j
public class IPAddressConverter extends ClassicConverter {

	private static String ipAddress;

	static {
		try {
			ipAddress = InetAddress.getLocalHost().getHostAddress();
		} catch (UnknownHostException e) {
			log.error("fetch localhost host address failed", e);
			ipAddress = "UNKNOWN";
		}
	}

	@Override
	public String convert(ILoggingEvent event) {
		return ipAddress;
	}
}

 按模块输出

给 @Slf4j 加上 topic。

/**
 * <b>Function: </b> todo
 *
 * @program: LogbackController
 * @Package: com.kingbal.king.dmp
 * @author: songjianlin
 * @date: 2024/04/17
 * @version: 1.0
 * @Copyright: 2024 www.kingbal.com Inc. All rights reserved.
 */
@RestController
@RequestMapping(value = "/portal")
@Slf4j(topic = "LogbackController")
public class LogbackController {

	@RequestMapping(value = "/gohome")
	public void m1() {
		log.info("buddy,we go home~");
	}

}

自定义日志级别

如果想打印 SQL 语句,需要将日志级别设置成 debug 级别。

logging.path = /tmp
logging.level.com.ryan.trading.account.dao = debug 

 推送 Kafka展开目录

ryan.web.logging.kafka.enabled=true
#多个broker用英文逗号分隔
ryan.web.logging.kafka.broker=127.0.0.1:9092
#创建Kafka的topic时使用
ryan.web.logging.kafka.env=test

  • 31
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
1. 添加logback-spring.xml文件 在src/main/resources目录下创建一个名为logback-spring.xml的文件,将下面的代码复制并粘贴进去。 ``` <?xml version="1.0" encoding="utf-8" ?> <configuration> <!-- 确定打印的日志级别 --> <timestamp key="byDay" datePattern="yyyyMMdd" /> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{35} -%msg%n</pattern> </encoder> </appender> <!-- 输出到本地文件 --> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_PATH}/springboot2.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_PATH}/springboot2.%d{yyyy-MM-dd}.log</fileNamePattern> <maxHistory>30</maxHistory> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{35} -%msg%n</pattern> </encoder> </appender> <!-- root级别日志处理器 --> <root level="info"> <appender-ref ref="CONSOLE" /> <appender-ref ref="FILE" /> </root> <!-- 配置包日级别日志处理器 --> <logger name="com.example" level="debug" additivity="false"> <appender-ref ref="CONSOLE" /> <appender-ref ref="FILE" /> </logger> </configuration> ``` 2. 配置文件参数 在application.properties或application.yml文件中添加以下参数: - logging.config:指定logback-spring.xml配置文件路径,如果不指定将使用默认的日志配置。 - logging.path:指定日志文件存放路径,必须是一个相对目录。例如:logging.path=log 相当于在项目根目录下创建了一个log文件夹,日志将输出到该文件夹中。如果没有设置该参数,则日志将输出到控制台。 ``` #以配置文件的方式加载日志框架,默认使用logback-spring.xml作为配置文件 logging.config=classpath:logback-spring.xml #指定日志存放的相对路径 logging.path=log ``` 3. 在代码中使用日志输出 在需要输出日志的类中使用注入方式加载日志,在方法中使用对应的日志级别输出日志。 ``` @Component public class TestController { private static final Logger logger = LoggerFactory.getLogger(TestController.class); @RequestMapping("/test") public String test() { logger.debug("这是一条debug日志"); logger.info("这是一条info日志"); logger.warn("这是一条warn日志"); logger.error("这是一条error日志"); return "test"; } } ``` 运行项目,打开控制台或者查看日志文件,可以看到日志已经输出成功。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值