剖析项目多个logback配置(下)
来源:http://www.cnblogs.com/guozp/p/5973038.html
上篇大概描述了logback的加载顺序以及加载的源码,本篇将分析如果在你的Maven或者其他多模块的项目中,每个模块都存在logback.xml的情况,项目会加载哪个为准。
这里简单的测试下,我的service模块下有个logback.xml,其他的模块下也有,但是输出目录不同,以此来观察。
service模块:
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="false" scanPeriod="60 seconds" debug="false">
<property name="LOG_HOME" value="D:/log" />
<property name="appName" value="index"></property> <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<Encoding>UTF-8</Encoding>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</layout>
</appender> <appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<Encoding>UTF-8</Encoding>
<file>${LOG_HOME}/${appName}.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/${appName}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
<MaxHistory>10</MaxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>500MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern>
</layout>
</appender> <!-- Spring framework logger -->
<logger name="org.springframework" level="error" additivity="false"></logger> <logger name="com.XX.XX" level="info" additivity="false">
<appender-ref ref="stdout" />
<appender-ref ref="appLogAppender" />
</logger> <root level="info">
<appender-ref ref="stdout" />
</root>
</configuration>
其他模块配置,例如Dao:
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="false" scanPeriod="60 seconds" debug="false">
<property name="LOG_HOME" value="D:/log" />
<property name="appName" value="index_dao"></property> <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<Encoding>UTF-8</Encoding>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</layout>
</appender> <appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<Encoding>UTF-8</Encoding>
<file>${LOG_HOME}/${appName}.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/${appName}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
<MaxHistory>10</MaxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>500MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern>
</layout>
</appender> <!-- Spring framework logger -->
<logger name="org.springframework" level="error" additivity="false"></logger> <logger name="com.XX.XX" level="info" additivity="false">
<appender-ref ref="stdout" />
<appender-ref ref="appLogAppender" />
</logger> <root level="info">
<appender-ref ref="stdout" />
</root>
</configuration>
在不同的模块有不同的用例,但是service模块依赖dao和common模块,观察service模块会加载哪个文件,dao模块又会加载哪个文件,在用例中取出配置文件的某个值可以直观的看到你到底加载的那个配置文件(我本地使用的是log4j的配置文件,但是我项目中没有log4j的jar,仅仅是适用配置文件中的值输出测试而已)
service模块的值:
log4j.rootLogger=INFO,A1,FF
dao模块的值:
log4j.rootLogger=INFO,A1,FF,dddddddd
common模块的值:
log4j.rootLogger=INFO,A1,FF,ccccccccc
用例:
public class LogTest {
private static Logger logger = LoggerFactory.getLogger(LogTest.class);
public static void main(String[] args) throws Exception {
logger.info("111111");
ClassLoader classLoader = LogTest.class.getClassLoader();
HashSet urlSet = new HashSet();
//看当前类路径下存在的配置文件
Enumeration urlEnum = classLoader.getResources("log4j.properties");
while(urlEnum.hasMoreElements()) {
URL url = (URL)urlEnum.nextElement();
urlSet.add(url);
System.out.println(url);
}
//查找具有给定名称的资源
URL url = classLoader.getResource("log4j.properties");
File file = new File(url.toURI());
BufferedReader bf = new BufferedReader(new FileReader(file));
String s = bf.readLine();
System.out.println(s);
}
}
输出结果:
2016-10-20 16:26:08.439 [main] INFO com.jd.index.storm.LogTest - 111111
file:/D:/IdeaCode/gitCode/index_file/index_file_service/target/classes/log4j.properties
file:/D:/IdeaCode/gitCode/index_file/index_file_common/target/classes/log4j.properties
file:/D:/IdeaCode/gitCode/index_file/index_file_dao/target/classes/log4j.properties
log4j.rootLogger=INFO,A1,FF
输出文件:

