log4j日志不输出的问题
今天服务器上报错,想先去看一下日志进行排查,结果发现日志很久都没有输出过了。从上午排查到下午,刚刚解决,因此记录一下,但现在也只是知其然,并不知其所以然,所以如果大家有什么想法请在下方评论。
先说一下环境,服务器是linux,项目是运行在tomcat下的Spring项目,日志用的是log4j。
首先,从10月13号开始便没有新的日志文件了。假设日志名为log.txt(如果你设置了DailyRollingFileAppender,那么你当天的日志文件就是log.txt),先备份该文件到其他目录下,然后删除该文件,重新启动tomcat。这是为了确认你的log4j配置是否有问题,因为这是最容易出错的地方。很遗憾,我不是这里出的问题,因为项目重启后,日志文件又重新生成了,但很奇怪的是,日志文件是空的,其大小为0.
感觉自己碰上了很神奇的问题,因此我在自己的本地进行调试,启动项目后发现,正常的项目启动日志是有的:
15:13:48:0253 INFO [RMI TCP Connection(3)-127.0.0.1] -Root WebApplicationContext: initialization completed in 18479 ms
但我自己的一些日志输出是不显示的,比如:
private static final Logger log = LoggerFactory.getLogger(MyDomain.class);
log.info("show info log");
show info log这句话就不打印,现在证明,我的日志配置没有问题,服务器也找到了我的日志文件,但应该是我自己的Logger是不对应正确的日志输出的,因为我的console(控制台)有显示。
接下来,我就是开始看源码了。先是LoggerFactory.getLogger(Class<?> clazz)方法:
public static Logger getLogger(Class<?> clazz) {
Logger logger = getLogger(clazz.getName());
if (DETECT_LOGGER_NAME_MISMATCH) {
Class<?> autoComputedCallingClass = Util.getCallingClass();
if (autoComputedCallingClass != null && nonMatchingClasses(clazz, autoComputedCallingClass)) {
Util.report(String.format("Detected logger name mismatch. Given name: \"%s\"; computed name: \"%s\".", logger.getName(),
autoComputedCallingClass.getName()));
Util.report("See " + LOGGER_NAME_MISMATCH_URL + " for an explanation");
}
}
return logger;
}
好吧,没什么用,看不出我的logger变成了,继续看getLogger(String name)方法:
public static Logger getLogger(String name) {
ILoggerFactory iLoggerFactory = getILoggerFactory();
return iLoggerFactory.getLogger(name);
}
这时我在return iLoggerFactory.getLogger(name);这行打了断点,我看到了这样的东西:

为什么我的iLoggerFactory是用的logback中的实现?其实也是怪我自己大意,我其实依赖了一个基于Spring Boot的项目(虽然我只是用了里面的一些domain类,但因为设计不当,还没有把这些domain类单独提成一个_项目),而Spring Boot中一般默认就依赖的logback。通过gradle查看项目的依赖树,也证实了我的这一猜想(./gradlew 子项目名称:dependencies):
| +--- org.springframework.boot:spring-boot-starter-web:2.0.2.RELEASE
| | +--- org.springframework.boot:spring-boot-starter:2.0.2.RELEASE
| | | +--- org.springframework.boot:spring-boot:2.0.2.RELEASE
| | | | +--- org.springframework:spring-core:5.0.6.RELEASE (*)
| | | | \--- org.springframework:spring-context:5.0.6.RELEASE (*)
| | | +--- org.springframework.boot:spring-boot-autoconfigure:2.0.2.RELEASE
| | | | \--- org.springframework.boot:spring-boot:2.0.2.RELEASE (*)
| | | +--- org.springframework.boot:spring-boot-starter-logging:2.0.2.RELEASE
| | | | +--- ch.qos.logback:logback-classic:1.2.3
| | | | | +--- ch.qos.logback:logback-core:1.2.3
| | | | | \--- org.slf4j:slf4j-api:1.7.25
接下来就好办了,你排除掉ch.qos.logback的依赖就可以了,在你的build.gradle中增加:
configurations {
compile.exclude group: 'ch.qos.logback'
}
这个时候你再重新调试一下看看:

