logback使用与解析

本文详细介绍了logback的使用,包括maven依赖、jar包关系、web.xml配置以及logback.xml的解析,重点关注了配置文件中的configuration、property、appender(ConsoleAppender、RollingFileAppender、AsyncAppender)、logger与root的设置,提供了丰富的配置示例和工作原理说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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);
            }
        }
    }


}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值