从结果可以看出我在service模块的用例加载的是当前模块下的log4j配置文件,而且日志使用的logback配置也是当前模块下的,并没有使用其他模块中的。
具体原因可以参考以下源码:
public void autoConfig() throws JoranException {
StatusListenerConfigHelper.installIfAsked(this.loggerContext);
//在这里加载真正的配置文件
URL url = this.findURLOfDefaultConfigurationFile(true);
if(url != null) {
this.configureByResource(url);
} else {
BasicConfigurator.configure(this.loggerContext);
}
}
public URL findURLOfDefaultConfigurationFile(boolean updateStatus) {
ClassLoader myClassLoader = Loader.getClassLoaderOfObject(this);
URL url = this.findConfigFileURLFromSystemProperties(myClassLoader, updateStatus);
if(url != null) {
return url;
} else {
//通过getResource返回目标文件的URL
url = this.getResource("logback.groovy", myClassLoader, updateStatus);
if(url != null) {
return url;
} else {
url = this.getResource("logback-test.xml", myClassLoader, updateStatus);
return url != null?url:this.getResource("logback.xml", myClassLoader, updateStatus);
}
}
}
private URL getResource(String filename, ClassLoader myClassLoader, boolean updateStatus) {
//通过调用类加载器加载
URL url = Loader.getResource(filename, myClassLoader);
if(updateStatus) {
//输出警告
this.statusOnResourceSearch(filename, myClassLoader, url);
}
return url;
}
public static URL getResource(String resource, ClassLoader classLoader) {
try {
//通过调用类加载器加载
return classLoader.getResource(resource);
} catch (Throwable var3) {
return null;
}
}
ClassLoader中的方法:
此方法首先搜索资源的父类加载器;如果父类加载器为 null,则搜索的路径就是虚拟机的内置类加载器的路径。如果搜索失败,则此方法将调用findResource(String)来查找资源。
public URL getResource(String name) {
URL url;
if (parent != null) {
url = parent.getResource(name);
} else {
url = getBootstrapResource(name);
}
if (url == null) {
url = findResource(name);
}
return url;
}
注意我用例中使用的另一个方法:
public Enumeration<URL> getResources(String name)
资源的 URL 对象的枚举。如果找不到资源,则该枚举将为空。类加载器无权访问的资源不在此枚举中。
public Enumeration<URL> getResources(String name) throws IOException {
Enumeration[] tmp = new Enumeration[2];
if (parent != null) {
tmp[0] = parent.getResources(name);
} else {
tmp[0] = getBootstrapResources(name);
}
tmp[1] = findResources(name);
return new CompoundEnumeration<>(tmp);
}
至此可以看出,logback加载配置文件顺序是调用的类加载器原生的方法,所以加载的顺序以及要加载哪个配置自然和原生的类加载器一样。
简单来说,看你的程序运行在哪个模块,运行时会加载相应的模块的日志配置,并不使用其他模块下的日志配置,虽然同在类路径下。
本项目包含Storm和其他的模块,但是Storm输出日志的时候并不会使用其他模块下的logback的配置,原因就在这里。
在这里顺道唠叨几句Storm日志问题,很多人对此还是有还是有些模糊的,例如使用的是那个篇日志文件,文件名称又是哪里定义的。
storm使用logback作为日志服务插件,配置文件在$STORM_HOME/logback/cluster.xml 。
对于storm,我们关心的主要是worker、nimbus、supervisor等日志(worker-xxxx.log,nimbus.log,supervisor.log),
<appender name="A1" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${storm.home}/logs/${logfile.name}</file>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>${storm.home}/logs/${logfile.name}.%i</fileNamePattern>
<minIndex>1</minIndex>
<maxIndex>9</maxIndex>
</rollingPolicy> <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>1024MB</maxFileSize>
</triggeringPolicy> <encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %c{1} [%p] %m%n</pattern>
</encoder>
</appender> <appender name="ACCESS" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${storm.home}/logs/access.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>${storm.home}/logs/access.log.%i</fileNamePattern>
<minIndex>1</minIndex>
<maxIndex>9</maxIndex>
</rollingPolicy> <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>100MB</maxFileSize>
</triggeringPolicy> <encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %c{1} [%p] %m%n</pattern>
</encoder>
</appender> <appender name="METRICS" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${storm.home}/logs/metrics.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>metrics.log.%i</fileNamePattern>
<minIndex>1</minIndex>
<maxIndex>9</maxIndex>
</rollingPolicy> <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>2MB</maxFileSize>
</triggeringPolicy> <encoder>
<pattern>%d %-8r %m%n</pattern>
</encoder>
</appender> <root level="INFO">
<appender-ref ref="A1"/>
</root>
剖析项目多个logback配置(下)的更多相关文章
- 剖析项目多个logback配置(上)
来源:http://www.cnblogs.com/guozp/p/5949744.html 以下两个是我在使用slf4j + logback时候日志提示的问题,问题不大,都是WARN,并不真正影响运 ...
- Intellij Idea 15 下新建 Hibernate 项目以及如何添加配置
1.说明:Idea 下,项目对应于 Eclipse 下的 workspace,Module 对应于 Eclipse 下的项目.Idea 下,新添加的项目既可以单独作为一个 Project,也可以作为一 ...
- 在SpringBoot项目中添加logback的MDC
在SpringBoot项目中添加logback的MDC 先看下MDC是什么 Mapped Diagnostic Context,用于打LOG时跟踪一个“会话“.一个”事务“.举例,有一个web ...
- JAVA项目中引用Logback的方法
一.简介 本文主要讲JAVA项目中引入Logback的方法. 二.解决 1.引入依赖. <!--Begin LogBack Log--> <!-- https://mvnreposi ...
- Spring Boot系列一:默认日志logback配置解析
前言 今天来介绍下Spring Boot如何配置日志logback,我刚学习的时候,是带着下面几个问题来查资料的,你呢 如何引入日志? 日志输出格式以及输出方式如何配置? 代码中如何使用? 正文 Sp ...
- Java中多环境Logback配置与ELK日志发送
Java中多环境Logback配置与ELK日志发送 一.项目基于SpringBoot实现,引入SpringBoot相关库后,本文还要讲上传到ELK的Logstash,所以需要在pom.xml中加入 ...
- logback配置详解
本文转自:https://segmentfault.com/a/1190000008315137 概览 简单地说,Logback 是一个 Java 领域的日志框架.它被认为是 Log4J 的继承人.L ...
- Logback配置解析
logback优点 比较吸引的几个优点如下: 内核重写,初始化内存加载更小 文档比较齐全 支持自动重新加载配置文件,扫描过程快且安全,它并不需要另外创建一个扫描线程 支持自动去除旧的日志文件,可以控制 ...
- 一秒完成springboot与logback配置
1. 一秒配置与效果 1.1 一秒配置 spring boot中无须添加任何依赖,直接在resources文件夹下面新建logback.xml文件,将以下代码复制过去,配置完成,可以使用了. &l ...
随机推荐
- javafx由浅到深的 认识(一)
javafx是一款比较新兴的语言框架,随着javafx越来越实用,估计许多程序员也会慢慢接触它,故我在这里对它由浅到深进行介绍一下. 首先,要了解javafx,就应该先知道.xml文件的布局软件,以往 ...
- Linux内核优化
相信做运维的同仁,进行运维环境初建时,必须要考虑到操作系统内核参数的优化问题,本人经历数次的运维环境重建后,决定要自行收集一份比较完善的系统内核参数优化说明文件出来,于是就有了下文,本文当前值是官方 ...
- Linux命令学习总结之rmdir命令的相关资料可以参考下
这篇文章主要介绍了Linux命令学习总结之rmdir命令的相关资料,需要的朋友可以参考下(http://www.nanke0834.com) 命令简介: rmdir命令用用来删除空目录,如果目录非空, ...
- 多个PVSS数据点属性读写的优化处理
注:本译文出自15多年前,尚未用最新软硬件平台进行重新测试,只提供方法论层面的参考,具体性能指标不具备参考意义. 多个PVSS数据点属性读写的优化处理 本文档概述了测试三种读取和写入多个PVSS数据点 ...
- oracle行转列、列转行、连续日期数字实现方式及mybatis下实现方式
转载请注明出处:https://www.cnblogs.com/funnyzpc/p/9977591.html 九月份复习,十月份考试,十月底一直没法收心,赶在十一初 由于不可抗拒的原因又不得不重新找 ...
- 我的 FPGA 学习历程(09)—— 时序逻辑入门
讲到这篇时,组合逻辑就告一段落了,下面是一些总结: 描述组合逻辑时,always 语句中的敏感信号列表中需要列出全部的可能影响输出的变量 描述组合逻辑时,always 语句中的赋值总是使用阻塞赋值符号 ...
- 虚拟环境更新HA
停止HA服务 sudo systemctl stop homeassistant@homeassistant 开始更新HA sudo -u homeassistant -H -s cd /srv/ho ...
- Linux下Shell重定向
1. 标准输入,标准输出与标准错误输出 Linux下系统打开3个文件,标准输入,标准输出,标准错误输出. 标准输入:从键盘输入数据,即从键盘读入数据. 标准输出:把数据输出到终端上. 标准错误输出:把 ...
- 【自动化测试】robotframework中一些建议可能需要掌握的关键字
这是2019年的第一篇文章,因公司事情较多,导致更新缓慢.这次主要推荐一些可能在使用rf工具的时候需要掌握的关键字. 1. @{cloose_ele} get webelements xpath= ...
- Prometheus 自定义exporter 监控key
当Prometheus的node_exporter中没有我们需要的一些监控项时,就可以如zabbix一样定制一些key,让其支持我们所需要的监控项. 例如,我要根据 逻辑cpu核数 来确定load的告 ...