完美,现在是log4j中的实现,得到了我想要的操作。当然了,既然我知道之前项目中的slf4j是logback实现了,那么我自然也可以换成logback的配置,但这就需要我将项目换成用Spring Boot启动,这个改动有点大,如果以后有必要的话,我再将这个exclude删除,换成Spring Boot的形式。
这次Spring Boot帮我们默认启用的是logback,那么有没有什么简单方法可以知道呢?如果你的项目出现了以下的日志输出,说明你的项目当前有不止一个SLF4J的实现组件:
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/project.war/WEB-INF/lib/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/project.war/WEB-INF/lib/slf4j-log4j12-1.7.21.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 [ch.qos.logback.classic.util.ContextSelectorStaticBinder]
因为在org.slf4j.LoggerFactory的bind方法中有关于这方面的输出:
private final static void bind() {
try {
Set<URL> staticLoggerBinderPathSet = null;
// skip check under android, see also
// http://jira.qos.ch/browse/SLF4J-328
if (!isAndroid()) {
// 查找你的当前项目有几个slf4j的实现
staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
// 如果多余一个就打印
reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
}
// the next line does the binding
// 这个是具体选了哪一个实现(重点关注)
StaticLoggerBinder.getSingleton();
INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
reportActualBinding(staticLoggerBinderPathSet);
fixSubstituteLoggers();
replayEvents();
// release all resources in SUBST_FACTORY
SUBST_FACTORY.clear();
} catch (NoClassDefFoundError ncde) {
String msg = ncde.getMessage();
if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) {
INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION;
Util.report("Failed to load class \"org.slf4j.impl.StaticLoggerBinder\".");
Util.report("Defaulting to no-operation (NOP) logger implementation");
Util.report("See " + NO_STATICLOGGERBINDER_URL + " for further details.");
} else {
failedBinding(ncde);
throw ncde;
}
} catch (java.lang.NoSuchMethodError nsme) {
String msg = nsme.getMessage();
if (msg != null && msg.contains("org.slf4j.impl.StaticLoggerBinder.getSingleton()")) {
INITIALIZATION_STATE = FAILED_INITIALIZATION;
Util.report("slf4j-api 1.6.x (or later) is incompatible with this binding.");
Util.report("Your binding is version 1.5.5 or earlier.");
Util.report("Upgrade your binding to version 1.6.x.");
}
throw nsme;
} catch (Exception e) {
failedBinding(e);
throw new IllegalStateException("Unexpected initialization failure", e);
}
}
特别要注意的是StaticLoggerBinder.getSingleton();这行代码,StaticLoggerBinder在logback-classic和slf4j-log4j12这两个jar包各有一个,因此,Spring boot是自动选择logback-classic(虽然我在本地运行的时候还是默认进入的slf4j-log4j12,但是会提醒我Source code does not match the bytecode,因此我判断依旧进的是logback-classic),所以只要把logback给exclude掉,就解决了这个问题。
现在看问题,更加关注源代码,因为这可以让我们更加快速定位问题,并且也能据此大致猜出其解决方案。希望大家能一起看看源代码,如果你有什么发现,可以在下方留言,我将和你一起讨论。
有兴趣的话可以关注我的公众号或者头条号,说不定会有意外的惊喜。


