日志订阅要有三种:(catalina会自动订阅,不自动订阅时当然也要解决)
logback或log4j的业务日志,tomcat的应用初始化日志,nginx的access和error日志
logback里用if else需要单独处理,暂不能用,可以先指定一个配置文件来读取环境变量
https://www.cnblogs.com/warking/p/5710303.html
可以用<property和<if <then指定环境
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property resource="supplier-web.properties"/>
<!--输出到控制台-->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d %-5level %logger - %msg%n</pattern>
</encoder>
</appender>
<if condition='"${app.env}".equalsIgnoreCase("pre") || "${app.env}".equalsIgnoreCase("pro")'>
<then>
<!--应用日志输出到文件-->
<appender name="SUPPLIER-WEB" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path.supplier}/supplier-web.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- daily rollover -->
<fileNamePattern>${log.path.supplier}/supplier-web.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>100MB</maxFileSize>
<maxHistory>60</maxHistory>
<totalSizeCap>20GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d %-5level %logger - %msg%n</pattern>
</encoder>
</appender>
<appender name="SUPPLIER" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path.supplier}/supplier.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- daily rollover -->
<fileNamePattern>${log.path.supplier}/supplier.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>500MB</maxFileSize>
<maxHistory>60</maxHistory>
<totalSizeCap>20GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d %-5level %logger - %msg%n</pattern>
</encoder>
</appender>
<appender name="BASE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path.base}/base.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- daily rollover -->
<fileNamePattern>${log.path.base}/base.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>100MB</maxFileSize>
<maxHistory>60</maxHistory>
<totalSizeCap>20GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d %-5level %logger - %msg%n</pattern>
</encoder>
</appender>
<appender name="PRODUCT" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path.product}/product.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- daily rollover -->
<fileNamePattern>${log.path.product}/product.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>100MB</maxFileSize>
<maxHistory>60</maxHistory>
<totalSizeCap>20GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d %-5level %logger - %msg%n</pattern>
</encoder>
</appender>
<!--supplier web 模块的日志输出到指定文件-->
<logger name="com.jd.ihhotel.supplier.webapp" level="${log.level}">
<appender-ref ref="SUPPLIER-WEB"/>
<appender-ref ref="STDOUT"/>
</logger>
<!--supplier模块的日志输出到指定文件-->
<logger name="com.jd.ihhotel.supplier.biz" level="${log.level}" additivity="false">
<appender-ref ref="SUPPLIER"/>
<appender-ref ref="STDOUT"/>
</logger>
<!--base模块的日志输出到指定文件-->
<logger name="com.jd.ihhotel.base" level="${log.level}" additivity="false">
<appender-ref ref="BASE"/>
<appender-ref ref="STDOUT"/>
</logger>
<logger name="com.jd.ihhotel.product" level="${log.level}" additivity="false">
<appender-ref ref="PRODUCT"/>
<appender-ref ref="STDOUT"/>
</logger>
</then>
</if>
<root level="${log.level}">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
关键:配置要打印日志的代码路径和日志文件路径
logger的name配置哪些类或包下的所有类打印日志
配置文件路径时文件夹不知道用不用选(logback在代码里配的路径文件夹可以自己创建),文件会自己创建
实现:1.创建log4j2.xml 2.配置依赖
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="OFF">
<appenders>
<!--访问日志-->
<RollingFile name="MAN" fileName="/export/Logs/ihman.jd.com/man.log"
filePattern="/export/Logs/ihman.jd.com/man.log.%d{yyyy-MM-dd}.gz">
<PatternLayout pattern="%d{yyyy/MM/dd HH:mm:ss.SSS} [%t] %-5level %logger{1.} - %msg%n" charset="UTF-8"/>
<Policies>
<TimeBasedTriggeringPolicy modulate="true" interval="1"/>
</Policies>
</RollingFile>
<!--访问日志-->
<RollingFile name="SUPPLIER" fileName="/export/Logs/ihman.jd.com/supplier.log"
filePattern="/export/Logs/ihman.jd.com/supplier.log.%d{yyyy-MM-dd}.gz">
<PatternLayout pattern="%d{yyyy/MM/dd HH:mm:ss.SSS} [%t] %-5level %logger{1.} - %msg%n" charset="UTF-8"/>
<Policies>
<TimeBasedTriggeringPolicy modulate="true" interval="1"/>
</Policies>
</RollingFile>
<!--访问日志-->
<RollingFile name="BASE" fileName="/export/Logs/ihman.jd.com/base.log"
filePattern="/export/Logs/ihman.jd.com/supplier.log.%d{yyyy-MM-dd}.gz">
<PatternLayout pattern="%d{yyyy/MM/dd HH:mm:ss.SSS} [%t] %-5level %logger{1.} - %msg%n" charset="UTF-8"/>
<Policies>
<TimeBasedTriggeringPolicy modulate="true" interval="1"/>
</Policies>
</RollingFile>
<!--访问日志-->
<RollingFile name="PRODUCT" fileName="/export/Logs/ihman.jd.com/product.log"
filePattern="/export/Logs/ihman.jd.com/product.log.%d{yyyy-MM-dd}.gz">
<PatternLayout pattern="%d{yyyy/MM/dd HH:mm:ss.SSS} [%t] %-5level %logger{1.} - %msg%n" charset="UTF-8"/>
<Policies>
<TimeBasedTriggeringPolicy modulate="true" interval="1"/>
</Policies>
</RollingFile>
</appenders>
<loggers>
<logger name="com.jd.ihhotel.man" level="info">
<appender-ref ref="MAN"/>
</logger>
<!--supplier模块的日志输出到指定文件-->
<logger name="com.jd.ihhotel.supplier" level="info" additivity="false">
<appender-ref ref="SUPPLIER"/>
</logger>
<!--base模块的日志输出到指定文件-->
<logger name="com.jd.ihhotel" level="info" additivity="false">
<appender-ref ref="BASE"/>
</logger>
<logger name="com.jd.ihhotel.product" level="info" additivity="false">
<appender-ref ref="PRODUCT"/>
</logger>
</loggers>
</configuration>
单纯logback的使用不好:(配置复杂,找不到哪里配目标类路径)
import ch.qos.logback.classic.encoder.PatternLayoutEncoder
import ch.qos.logback.classic.net.*
import ch.qos.logback.core.*
import ch.qos.logback.core.encoder.*
import ch.qos.logback.core.read.*
import ch.qos.logback.core.rolling.*
import ch.qos.logback.core.status.*
import com.jd.immortal.log.logback.LogbackAppender
statusListener(OnConsoleStatusListener)
def props = new Properties()
props.load(this.getClass().getClassLoader().getResourceAsStream("properties/application.properties"))
def config = new ConfigSlurper().parse(props)
def env = System.properties['spring.profiles.active'] ?: 'production'
def appenderList = []
def level = INFO
def LOG_DIR = '/export/Logs/'+config.appname+'.jd.local'
def LOG_PREFIX = '-webapp'
if (env == 'production') {
appenderList.add("ROLLING")
} else if(env == 'integratetest') {
appenderList.add("ROLLING")
level = WARN
} else if(env == 'development') {
appenderList.add("CONSOLE")
level = DEBUG
}
if(env=='development') {
appender("CONSOLE", ConsoleAppender) {
encoder(PatternLayoutEncoder) { pattern = "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" }
}
}
if(env=='production' || env=='integratetest') {
appender("ROLLING", RollingFileAppender) {
file = "${LOG_DIR}/logs/log${LOG_PREFIX}.log"
encoder(PatternLayoutEncoder) { Pattern = "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" }
rollingPolicy(TimeBasedRollingPolicy) {
fileNamePattern = "${LOG_DIR}/logs/log${LOG_PREFIX}-%d{yyyy-MM-dd}.zip"
//triggeringPolicy(timeBasedFileNamingAndTriggeringPolicy) { maxFileSize = '10M' }
}
}
}
if(env=='production' || env=='integratetest') {
appender("IMMORTAL", LogbackAppender) {
//encoder(PatternLayoutEncoder) {
// pattern = "%date [%thread] %-5level %logger{80} - %msg%n"
//}
}
// logger("com.jd.ihtrade.core.controller", INFO, ["IMMORTAL"], false)
appender("ImmortalTraceFileAppender", RollingFileAppender) {
file = "${LOG_DIR}/traces/log${LOG_PREFIX}-trace.out"
rollingPolicy(FixedWindowRollingPolicy) {
fileNamePattern = "${LOG_DIR}/traces/log${LOG_PREFIX}-trace-%i.out"
minIndex = 1
maxIndex = 10
}
append = true
triggeringPolicy(SizeBasedTriggeringPolicy) {
maxFileSize = "10GB"
}
encoder(PatternLayoutEncoder) {
pattern = "%msg%n"
}
}
logger("immortal-trace-logger", INFO, ["ImmortalTraceFileAppender"], false)
appender("ImmortalLogFileAppender", RollingFileAppender) {
file = "${LOG_DIR}/traces/log${LOG_PREFIX}-log.out"
rollingPolicy(FixedWindowRollingPolicy) {
fileNamePattern = "${LOG_DIR}/traces/${LOG_PREFIX}-log-%i.out"
minIndex = 1
maxIndex = 10
}
append = true
triggeringPolicy(SizeBasedTriggeringPolicy) {
maxFileSize = "10GB"
}
encoder(PatternLayoutEncoder) {
pattern = "%msg%n"
}
}
logger("immortal-log-logger", INFO, ["ImmortalLogFileAppender"], false)
appender("ImmortalMetricFileAppender", RollingFileAppender) {
file = "${LOG_DIR}/traces/log${LOG_PREFIX}-metric.out"
rollingPolicy(FixedWindowRollingPolicy) {
fileNamePattern = "${LOG_DIR}/traces/log${LOG_PREFIX}-metric-%i.out"
minIndex = 1
maxIndex = 10
}
append = true
triggeringPolicy(SizeBasedTriggeringPolicy) {
maxFileSize = "10GB"
}
encoder(PatternLayoutEncoder) {
pattern = "%msg%n"
}
}
logger("immortal-metric-logger", INFO, ["ImmortalMetricFileAppender"], false)
}
root(level, appenderList)
怎么把代码里error,debug等级别的日志打出来?
对于slf4j:一共分为五个级别:DEBUG、INFO、WARN、ERROR和FATAL。这五个级别是有顺序的,DEBUG < INFO < WARN < ERROR < FATAL,明白这一点很重要,这里Log4j有一个规则:假设设置了级别为P,如果发生了一个级别Q比P高,则可以启动,否则屏蔽掉。(设置info,warn和error,fatal自动会打)
logback怎么配不同包打到不同路径
logback.groovy专门配环境?jdos预发环境的配置没有配logback.xml也没有自动生成logback.xml,难道是配置logback.groovy就不用配logback.xml了?
cat/export/Logs/Domains/应用名.com/server1/logs/localhost.2018-09-21.log是tomcat的应用初始化日志:
tomcat日志有下面五种:在tomcat的logging.properties中配置
catalina 、 localhost 、 manager 、 admin 、 host-manager
localhost.日期.log只打印应用初始化信息,所以只在项目部署时应用初始化时打印,不是每天都打印。订阅只能订阅部署当天的,不知道哪天部署的就重新部署。
catalina.home catalina.base 区别
https://blog.csdn.net/xiaohai0504/article/details/7631014
catalina.out为什么有时候打业务日志有时候不打??
logback会依次读取以下类型配置文件:
logback.groovy
logback-test.xml
logback.xml 如果均不存在会采用默认配置
logback会自动使用BasicConfigurator來配置自己,这将导致日志定向输出到控制台。 自動配置 假设logback的配置文件logback-test.xml或logback.xml不存在,logback将默认调用BasicConfigurator,設置最精簡配置。这个最小的配置包括一个ConsoleAppender設置在root logger下。 使用PatternLayoutEncoder進行輸出格式化,格式爲 %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n。此外,在默认情况下根记录器被指定爲debug级别。
对于logback.groovy的使用,需要注意: logback.groovy需要放在源码包的根目录下,否则会找不到。 在eclipse中,如果安装了groovy的插件,需要将放置logback.groovy的源码包位置设置为groovysrcipt的所在位置,即在编译的时候不将goorvy编译成class文件,而是直接将groovy脚本复制到output path下。否则仍无法生效。
log4j只需要引入一个jar包即可,
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
而log4j 2则是需要2个核心
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.5</version>
</dependency>
log4j与日志门面slf4j结合使用需要的jar:
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>(用于和log4j绑定)
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
logback和slf4j结合标准样例:
依赖:
<!--logback的jar包:两个slf三个lokback,再多其他包容易出错-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.8</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.8</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.1.6</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-access</artifactId>
<version>1.1.6</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.6</version>
</dependency>
配置:
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<contextName>checkStaticData</contextName>
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<property name="LOG_HOME" value="E:/Logback/log/checkStaticData" />
<!-- 控制台输出(必须配logger标签才能生效) -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 按照每天生成日志文件(必须配logger标签才能生效) -->
<appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/TestWeb.log.%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<Encoding>UTF-8</Encoding>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
<!--日志文件最大的大小-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>
</appender>
<!--打印info级别的日志-->
<logger name="infoLog" level="info" additivity="false">
<appender-ref ref="INFO" />
</logger>
<!-- 日志输出级别 -->
<root level="INFO">
<appender-ref ref="INFO" />
<appender-ref ref="STDOUT" />
</root>
</configuration>
log4j2和slf4j结合标准样例:
<!-- slf4j核心包-->
2 <dependency>
3 <groupId>org.slf4j</groupId>
4 <artifactId>slf4j-api</artifactId>
5 <version>1.7.13</version>
6 </dependency>
7 <dependency>
8 <groupId>org.slf4j</groupId>
9 <artifactId>jcl-over-slf4j</artifactId>
10 <version>1.7.13</version>
11 <scope>runtime</scope>
12 </dependency>
13
14 <!--核心log4j2jar包-->
15 <dependency>
16 <groupId>org.apache.logging.log4j</groupId>
17 <artifactId>log4j-api</artifactId>
18 <version>2.4.1</version>
19 </dependency>
20 <dependency>
21 <groupId>org.apache.logging.log4j</groupId>
22 <artifactId>log4j-core</artifactId>
23 <version>2.4.1</version>
24 </dependency>
25 <!--用于与slf4j保持桥接-->
26 <dependency>
27 <groupId>org.apache.logging.log4j</groupId>
28 <artifactId>log4j-slf4j-impl</artifactId>
29 <version>2.4.1</version>
30 </dependency>
31 <!--web工程需要包含log4j-web,非web工程不需要-->
32 <dependency>
33 <groupId>org.apache.logging.log4j</groupId>
34 <artifactId>log4j-web</artifactId>
35 <version>2.4.1</version>
36 <scope>runtime</scope>
37 </dependency>
38
39 <!--需要使用log4j2的AsyncLogger需要包含disruptor-->
40 <dependency>
41 <groupId>com.lmax</groupId>
42 <artifactId>disruptor</artifactId>
43 <version>3.2.0</version>
44 </dependency>
2.web.xml中设置log4j2的监听器和过滤器(servlet3.0及以上版本不需要该步操作)
1 <!--对于log4j2,Servlet2.5以前的版本需要-->
2 <listener>
3 <listener-class>org.apache.logging.log4j.web.Log4jServletContextListener</listener-class>
4 </listener>
5 <filter>
6 <filter-name>log4jServletFilter</filter-name>
7 <filter-class>org.apache.logging.log4j.web.Log4jServletFilter</filter-class>
8 </filter>
9 <filter-mapping>
10 <filter-name>log4jServletFilter</filter-name>
11 <url-pattern>/*</url-pattern>
12 <dispatcher>REQUEST</dispatcher>
13 <dispatcher>FORWARD</dispatcher>
14 <dispatcher>INCLUDE</dispatcher>
15 <dispatcher>ERROR</dispatcher>
16 </filter-mapping>
注意:log4j2不再支持properties文件了,只支持xml,json或是yaml,不指定位置的情况下默认在src/main/resources下查找。
如果需要自定义位置,需要在上面的web.xml中添加以下代码
1 <context-param>
2 <param-name>log4jConfiguration</param-name>
3 <param-value>/WEB-INF/classes/log4j2.xml</param-value>
4 </context-param>
3.log4j2.xml
1 <?xml version="1.0" encoding="UTF-8"?>
2
3 <Configuration status="off" monitorInterval="1800">
4
5 <properties>
6 <property name="LOG_HOME">/opt/logs/hafiz/log4j2Demo/logs</property>
7 <property name="ERROR_LOG_FILE_NAME">error</property>
8 </properties>
9
10
11 <Appenders>
12 <Console name="Console" target="SYSTEM_OUT">
13 <PatternLayout pattern="%d %-5p (%F:%L) - %m%n" />
14 </Console>
15
16 <RollingRandomAccessFile name="ErrorLog"
17 fileName="${LOG_HOME}/${ERROR_LOG_FILE_NAME}.log"
18 filePattern="${LOG_HOME}/${ERROR_LOG_FILE_NAME}.log.%d{yyyy-MM-dd}.gz">
19 <PatternLayout
20 pattern="%d %-5p (%F:%L) - %m%n"/>
21 <Policies>
22 <TimeBasedTriggeringPolicy/>
23 <SizeBasedTriggeringPolicy size="100 MB"/>
24 </Policies>
25 <DefaultRolloverStrategy max="20"/>
26 </RollingRandomAccessFile>
27
28 </Appenders>
29
30 <Loggers>
31 <!-- 3rdparty Loggers -->
32 <logger name="org.springframework.core" level="info">
33 </logger>
34 <logger name="org.springframework.beans" level="info">
35 </logger>
36 <logger name="org.springframework.context" level="info">
37 </logger>
38 <logger name="org.springframework.web" level="info">
39 </logger>
40
41 <logger name="com.hafiz.www.controller" level="error" includeLocation="true" additivity="false">
42 <appender-ref ref="ErrorLog"/>
43 <appender-ref ref="Console"/>
44 </logger>
45
46 <root level="info" includeLocation="true">
47 <appender-ref ref="Console"/>
48 </root>
49 </Loggers>
50 </Configuration>
预防多种绑定:
引入公共组件时排除非自己系统的日志组件的绑定:
log4j的绑定是:
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
logback的绑定看日志貌似是:
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
log4j2的绑定是:
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
slf4j转向某个实际的日志框架:
场景介绍:如 使用slf4j的API进行编程,底层想使用log4j1来进行实际的日志输出,这就是slf4j-log4j12干的事。
- slf4j-jdk14:slf4j到jdk-logging的桥梁
- slf4j-log4j12:slf4j到log4j1的桥梁
- log4j-slf4j-impl:slf4j到log4j2的桥梁:
-
- logback-classic:slf4j到logback的桥梁
- slf4j-jcl:slf4j到commons-logging的桥梁
java 界里有许多实现日志功能的工具,最早得到广泛使用的是 log4j,许多应用程序的日志部分都交给了 log4j,不过作为组件开发者,他们希望自己的组件不要紧紧依赖某一个工具,毕竟在同一个时候还有很多其他很多日志工具,假如一个应用程序用到了两个组件,恰好两个组件使用不同的日志工具,那么应用程序就会有两份日志输出了。
为了解决这个问题,Apache Commons Logging (之前叫 Jakarta Commons Logging,JCL)粉墨登场,JCL 只提供 log 接口,具体的实现则在运行时动态寻找。这样一来组件开发者只需要针对 JCL 接口开发,而调用组件的应用程序则可以在运行时搭配自己喜好的日志实践工具。
所以即使到现在你仍会看到很多程序应用 JCL + log4j 这种搭配,不过当程序规模越来越庞大时,JCL的动态绑定并不是总能成功,具体原因大家可以 Google 一下,这里就不再赘述了。解决方法之一就是在程序部署时静态绑定指定的日志工具,这就是 SLF4J 产生的原因。
跟 JCL 一样,SLF4J 也是只提供 log 接口,具体的实现是在打包应用程序时所放入的绑定器(名字为 slf4j-XXX-version.jar)来决定,XXX 可以是 log4j12, jdk14, jcl, nop 等,他们实现了跟具体日志工具(比如 log4j)的绑定及代理工作。举个例子:如果一个程序希望用 log4j 日志工具,那么程序只需针对 slf4j-api 接口编程,然后在打包时再放入 slf4j-log4j12-version.jar 和 log4j.jar 就可以了。
现在还有一个问题,假如你正在开发应用程序所调用的组件当中已经使用了 JCL 的,还有一些组建可能直接调用了 java.util.logging,这时你需要一个桥接器(名字为 XXX-over-slf4j.jar)把他们的日志输出重定向到 SLF4J,所谓的桥接器就是一个假的日志实现工具,比如当你把 jcl-over-slf4j.jar 放到 CLASS_PATH 时,即使某个组件原本是通过 JCL 输出日志的,现在却会被 jcl-over-slf4j “骗到”SLF4J 里,然后 SLF4J 又会根据绑定器把日志交给具体的日志实现工具。过程如下
Component
|
| log to Apache Commons Logging
V
jcl-over-slf4j.jar — (redirect) —> SLF4j —> slf4j-log4j12-version.jar —> log4j.jar —> 输出日志
看到上面的流程图可能会发现一个有趣的问题,假如在 CLASS_PATH 里同时放置 log4j-over-slf4j.jar 和 slf4j-log4j12-version.jar 会发生什么情况呢?没错,日志会被踢来踢去,最终进入死循环。此时要么去掉log4j-over-slf4j桥接器,要么替换slf4j的实现,比如换成logback,否则陷入死循环
https://my.oschina.net/pingpangkuangmo/blog/410224 各种日志系统
log4j.properties示例:
log4j.rootLogger=INFO, stdout, D, E log4j.logger.com.baijia=INFO log4j.logger.org.jgroups=TRACE log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %X{logger_id} %5p %c{1}:%M:%L - %m%n log4j.appender.D=org.apache.log4j.DailyRollingFileAppender log4j.appender.D.File=${catalina.base}/logs/weishi.log log4j.appender.D.Append=true log4j.appender.D.Threshold=INFO log4j.appender.D.layout=org.apache.log4j.PatternLayout log4j.appender.D.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %X{logger_id} %5p %c{1}:%M:%L - %m%n log4j.appender.E=org.apache.log4j.DailyRollingFileAppender log4j.appender.E.File=${catalina.base}/logs/error.log log4j.appender.E.Append=true log4j.appender.E.Threshold=ERROR log4j.appender.E.layout=org.apache.log4j.PatternLayout log4j.appender.E.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %X{logger_id} %5p %c{1}:%M:%L - %m%n