[日志管理] 启动程序时,因报“log4j-slf4j-impl cannot be present with log4j-to-slf4j”错误而导致程序终止运行[转发]

Posted 千千寰宇

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[日志管理] 启动程序时,因报“log4j-slf4j-impl cannot be present with log4j-to-slf4j”错误而导致程序终止运行[转发]相关的知识,希望对你有一定的参考价值。

此错误出现过了几次了,有必要记录一下。

1 问题描述

运行测试用例的spring-boot Java程序片段时,报如下错误:


SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/D:/Program_Data/maven_repository/org/apache/logging/log4j/log4j-slf4j-impl/2.13.3/log4j-slf4j-impl-2.13.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/D:/Program_Data/maven_repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]

java.lang.ExceptionInInitializerError
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
	at org.junit.runners.BlockJUnit4ClassRunner.createTest(BlockJUnit4ClassRunner.java:250)
	at org.junit.runners.BlockJUnit4ClassRunner.createTest(BlockJUnit4ClassRunner.java:260)
	at org.junit.runners.BlockJUnit4ClassRunner$2.runReflectiveCall(BlockJUnit4ClassRunner.java:309)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.BlockJUnit4ClassRunner.methodBlock(BlockJUnit4ClassRunner.java:306)
	at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
	at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: org.apache.logging.log4j.LoggingException: log4j-slf4j-impl cannot be present with log4j-to-slf4j
	at org.apache.logging.slf4j.Log4jLoggerFactory.validateContext(Log4jLoggerFactory.java:49)
	at org.apache.logging.slf4j.Log4jLoggerFactory.newLogger(Log4jLoggerFactory.java:39)
	at org.apache.logging.slf4j.Log4jLoggerFactory.newLogger(Log4jLoggerFactory.java:30)
	at org.apache.logging.log4j.spi.AbstractLoggerAdapter.getLogger(AbstractLoggerAdapter.java:54)
	at org.apache.logging.slf4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:30)
	at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:358)
	at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:383)
	at bugs.debug.ParseNettyHttpServerLog.<clinit>(ParseNettyHttpServerLog.java:25)
	... 27 more


Process finished with exit code -1

2 问题分析

  • 错误日志翻译:Caused by: org.apache.logging.log4j.LoggingException: log4j-slf4j-impl cannot be present with log4j-to-slf4j
log4j-slf4j-impl 和 log4j-to-slf4j 这两个包不能同时存在。
  • 那么为什么这两个包不能同时存在呢?

我们先来看一下这两个包的定义:

  • log4j-slf4j-impl : 主要是 log4j 对 slf4j 接口的实现

Apache Log4j SLF4J Binding: The Apache Log4j SLF4J API binding to Log4j 2 Core

  • log4j-to-slf4j : slf4j 对 log4j 接口的适配

Apache Log4j to SLF4J Adapter: The Apache Log4j binding between Log4j 2 API and SLF4J

这两个接口不能同时存在的意思是说:

要么用 log4j 日志系统,然后同时支持 slf4j 接口的调用;
要么用其他日志系统,比如logback(logback是 slf4j 接口的实现),然后适配log4j接口。不能兼而有之!

  • spring boot 框架默认使用的logback日志系统,logback实现的是slf4j接口。因此需要适配 log4j 接口,因而会引入 log4j-to-slf4j

因此,如果您正在使用的是spring boot,则不能引入log4j-slf4j-impl。
问题解决思路:只需要看一下是哪个 pom 文件引入了 log4j-slf4j-impl,把这个包去掉就可以啦!

3 解决方法

  • 本问题中,博主的工程确实是基于spring-boot框架,但博主采纳并使用的日志框架是slf4j + log4j

即:需去除spring-boot自带的log4j-to-slf4j依赖

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-gateway-server</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <artifactId>log4j-to-slf4j</artifactId>
                    <groupId>org.apache.logging.log4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>

X 参考文献

Linux系统管理初步系统日志与screen程序

一、系统日志

系统日志是我们了解系统状况,服务启动情况,学会阅读日志是我们了解系统运行状况并进行管理的基本技能。