log4j日志不输出的问题的更多相关文章
- log4j日志整合输出(slf4j+commonslog+log4j+jdklogger)
log4j日志整合输出(slf4j+commonslog+log4j+jdklogger) 博客分类: 日志 J2EE项目中,经常会用到很多第三方的开源组件和软件,这些组件都使用各自的日志组件,比 ...
- 记一次log4j日志文件输出错误的解决
log4j错误信息:log4j:ERROR Failed to rename [D:/logs/wmts_] to [D:/logs/wmts_2015-12-21.log ]. 起因:部门网站使用B ...
- log4j日志不输出MyBatis SQL脚本?
日志输出级别调成debug,然并卵? 试试加下这个包. <dependency> <groupId>org.slf4j</groupId> <artifact ...
- log4j日志文件输出保存
og4j.appender.A1=org.apache.log4j.DailyRollingFileAppender log4j.appender.A1.File=app.log log4j.appe ...
- log4j日志输出到web项目指定文件夹
感谢 eric2500 的这篇文章:http://www.cxyclub.cn/n/27860/ 摘要:尝试将log4j的文件日志输出到web工程制定目录,遇到了很多问题,最终在eric2500的指导 ...
- Log4j 输出的日志中时间比系统时间少了8小时的解决方法,log4j日志文件重复输出
1. 第一个问题:时间少了8小时 Log4j 输出的日志中,时间比系统时间少了8小时,但是 eclipse 控制台输出的日志的时间却是对的. log4j配置如下: #all logger output ...
- (转)log4j日志级别设置成DEBUG时输出Html代码等问题:
log4j日志级别设置成DEBUG时输出Html代码等问题: 问题: log4j日志级别设置成DEBUG时会输出很多信息,包括一些Html代码 解决方案: log4j的控制是树形,所以在log4j.p ...
- Log4j按级别输出日志到不同文件配置分析 (转:projava)
关于LOG4J 按照级别输出日志,并按照级别输出到不同文件中的说法有很多, 网上贴的最多的log4j.properties的设置是这样的 log4j.rootLogger=info,stdout,in ...
- log4j日志输出级别变更
1. 现阶段log4j日志输出配置 示例:基础服务日志配置 #DEBUG < INFO < WARN < ERROR < FATAL\u65E5\u5FD7\u7684\u ...
随机推荐
- 基于SpringBoot从零构建博客网站 - 分页显示文章列表功能
显示文章列表一般都是采用分页显示,比如每页10篇文章显示.这样就不用每次就将所有的文章查询出来,而且当文章数量特别多的时候,如果一次性查询出来很容易出现OOM异常. 后台的分页插件采用的是mybati ...
- (四十五)c#Winform自定义控件-水波图表
前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:ht ...
- GUID做主键真的合适吗
在一个分布式环境中,我们习惯使用GUID做主键,来保证全局唯一,然后,GUID做主键真的合适吗? 其实GUID做主键本身没有问题,微软的很多项目自带DB都是使用GUID做主键的,显然,这样做是没有问题 ...
- 用Canvas实现Photoshop的钢笔工具(贝塞尔曲线)
前两天在用Canvas实现一个绘制路径的小功能.做完之后发现加以完善可以“复刻”一下PS里面的钢笔工具. PS里的钢笔工具对我来说是PS中最好用的工具! 所以本文主要介绍如何用Canvas来实现Pho ...
- 初尝RabbitMQ消息队列
RabbitMQ 是什么? 消息中间件 作用? 用于分布式项目中的模块解耦 用法? 创建队列 创建消息工厂并设置 (生产者额外步骤 : 创建消息) 创建连接,通道 声明队列 生产者 : 发送消 ...
- 2019icpc南京网络赛_F_Greedy Sequence
题意 题意不明,队友告诉我对于每个\(i\),所在下标\(p[i]\),在\([p[i]-k,p[i]+k]\)中找到小于\(i\)的最大数\(x\),然后\(ans[i]=ans[x]+1\)即可. ...
- eclipse中导入外部包却无法查看对应源码或Javadoc的入坑指南
eclipse中导入外部包却无法查看对应源码或Javadoc的 入坑指南 出现这个错误的原因是,你虽然导入了.jar包,但没有配置对应的Javadoc或源码路径,所以在编辑器中无法查看源 码和对应AP ...
- 手机端apk文件安装
1.电脑端下载豌豆荚 2.手机连接电脑,打开手机USB调试模式(设置->开发人员选项,打开开发人员选项和USB调试) 3.在电脑中双击下载好的apk文件,即可打开豌豆角,然后便可安装到手机.
- 牛客小白月赛5 E 面积 计算三角形面积模板 波尔约-格维也纳定理 匹克公式
链接:https://www.nowcoder.com/acm/contest/135/E来源:牛客网 题目描述 定义“最大生成图”:在M*N的点阵中,连接一些点形成一条经过所有点恰好一次的回路,且连 ...
- hdu 5974 A Simple Math Problem(数学题)
Problem Description Given two positive integers a and b,find suitable X and Y to meet the conditions ...