笔者最近创建了一个新的spring boot 工程,项目要发布到测试环境用docker来跑,日志需要输出到指定目录映射出来查看,就想着配置一下log。

 

引入log4j2

首先介绍如何引入log4j2,spring boot 不做修改默认使用的是logback,性能不如log4j2优秀,所以我们换成log4j2。

我们要在pom中先将默认的logging(里面用的Logbak)包排除,排除的方法有很多,由于笔者采用分模块打包的形式,所有项目有一个根pom,我选择在根pom的 dependencyManagement 依赖管理中排除这个包

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>2.2.6.RELEASE</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
</dependencyManagement>

如此一来,子模块引入的spring-boot-starter里面都不包含spring-boot-starter-logging的

然后我们在需要打印log的模块中引入spring-boot-starter-log4j2就可以了

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

配置log4j2

引入后,spring-boot-starter-log4j2会有默认的配置,然后笔者的需求是修改日志打印的路径,所以要修改其配置文件

我们在resources目录下创建log4j2-spring.xml,注意这样命名是为了spring可以自动加载我们的配置文件,当前你也可以随便起名字,那就需要你在application.yml配置中指定你的配置文件名

logging:
  config: 你的配置文件名

个人比较喜欢它原生的日志格式,想在它默认配置下只修改文件目录,于是在 spring-boot这个jar包里面的org.springframework.boot.logging.log4j2下找到默认配置log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
	<Properties>
		<Property name="LOG_EXCEPTION_CONVERSION_WORD">%xwEx</Property>
		<Property name="LOG_LEVEL_PATTERN">%5p</Property>
		<Property name="LOG_DATEFORMAT_PATTERN">yyyy-MM-dd HH:mm:ss.SSS</Property>
		<Property name="CONSOLE_LOG_PATTERN">%clr{%d{${LOG_DATEFORMAT_PATTERN}}}{faint} %clr{${LOG_LEVEL_PATTERN}} %clr{%pid}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}</Property>
		<Property name="FILE_LOG_PATTERN">%d{${LOG_DATEFORMAT_PATTERN}} ${LOG_LEVEL_PATTERN} %pid --- [%t] %-40.40c{1.} : %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}</Property>
	</Properties>
	<Appenders>
		<Console name="Console" target="SYSTEM_OUT" follow="true">
			<PatternLayout pattern="${sys:CONSOLE_LOG_PATTERN}" />
		</Console>
	</Appenders>
	<Loggers>
		<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" />
		<logger name="org.springframework.boot.actuate.endpoint.jmx" level="warn"/>
		<Root level="info">
			<AppenderRef ref="Console" />
		</Root>
	</Loggers>
</Configuration>

只需要在里面增加文件配置就可以了,修改后的文件如下

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
	<Properties>
		<Property name="log.name">${project.name}</Property>
        <Property name="log.path">/mnt/logs/${project.name}/${hostName}</Property>
		<Property name="LOG_EXCEPTION_CONVERSION_WORD">%xwEx</Property>
		<Property name="LOG_LEVEL_PATTERN">%5p</Property>
		<Property name="LOG_DATEFORMAT_PATTERN">yyyy-MM-dd HH:mm:ss.SSS</Property>
		<Property name="CONSOLE_LOG_PATTERN">%clr{%d{${LOG_DATEFORMAT_PATTERN}}}{faint} %clr{${LOG_LEVEL_PATTERN}} %clr{%pid}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}</Property>
		<Property name="FILE_LOG_PATTERN">%d{${LOG_DATEFORMAT_PATTERN}} ${LOG_LEVEL_PATTERN} %pid --- [%t] %-40.40c{1.} : %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}</Property>
	</Properties>
	<Appenders>
		<Console name="Console" target="SYSTEM_OUT" follow="true">
			<PatternLayout pattern="${sys:CONSOLE_LOG_PATTERN}" />
		</Console>
        <RollingFile name="File"
                     fileName="${log.path}/${log.name}.log"
                     filePattern="${log.path}/$${date:yyyy-MM}/${log.name}-%d{yyyy-MM-dd}-%i.log">
            <PatternLayout pattern="${sys:FILE_LOG_PATTERN}"/>
            <!--每个日志文件的大小,达到size后自动打包-->
            <SizeBasedTriggeringPolicy size="500 MB"/>
            <!--每天最多有多少个压缩包,超过该值,自动删除当天最早的压缩包-->
            <DefaultRolloverStrategy max="100">
                <!--日志删除策略,自动删除30天前的日志-->
                <Delete basePath="${log.path}" maxDepth="2">
                    <IfFileName glob="*/*.log" />
                    <IfLastModified age="100d" />
                </Delete>
            </DefaultRolloverStrategy>
        </RollingFile>
	</Appenders>
	<Loggers>
		<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" />
		<logger name="org.springframework.boot.actuate.endpoint.jmx" level="warn"/>
		<Root level="info">
			<AppenderRef ref="Console" />
			<AppenderRef ref="File" />
		</Root>
	</Loggers>
</Configuration>

引入pom变量

在模块多的情况下,笔者不想每个文件都要改,于是引用了pom里面的变量project.name,如果不做任何配置,会把这两个变量当成字符串,然后真的打到${project.name}目录下面

接下来我们解决这个问题

spring boot 2.0 默认的变量符号是@变量名@,我们将它改成${变量名},在pom文件build节点下引入maven-resource-plugin,然后设置useDefaultDelimiters = true,变量的符号就变成了${}

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-resources-plugin</artifactId>
            <configuration>
                <encoding>UTF-8</encoding>
                <useDefaultDelimiters>true</useDefaultDelimiters>
            </configuration>
        </plugin>
    </plugins>
</build>

这样配置完后,笔者发现打包完成后的xml文件中,变量并没有被替换掉,还是${}的形式,还需要增加以下配置

<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
        </resource>
    </resources>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-resources-plugin</artifactId>
            <configuration>
                <encoding>UTF-8</encoding>
                <useDefaultDelimiters>true</useDefaultDelimiters>
            </configuration>
        </plugin>
    </plugins>
</build>

再次打包,project.name已经打入xml文件中了。(hostName会在运行时加入系统变量中,所以这个打完包仍然是${hostName},不影响最终的日志输出目录)

至于为什么在配置中增加了resource目录的过滤就好了,也许是这样才能在打包时处理一遍这个目录(猜的),希望有懂的大佬交流一下。