logback使用与解析
来源:互联网 发布:手机服务器端口 编辑:程序博客网 时间:2024/06/05 18:22
logback使用与解析
项目中使用了logback,蹭着项目发布后的闲暇时间总结下。
先说使用,了解怎么用后带着疑问再看具体的解析。
maven依赖
项目中使用了maven进行管理,logback的maven依赖:
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j_version}</version></dependency><dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>${logback_version}</version></dependency><dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>${logback_version}</version></dependency>
jar包间的关系
可以看到引入了slf4j-api、logback-core、logback-classic这三个jar包。
slf4j:Simple Logging Facade for Java,为java提供的日志接口。
logback当前分成三个模块:logback-core,logback-classic和logback-access。logback-core是其它两个模块的基础模块。logback-classic是log4j的一个 改良版本。此外logback-classic完整实现SLF4J API使你可以很方便地更换成其它日志系统如log4j或JDK14 Logging。logback-access访问模块与Servlet容器集成提供通过Http来访问日志的功能。
关系图:
web.xml配置
我们的项目中在web.xml中进行了配置,使得spring与logback结合:
在web.xml中配置一个listener.同时配置一个上下文参数,用于指定logback.xml配置文件的路径。
<!-- 添加日志监听器 --><context-param> <param-name>logbackConfigLocation</param-name> <param-value>classpath:logback.xml</param-value></context-param><listener> <listener-class>ch.qos.logback.ext.spring.web.LogbackConfigListener</listener-class></listener>
logback.xml文件解析
<?xml version="1.0" encoding="UTF-8"?><configuration> <property name="LOG_PATH" value="/usr/local/tomcat/tomcat_log/manage-server"/> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <Target>System.out</Target> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} [%-5level] [%logger.%M:%L] |%msg%n</pattern> <!--<charset>utf-8</charset>--> </encoder> <!-- 此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息--> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>debug</level> </filter> </appender> <appender name="platform" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_PATH}/platform.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 每天生成一个文件,存放到目录下--> <fileNamePattern>${LOG_PATH}/%d{yyyy-MM-dd}/platform.%d{yyyy-MM-dd}.%i.log</fileNamePattern> <maxHistory>30</maxHistory> <!-- 如果当个文件大于500M,则重新生成文件--> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>500MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} > %msg%n</pattern> <charset>utf-8</charset> </encoder> </appender> <appender name="platform.async" class="ch.qos.logback.classic.AsyncAppender"> <discardingThreshold>0</discardingThreshold> <queueSize>256</queueSize> <appender-ref ref="platform"/> </appender> <appender name="access" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_PATH}/access.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 每天生成一个文件,存放到目录下--> <fileNamePattern>${LOG_PATH}/%d{yyyy-MM-dd}/access.%d{yyyy-MM-dd}.%i.log</fileNamePattern> <maxHistory>30</maxHistory> <!-- 如果当个文件大于500M,则重新生成文件--> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>500MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} > %msg%n</pattern> <charset>utf-8</charset> </encoder> </appender> <appender name="access.async" class="ch.qos.logback.classic.AsyncAppender"> <discardingThreshold>0</discardingThreshold> <queueSize>256</queueSize> <appender-ref ref="access"/> </appender> <appender name="debug" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_PATH}/debug.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 每天生成一个文件,存放到目录下--> <fileNamePattern>${LOG_PATH}/%d{yyyy-MM-dd}/debug.%d{yyyy-MM-dd}.%i.log</fileNamePattern> <maxHistory>30</maxHistory> <!-- 如果当个文件大于500M,则重新生成文件--> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>500MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} > %msg%n</pattern> <charset>utf-8</charset> </encoder> </appender> <appender name="debug.async" class="ch.qos.logback.classic.AsyncAppender"> <discardingThreshold>0</discardingThreshold> <queueSize>256</queueSize> <appender-ref ref="debug"/> </appender> <appender name="system" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_PATH}/system.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 每天生成一个文件,存放到目录下--> <fileNamePattern>${LOG_PATH}/%d{yyyy-MM-dd}/system.%d{yyyy-MM-dd}.%i.log</fileNamePattern> <maxHistory>30</maxHistory> <!-- 如果当个文件大于500M,则重新生成文件--> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>500MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} > %msg%n</pattern> <charset>utf-8</charset> </encoder> </appender> <appender name="system.async" class="ch.qos.logback.classic.AsyncAppender"> <discardingThreshold>0</discardingThreshold> <queueSize>256</queueSize> <appender-ref ref="system"/> </appender> <appender name="error" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_PATH}/error.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 每天生成一个文件,存放到目录下--> <fileNamePattern>${LOG_PATH}/%d{yyyy-MM-dd}/error.%d{yyyy-MM-dd}.%i.log</fileNamePattern> <maxHistory>30</maxHistory> <!-- 如果当个文件大于500M,则重新生成文件--> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>500MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} > %msg%n</pattern> <charset>utf-8</charset> </encoder> </appender> <appender name="error.async" class="ch.qos.logback.classic.AsyncAppender"> <discardingThreshold>0</discardingThreshold> <queueSize>256</queueSize> <appender-ref ref="error"/> </appender> <logger name="myph.log.access" level="info" additivity="false"> <appender-ref ref="access.async"/> </logger> <logger name="myph.log.exception" level="info" additivity="false"> <appender-ref ref="error.async"/> </logger> <logger name="myph.log.system" level="info" additivity="false"> <appender-ref ref="system.async"/> </logger> <logger name="myph.log.debug" level="info" additivity="false"> <appender-ref ref="debug.async"/> </logger> <!--输入spring的error --> <logger name="com.myph" level="debug"/> <logger name="com.alibaba.dubbo" level="debug"/> <logger name="com.ibatis" level="debug"/> <logger name="org.springframework" level="debug"/> <logger name="com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate" level="debug"/> <logger name="org.apache.commons" level="debug"/> <logger name="catalia" level="debug"/> <logger name="org.apache" level="debug"/> <logger name="org.apache.shiro" level="debug"/> <logger name="com.ibatis.common.jdbc.SimpleDataSource" level="debug"/> <logger name="java.sql.ResultSet" level="debug"/> <logger name="com.ibatis.common.jdbc.ScriptRunner" level="debug"/> <logger name="java.sql.Connection" level="debug"/> <logger name="java.sql.PreparedStatement" level="debug"/> <!--定义root 级别 --> <root level="info"> <appender-ref ref="platform.async"/> <!--<!– 本地测试开始–>--> <appender-ref ref="STDOUT"/> </root></configuration>
logback.xml文件结构
configuration
根节点configuration包含以下参数:
scan:当此属性为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
scanPeriod:scan为true时此属性生效。设置检测配置文件是否有修改的时间间隔,默认单位毫秒,默认时间间隔一分钟。
debug:当此属性为true时,将打印出logback内部日志信息,实时查看logback运行状态,默认false。
样例:
<configuration scan="true" scanPeriod="60 seconds" debug="false"> <!-- --> </configuration>
property
property用于定义变量值,通过property定义的值会被插入到logger上下文中,定义变量后,可以使用‘${}’来使用变量。
样例:
<property name="LOG_PATH" value="/usr/local/tomcat/tomcat_log/manage-server"/>
appender
appender是configuration的子节点,是负责写日志的组件。
appender有有两个必要属性name和class。name指定appender名称,class指定appender的全限定名。
配置文件中有这样几种class:ConsoleAppender、RollingFileAppender、AsyncAppender。
ConsoleAppender
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <Target>System.out</Target> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} [%-5level] [%logger.%M:%L] |%msg%n</pattern> <!--<charset>utf-8</charset>--> </encoder> <!-- 此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息--> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>debug</level> </filter></appender>
把日志添加到控制台,有以下子节点:
encoder:对日志进行格式化。
target:字符串 System.out 或者 System.err ,默认 System.out ;
这里还用到了filter标签,filter是过滤器。过滤器被添加到 中,为 添加一个或多个过滤器后,可以用任意条件对日志进行过滤。 有多个过滤器时,按照配置顺序执行。
这里用到了ThresholdFilter,临界值过滤器,过滤掉低于指定临界值的日志。当日志级别等于或高于临界值时,过滤器返回NEUTRAL;当日志级别低于临界值时,日志会被拒绝。
RollingFileAppender
<appender name="platform" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_PATH}/platform.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 每天生成一个文件,存放到目录下--> <fileNamePattern>${LOG_PATH}/%d{yyyy-MM-dd}/platform.%d{yyyy-MM-dd}.%i.log</fileNamePattern> <maxHistory>30</maxHistory> <!-- 如果当个文件大于500M,则重新生成文件--> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>500MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} > %msg%n</pattern> <charset>utf-8</charset> </encoder></appender>
滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件。有以下子节点:
file:被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值。
append:如果是 true,日志被追加到文件结尾,如果是 false,清空现存文件,默认是true。
encoder:对记录事件进行格式化。
rollingPolicy:当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名。
triggeringPolicy : 告知 RollingFileAppender 合适激活滚动。
prudent:当为true时,不支持FixedWindowRollingPolicy。支持TimeBasedRollingPolicy,但是有两个限制,1不支持也不允许文件压缩,2不能设置file属性,必须留空。
TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动。有以下子节点:
fileNamePattern:
必要节点,包含文件名及“%d”转换符, “%d”可以包含一个 java.text.SimpleDateFormat指定的时间格式,如:%d{yyyy-MM}。如果直接使用 %d,默认格式是 yyyy-MM-dd。 RollingFileAppender 的file字节点可有可无,通过设置file,可以为活动文件和归档文件指定不同位置,当前日志总是记录到file指定的文件(活动文件),活动文件的名字不会改变;如果没设置file,活动文件的名字会根据fileNamePattern 的值,每隔一段时间改变一次。“/”或者“\”会被当做目录分隔符。
maxHistory:
可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每个月滚动,且 maxHistory是6,则只保存最近6个月的文件,删除之前的旧文件。注意,删除旧文件是,那些为了归档而创建的目录也会被删除。
AsyncAppender
AsyncAppender:异步记录日志。需要注意的是,用了异步后,日志可能会缺失。缺失是由于其工作原理决定的。
<appender name="platform.async" class="ch.qos.logback.classic.AsyncAppender"> <discardingThreshold>0</discardingThreshold> <queueSize>256</queueSize> <appender-ref ref="platform"/></appender>
工作原理:
当Logging Event进入AsyncAppender后,AsyncAppender会调用appender方法,append方法中在将event填入Buffer(这里选用的数据结构为BlockingQueue)中前,会先判断当前buffer的容量以及丢弃日志特性是否开启,当消费能力不如生产能力时,AsyncAppender会超出Buffer容量的Logging Event的级别,进行丢弃,作为消费速度一旦跟不上生产速度,中转buffer的溢出处理的一种方案。AsyncAppender有个线程类Worker,它是一个简单的线程类,是AsyncAppender的后台线程,所要做的工作是:从buffer中取出event交给对应的appender进行后面的日志推送。
从上面的描述中可以看出,AsyncAppender并不处理日志,只是将日志缓冲到一个BlockingQueue里面去,并在内部创建一个工作线程从队列头部获取日志,之后将获取的日志循环记录到附加的其他appender上去,从而达到不阻塞主线程的效果。因此AsynAppender仅仅充当事件转发器,必须引用另一个appender来做事。
在使用AsyncAppender的时候,有些选项还是要注意的。由于使用了BlockingQueue来缓存日志,因此就会出现队列满的情况。正如上面原理中所说的,在这种情况下,AsyncAppender会做出一些处理:默认情况下,如果队列80%已满,AsyncAppender将丢弃TRACE、DEBUG和INFO级别的event,从这点就可以看出,该策略有一个惊人的对event丢失的代价性能的影响。另外其他的一些选项信息,也会对性能产生影响。
参数:
queueSize:BlockingQueue的最大容量,默认情况下,大小为256。
discardingThreshold:默认情况下,当BlockingQueue还有20%容量,他将丢弃TRACE、DEBUG和INFO级别的event,只保留WARN和ERROR级别的event。为了保持所有的events,设置该值为0。
includeCallerData:提取调用者数据的代价是相当昂贵的。为了提升性能,默认情况下,当event被加入到queue时,event关联的调用者数据不会被提取。默认情况下,只有”cheap”的数据,如线程名。
logger与root
由于root也是loger元素,因此这两个可以一起总结。
< loger>
用来设置某一个包或者具体的某一个类的日志打印级别、以及指定。仅有一个name属性,一个可选的level和一个可选的addtivity属性。
name:
用来指定受此< loger>约束的某一个包或者具体的某一个类。
level:
用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。
如果未设置此属性,那么当前loger将会继承上级的级别。
addtivity:
是否向上级loger传递打印信息。默认是true。
loger可以包含零个或多个appender-ref元素,标识这个appender将会添加到这个loger。
< root>
也是< loger>元素,但是它是根loger。只有一个level属性,应为已经被命名为”root”.
level:
用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,不能设置为INHERITED或者同义词NULL。
默认是DEBUG。
< root>可以包含零个或多个< appender-ref>元素,标识这个appender将会添加到这个loger。
<logger name="myph.log.access" level="info" additivity="false"> <appender-ref ref="access.async"/> </logger> <logger name="myph.log.exception" level="info" additivity="false"> <appender-ref ref="error.async"/> </logger> <logger name="myph.log.system" level="info" additivity="false"> <appender-ref ref="system.async"/> </logger> <logger name="myph.log.debug" level="info" additivity="false"> <appender-ref ref="debug.async"/> </logger> <!--输入spring的error --> <logger name="com.myph" level="debug"/> <logger name="com.alibaba.dubbo" level="debug"/> <logger name="com.ibatis" level="debug"/> <logger name="org.springframework" level="debug"/> <logger name="com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate" level="debug"/> <logger name="org.apache.commons" level="debug"/> <logger name="catalia" level="debug"/> <logger name="org.apache" level="debug"/> <logger name="org.apache.shiro" level="debug"/> <logger name="com.ibatis.common.jdbc.SimpleDataSource" level="debug"/> <logger name="java.sql.ResultSet" level="debug"/> <logger name="com.ibatis.common.jdbc.ScriptRunner" level="debug"/> <logger name="java.sql.Connection" level="debug"/> <logger name="java.sql.PreparedStatement" level="debug"/> <!--定义root 级别 --> <root level="info"> <appender-ref ref="platform.async"/> <!--<!– 本地测试开始–>--> <appender-ref ref="STDOUT"/> </root>
如果是代码中手动打的debug,此断配置将生效
<logger name="myph.log.debug" level="info" additivity="false"> <appender-ref ref="debug.async"/></logger>
如果是引入的jar包中打的debug,此断配置将生效
<logger name="com.ibatis" level="debug"/>
由于此段没有指定appender-ref,因此将向上级传递到root中。
root中指定了appender-ref,将按照此appender-ref打印日志。
附上项目中打印日志的方法:
调用:
MyphLogger.error(e, "合规异常,入参{}", complianceDto.toString());
MyphLogger工具类:
package com.myph.common.log;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * INFO: info * User: zhaokai * Date: 2016/8/19 - 16:30 * Version: 1.0 * History: <p>如果有修改过程,请记录</P> */public class MyphLogger { private final static String AccessLoggerName = "myph.log.access"; private final static String ExceptionLoggerName = "myph.log.exception"; private final static String SystemLoggerName = "myph.log.system"; private final static String DebugLoggerName = "myph.log.debug"; private final static String OutInterfaceLoggerName = "myph.log.outInterface"; public static final String LOG_SEPARATOR = "|"; /** * sfl4j的logger */ private final static Logger accessLogger = LoggerFactory.getLogger(AccessLoggerName); private final static Logger exceptionLogger = LoggerFactory.getLogger(ExceptionLoggerName); private final static Logger systemLogger = LoggerFactory.getLogger(SystemLoggerName); private final static Logger debugLogger = LoggerFactory.getLogger(DebugLoggerName); private final static Logger outLogger = LoggerFactory.getLogger(OutInterfaceLoggerName); //----------------------------------------------------------- Logger method start /** * Debug等级日志,小于Info<br> * 由于动态获取Logger,效率较低,建议在非频繁调用的情况下使用!! * * @param message 输出消息 */ public static void debug(String message) { // 刷新参数 LogPropsReload.refreshLogProperties(); if (LogPropsReload.isDebugEnabled) { debugLogger.info(message); } } /** * Debug等级日志,小于Info<br> * 由于动态获取Logger,效率较低,建议在非频繁调用的情况下使用!! * * @param format 格式文本,{} 代表变量 * @param arguments 变量对应的参数 */ public static void debug(String format, Object... arguments) { LogPropsReload.refreshLogProperties(); if (LogPropsReload.isDebugEnabled) { debugLogger.info(format, arguments); } } /** * @param e * @param message */ public static void debug(Throwable e, String message) { LogPropsReload.refreshLogProperties(); if (LogPropsReload.isDebugEnabled) { debugLogger.info(message, e); } } /** * @param e * @param format 格式文本,{} 代表变量 * @param arguments */ public static void debug(Throwable e, String format, Object... arguments) { LogPropsReload.refreshLogProperties(); if (LogPropsReload.isDebugEnabled) { debugLogger.info(format(format, arguments), e); } } /** * @param message 输出消息 */ public static void access(String message) { LogPropsReload.refreshLogProperties(); if (LogPropsReload.isAccessEnabled) { accessLogger.info(message); } } /** * @param format 格式文本,{} 代表变量 * @param arguments 变量对应的参数 */ public static void access(String format, Object... arguments) { LogPropsReload.refreshLogProperties(); if (LogPropsReload.isAccessEnabled) { accessLogger.info(format, arguments); } } /** * @param message 输出消息 */ public static void outInterface(String message) { LogPropsReload.refreshLogProperties(); if (LogPropsReload.isInterfaceEnabled) { outLogger.info(message); } } /** * @param format 格式文本,{} 代表变量 * @param arguments 变量对应的参数 */ public static void outInterface(String format, Object... arguments) { LogPropsReload.refreshLogProperties(); if (LogPropsReload.isInterfaceEnabled) { outLogger.info(format, arguments); } } /** * @param message 输出消息 */ public static void info(String message) { LogPropsReload.refreshLogProperties(); if (LogPropsReload.isSystemEnabled) { systemLogger.info(message); } } /** * @param format 格式文本,{} 代表变量 * @param arguments 变量对应的参数 */ public static void info(String format, Object... arguments) { LogPropsReload.refreshLogProperties(); if (LogPropsReload.isSystemEnabled) { systemLogger.info(format, arguments); } } /** * @param e * @param message */ public static void info(Throwable e, String message) { LogPropsReload.refreshLogProperties(); if (LogPropsReload.isSystemEnabled) { systemLogger.info(message, e); } } /** * @param e * @param format 格式文本,{} 代表变量 * @param arguments */ public static void info(Throwable e, String format, Object... arguments) { LogPropsReload.refreshLogProperties(); if (LogPropsReload.isSystemEnabled) { systemLogger.info(format(format, arguments), e); } } /** * @param message 输出消息 */ public static void error(String message) { LogPropsReload.refreshLogProperties(); if (LogPropsReload.isExceptionEnabled) { exceptionLogger.info(message); } } /** * @param format 格式文本,{} 代表变量 * @param arguments 变量对应的参数 */ public static void error(String format, Object... arguments) { LogPropsReload.refreshLogProperties(); if (LogPropsReload.isExceptionEnabled) { exceptionLogger.info(format, arguments); } } /** * @param e * @param message */ public static void error(Throwable e, String message) { LogPropsReload.refreshLogProperties(); if (LogPropsReload.isExceptionEnabled) { exceptionLogger.info(message, e); } } /** * @param e * @param format 格式文本,{} 代表变量 * @param arguments */ public static void error(Throwable e, String format, Object... arguments) { LogPropsReload.refreshLogProperties(); if (LogPropsReload.isExceptionEnabled) { exceptionLogger.info(format(format, arguments), e); } }//----------------------------------------------------------- Private method start /** * 格式化文本 * * @param template 文本模板,被替换的部分用 {} 表示 * @param values 参数值 * @return 格式化后的文本 */ private static String format(String template, Object... values) { return String.format(template.replace("{}", "%s"), values); }}
LogPropsReload工具类
package com.myph.common.log;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.core.io.ClassPathResource;import java.io.IOException;import java.io.InputStream;import java.util.Date;import java.util.Properties;/** * INFO: info * User: zhaokai * Date: 2016/8/23 - 13:51 * Version: 1.0 * History: <p>如果有修改过程,请记录</P> */public class LogPropsReload { private static final Logger LOG = LoggerFactory.getLogger(LogPropsReload.class); /*@PostConstruct private void tt() { new Thread() { @Override public void run() { while (true) { try { refreshLogProperties(); Thread.sleep(5000); } catch (Exception e) { // 不允许停止监控 try { Thread.sleep(5000); } catch (InterruptedException e1) { // just ignore } LOG.error("LogThread error:" + e.getMessage()); } } } }.start(); }*/ private static final String LOG4J_HIDEPARAMS = "log4j.hideParams"; private static final String LOG4J_RELOAD_INTERVAL = "log4j.reload.interval"; private static final String LOG4J_DEBUGLOGGER_ISOPEN = "log4j.DebugLogger.isopen"; private static final String LOG4J_ACCESSLOGGER_ISOPEN = "log4j.AccessLogger.isopen"; private static final String LOG4J_OUTINTERFACELOGGER_ISOPEN = "log4j.OutInterfaceLogger.isopen"; private static final String LOG4J_EXCEPTIONLOGGER_ISOPEN = "log4j.ExceptionLogger.isopen"; private static final String LOG4J_SYSTEMLOGGER_ISOPEN = "log4j.SystemLogger.isopen"; //定义类变量初始化属性 // 刷新间隔 private static long interval = -1l; // 出入参隐藏 protected static boolean hideParams = true; /** * 上次修改时间 */ protected static Date lastUpdateDate = new Date(); // 调试日志开关 protected static boolean isDebugEnabled = false; // 访问日志开关 protected static boolean isAccessEnabled = false; // 外部访问日志开关 protected static boolean isInterfaceEnabled = false; // 异常日志开关 protected static boolean isExceptionEnabled = false; // 系统日志开关 protected static boolean isSystemEnabled = false; private static long default_interval = 60000L; /** * 本方法用于 当刷新log.properties日志获取最新参数出现异常情况下,默认赋予的运行配置参数 */ private static void initDefault() { // 刷新间隔 interval = default_interval; // 出入参隐藏 hideParams = true; lastUpdateDate = new Date(); // 调试日志开关 isDebugEnabled = false; // 访问日志开关 isAccessEnabled = false; // 外部访问日志开关 isInterfaceEnabled = false; // 异常日志开关 isExceptionEnabled = true; // 系统日志开关 isSystemEnabled = true; LOG.debug("LogThread fileid value is interval {},hideParams {},lastUpdateDate {},isDebugEnabled {}," + "isAccessEnabled {},isInterfaceEnabled {},isExceptionEnabled {},isSystemEnabled:{}", interval, hideParams, lastUpdateDate, isDebugEnabled, isAccessEnabled, isInterfaceEnabled, isExceptionEnabled, isSystemEnabled); } /** * @author jun.wang * @Description: 整点刷新 * @date 2014-9-16 上午11:28:25 */ public static void refreshLogProperties() { LOG.debug("new Date().getTime():{} - lastUpdateDate.getTime():{} to:{} > interval:{}", new Date().getTime(), lastUpdateDate.getTime(), new Date().getTime() - lastUpdateDate.getTime(), interval); // 间隔时间 if (new Date().getTime() - lastUpdateDate.getTime() > interval) { ClassPathResource config = new ClassPathResource("/config/log.properties"); if (!config.exists()) { LOG.error("日志刷新服务异常,配置文件log.properties不存在,将使用默认配置"); initDefault(); } else { Properties pros = new Properties(); InputStream in = null; try { in = config.getInputStream(); pros.load(in); } catch (IOException ex) { LOG.error("日志刷新服务异常,配置文件log.properties不存在"); initDefault(); } finally { if (null != in) { try { in.close(); } catch (IOException e) { LOG.error("日志刷新服务异常,配置文件log.properties不存在"); initDefault(); } } } // 重新加载时间间隔 interval = Long.parseLong(pros.getProperty(LOG4J_RELOAD_INTERVAL)); // 参数 hideParams = Boolean.parseBoolean(pros.getProperty(LOG4J_HIDEPARAMS)); // 调试日志开关 try { isDebugEnabled = Boolean.parseBoolean(pros.getProperty(LOG4J_DEBUGLOGGER_ISOPEN)); } catch (Exception e) { LOG.error("日志刷新服务异常,配置文件log.properties格式错误:{}", LOG4J_DEBUGLOGGER_ISOPEN); } // 访问日志开关 try { isAccessEnabled = Boolean.parseBoolean(pros.getProperty(LOG4J_ACCESSLOGGER_ISOPEN)); } catch (Exception e) { LOG.error("日志刷新服务异常,配置文件log.properties格式错误:{}", LOG4J_ACCESSLOGGER_ISOPEN); } // 接口日志 try { isInterfaceEnabled = Boolean.parseBoolean(pros.getProperty(LOG4J_OUTINTERFACELOGGER_ISOPEN)); } catch (Exception e) { LOG.error("日志刷新服务异常,配置文件log.properties格式错误:{}", LOG4J_OUTINTERFACELOGGER_ISOPEN); } // 异常日志 try { isExceptionEnabled = Boolean.parseBoolean(pros.getProperty(LOG4J_EXCEPTIONLOGGER_ISOPEN)); } catch (Exception e) { LOG.error("日志刷新服务异常,配置文件log.properties格式错误:{}", LOG4J_EXCEPTIONLOGGER_ISOPEN); } // 系统日志 try { isSystemEnabled = Boolean.parseBoolean(pros.getProperty(LOG4J_SYSTEMLOGGER_ISOPEN)); } catch (Exception e) { LOG.error("日志刷新服务异常,配置文件log.properties格式错误:{}", LOG4J_SYSTEMLOGGER_ISOPEN); } // 更新时间 lastUpdateDate = new Date(); config = null; LOG.debug("LogThread fileid value is interval {},hideParams {},lastUpdateDate {},isDebugEnabled {}," + "isAccessEnabled {},isInterfaceEnabled {},isExceptionEnabled {},isSystemEnabled:{}", interval, hideParams, lastUpdateDate, isDebugEnabled, isAccessEnabled, isInterfaceEnabled, isExceptionEnabled, isSystemEnabled); } } }}
- logback使用与解析
- logback配置与使用
- logback学习与使用(一)
- logback学习与使用(二)
- logback学习与使用(三)
- logback学习与使用(四)
- logback学习与配置使用
- logback学习与配置使用
- Logback使用以及与log4j区别
- logback与Spring、SpringMVC结合使用教程
- logback与Spring、SpringMVC结合使用教程
- Log4j 与 logback对比、及使用配置
- logback与Spring、SpringMVC结合使用教程
- logback与Spring、SpringMVC结合使用教程
- logback与Spring、SpringMVC结合使用教程
- Log4j 与 logback对比、及使用配置
- logback与Spring、SpringMVC结合使用教程
- 使用logback
- 第六届蓝桥杯【省赛试题9】垒骰子 ( 矩阵快速幂 )
- Redis学习之构建数据服务详解
- Linux模块编程框架
- Linux Make 命令
- 《linux多线程服务端编程muduo网络库的使用》读后感
- logback使用与解析
- 最长回文数2
- Gradle 1.12用户指南翻译——第五十章. 依赖管理
- OpenCV for Python [2]使用Matplotlib显示图片
- aptana---学习HTML
- 第十五周 oj训练 字符串处理new
- 亲测 logminer挖掘
- 在项目中使用spring-framework-bom统一管理jar包版本
- Java并发编程:Thread类的使用