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来访问日志的功能。
关系图:
jar包间的关系

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"/>        <!--&lt;!&ndash; 本地测试开始&ndash;&gt;-->        <appender-ref ref="STDOUT"/>    </root></configuration>

logback.xml文件结构

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结构
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"/>        <!--&lt;!&ndash; 本地测试开始&ndash;&gt;-->        <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);            }        }    }}
0 0
原创粉丝点击