来源: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),

这些日志使用的都是配置中的A1(即使用的是默认配置):
<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>
这里的${storm.home}、${logfile.name}这个是从哪里传入的呢?可以从bin/storm脚本中看到nimbus、ui、supervisor是在启动的时候传入了storm.home和logfile.name。
Storm中worker的日志,使用当前work的端口,并且只有在集群有topology运行的时候才会生成,可以再supervisor.clj的launch-worker方法中生成了logfile.name

阅读源码,可以看到在形如:worker-6719.log。

 
 

剖析项目多个logback配置(下)的更多相关文章

  1. 剖析项目多个logback配置(上)

    来源:http://www.cnblogs.com/guozp/p/5949744.html 以下两个是我在使用slf4j + logback时候日志提示的问题,问题不大,都是WARN,并不真正影响运 ...

  2. Intellij Idea 15 下新建 Hibernate 项目以及如何添加配置

    1.说明:Idea 下,项目对应于 Eclipse 下的 workspace,Module 对应于 Eclipse 下的项目.Idea 下,新添加的项目既可以单独作为一个 Project,也可以作为一 ...

  3. 在SpringBoot项目中添加logback的MDC

    在SpringBoot项目中添加logback的MDC     先看下MDC是什么 Mapped Diagnostic Context,用于打LOG时跟踪一个“会话“.一个”事务“.举例,有一个web ...

  4. JAVA项目中引用Logback的方法

    一.简介 本文主要讲JAVA项目中引入Logback的方法. 二.解决 1.引入依赖. <!--Begin LogBack Log--> <!-- https://mvnreposi ...

  5. Spring Boot系列一:默认日志logback配置解析

    前言 今天来介绍下Spring Boot如何配置日志logback,我刚学习的时候,是带着下面几个问题来查资料的,你呢 如何引入日志? 日志输出格式以及输出方式如何配置? 代码中如何使用? 正文 Sp ...

  6. Java中多环境Logback配置与ELK日志发送

    Java中多环境Logback配置与ELK日志发送   一.项目基于SpringBoot实现,引入SpringBoot相关库后,本文还要讲上传到ELK的Logstash,所以需要在pom.xml中加入 ...

  7. logback配置详解

    本文转自:https://segmentfault.com/a/1190000008315137 概览 简单地说,Logback 是一个 Java 领域的日志框架.它被认为是 Log4J 的继承人.L ...

  8. Logback配置解析

    logback优点 比较吸引的几个优点如下: 内核重写,初始化内存加载更小 文档比较齐全 支持自动重新加载配置文件,扫描过程快且安全,它并不需要另外创建一个扫描线程 支持自动去除旧的日志文件,可以控制 ...

  9. 一秒完成springboot与logback配置

    1. 一秒配置与效果 1.1 一秒配置 ​ spring boot中无须添加任何依赖,直接在resources文件夹下面新建logback.xml文件,将以下代码复制过去,配置完成,可以使用了. &l ...

随机推荐

  1. iOS开发从申请开发账号到APP上架的整体流程详解

    应公司要求,写一份文档从申请账号一直到APP上架的整体流程,下面进入正文. https://blog.csdn.net/qq_35612929/article/details/78754470 首先第 ...

  2. python序列化与反序列

    python序列化与反序列 在python中提供了两个模块可进行序列化.分别是pickle和json.他们两者的功能都差不多,dumps和dump都是进行序列化,而loads和load则是反序列化. ...

  3. restful规范简要概述

    在 RESTful 架构概念详解 中聊了一些概念和约束, 本篇主要简要的聊一聊 RESTful API 规范概要设计, 内容源自 阮一峰老师的博客 一. 协议(protocol) 服务端的 API 与 ...

  4. kafka原理和架构

    转载自:  https://blog.csdn.net/lp284558195/article/details/80297208 参考:   https://blog.csdn.net/qq_2059 ...

  5. MonggoDB(二)

    分组聚合 如果你有数据存储在MongoDB中,你想做的可能就不仅仅是将数据提取出来这么简单,可能需要对数据进行分析并加以利用. 聚合框架:可以使用多个构件创建一个管道,上一个构件的结果传给下一个构件. ...

  6. 极速创建 IOS APP !涛舅舅苹果 IOS APP自助生成系统!不用证书、不用越狱、永久可用

    不用签名将网页封装成苹果APP,无需苹果企业签名,IPA签名,ios签名,免越狱安装 (本方法只支持网站封装app,原生的用不了,详细请咨询客服) 近期很多朋友问我把网站变成app的方法,原因很多种, ...

  7. js活jQuery实现动态添加、移除css/js文件

    下面是在项目中用到的,直接封装好的函数,拿去在js中直接调用就可以实现css.js文件的动态引入与删除.代码如下 动态加载,移除,替换css/js文件 // 动态添加css文件 function ad ...

  8. PeopleSoft 启用多语言输入

    今天,我的一位同事询问有的人有语言选择,有的人没有(如下图所示). 以下是PT856.09菜单路经: 主菜单-->我的首选项--->一般设置--->多语言条目

  9. leetcode-只出现一次的数字合并两个有序数组

    题目:合并两个有序数组 给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组. 说明: 初始化 nums1 和 nums2 的元素 ...

  10. 小程序重新封装打印函数console.log

    习惯性使用console.log打印获取到的数据,信息等,然后上星期大佬看见了说怎么那么多打印信息出来,线上那个也是吗?问我能不能线上的就不打印出来? 我就说那就封装一个打印函数呗. 重写一个没问题, ...