(一)/var/log/messages

系统中的各种操作都会记录到系统日志中,日志储存在/var/log/目录中,日志会被系统的logrotate程序自动切割,就是日志文件达到你设定的条件时,就自动结束,然后重新生成一个文件开始记录日志。

1、查看系统日志

tail /var/log/messages

确实可以记录下不少内容的
技术分享图片

2、通过/logrotate.conf文件配置日志记录机制

cat /etc/logrotate.conf

把主要的内容列在这个
# rotate log files weekly
weekly 多久结束一次日志记录,每周还是每月、每天等等

# keep 4 weeks worth of backlogs
rotate 4 多少份替换掉最旧一份日志,就是你最多能保存几份日志文件,这里是4,就是说如果你有4份日志文件了那么再多出来的一份就会把第一份覆盖掉,就像监控中你最可以回放的录像天数。

# create new (empty) log files after rotating old ones
create

# use date as a suffix of the rotated file
dateext

# uncomment this if you want your log files compressed
#compress

# RPM packages drop log rotation information into this directory
include /etc/logrotate.d
可以把需要使用

# no packages own wtmp and btmp -- we‘ll rotate them here
这个语句下面可以把你要logrotate程序切割的日志文件的路径加进来,让程序自动帮你切割日志文件,常见的比如Nginx日志之类。

比如处理:

/usr/local/nginx/logs/*.log {
daily
dateext
compress
rotate 7
sharedscripts
postrotate
kill -USR1 cat /var/run/nginx.pid
endscript
}

/var/log/wtmp {
monthly
create 0664 root utmp
minsize 1M
rotate 1
}

/var/log/btmp {
missingok
monthly
create 0600 root utmp
rotate 1
}

# system-specific logs may be also be configured here.

(二)dmseg命令

dmesg命令可以显示系统的启动信息及硬件错误信息,系统某个硬件有问题时,可使用该命令排障。
技术分享图片

注意这个命令显示的日志与/var/log/dmseg日志关系不大。

(三)last命令与lastb命令

last命令与lastb命令用于查看系统的登陆用户,它通过调用系统日志/var/log/wtmp与/var/log/btmp来显示系统最近的用户登陆情况,在进行安全防范时要使用该命令。

>last
技术分享图片
>lastb
技术分享图片

日志/var/log/wtmp与/var/log/btmp是二进制文件,不能直接cat

与系统安全相关的日志还有secure日志(/var/log/secure),他记录了用户尝试登陆系统,或者暴力破解系统密码时的信息,帮助你进行下一步处理,比如用fail2ban来锁定攻击IP。

二、screen工具

screen是一个虚拟终端工具,一些程序的执行时间很长不能中途中断,而我们登陆服务器时是远程登陆的,为了防止系统意外中断时仍能持续运行一个程序我们就可以使用screen工具。注意即使我们断开

screen工具非系统自带,首先需要yum安装

工具选项
ctrl+A 再+D:新建一个screen
screen -S “自定义名字” :自定义终端名新建screen
screen -ls :列出系统中存在的screen
screen -r id号或者自定义名字:进入特定的screen

操作示例
1、新建一个screen并运行vnstat 1命令

screen
vmstat 1
ctrl+A 再+D
技术分享图片

他就移到后台了

2、切换回到刚在的screen

screen -r 1960
screen -r test1

两个都可以,后一个是用screen -s test1生成的。
技术分享图片

3、杀死一个已经detached的screen会话

screen -X -S (id号或者screen名字) quit

技术分享图片

以上是关于[日志管理] 启动程序时,因报“log4j-slf4j-impl cannot be present with log4j-to-slf4j”错误而导致程序终止运行[转发]的主要内容,如果未能解决你的问题,请参考以下文章

为啥在 Log4j2 上使用 Slf4j 时 log4j-slf4j-impl 不依赖于 log4j-core

log4j2+slf4j日志不打印问题

Linux系统管理初步系统日志与screen程序

通过日志判断系统是否正常运行

异常处理

(转)MySQL日志管理