龙空技术网

自定义 log4j2 过滤器,并把日志输出到指定文件

睿智的搞笑图集 272

前言:

此时姐妹们对“怎样让java输出日志内容”大体比较关心,我们都需要分析一些“怎样让java输出日志内容”的相关文章。那么小编在网上汇集了一些关于“怎样让java输出日志内容””的相关文章,希望你们能喜欢,同学们快快来学习一下吧!

因为需要在已有的某一个级别的日志中需要过滤排除某一些指定类的日志,所有用到了log4j 的自定义日志过滤器。

原始 日志内容 :

<?xml version="1.0" encoding="UTF-8"?><!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL --><!-- status : 这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,会看到log4j2内部各种详细输出 ,默认OFF	 monitorInterval : Log4j能够自动检测修改配置文件和重新配置本身, 设置间隔秒数。 单位是s,最小是5s.	 %d{yyyy-MM-dd HH:mm:ss, SSS} : 日志生产时间      %p : 日志输出格式      %c : logger的名称       %m : 日志内容,即 logger.info("message")      %n : 换行符      %C : Java类名      %L : 日志输出所在行数      %M : 日志输出所在方法名      hostName : 本地机器名 hostAddress : 本地ip地址 --><configuration status="debug" monitorInterval="1">	<properties>		<!-- 配置日志文件输出目录 -->		<property name="LOG_HOME">/utle/zhelidu/log4j</property>		<!-- 日志备份目录 -->		<property name="BACKUP_HOME">backup</property>		<!-- 日志备份文件的后缀 -->		<property name="BACKUP_FILE_NAME_SUFFIX"></property>		<!-- 日志名称, 这里-i  -->		<property name="SERVER_NAME">zhelidu</property>		<!-- 日志切割的最小单位 -->		<property name="EVERY_FILE_SIZE">50M</property>		<!-- 日志输出级别 -->		<property name="OUTPUT_LOG_LEVEL">DEBUG</property>		<!-- 日志输出格式 -->		<property name="PATTERN">%date{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %level [%C{36}.%M] - %msg%n</property>		<!-- logger输出的日志级别 -->		<property name="LOGGER_LEVEL">DEBUG</property>		<!-- 备份文件夹名称夹 -->		<property name="BACK_FOLDER">%d{yyyyMMdd}</property>		<!--<property name="BACK_FOLDER">%d{yyyyMMddHH}</property>-->		<!-- 保留相同的日志文件的个数 -->		<property name="MAX">20</property>		<!-- 要访问的目录的最大级别数。值为0表示仅访问起始文件(基本路径本身),除非被安全管理者拒绝。			Integer.MAX_VALUE的值表示应该访问所有级别。默认为1,意思是指定基本目录中的文件。 -->		<property name="MAXDEPTH">5</property>		<!-- 多长时间异常的日志需要删除掉 10天以上的 -->		<property name="AGE">30d</property>		<!-- 多长时间异常的日志需要删除掉,每天0点跑一次 -->		<property name="SCHEDULE">0 0 0 * * ?</property>	</properties>		<appenders>		<!--这个输出控制台的配置 -->		<Console name="Console" target="SYSTEM_OUT" follow="true">			<!-- 输出日志的格式 -->			<PatternLayout pattern="${PATTERN}" />		</Console>		<!-- 只显示error级别的信息 -->		<RollingFile name="RollingFileError"					 fileName="${LOG_HOME}/${SERVER_NAME}_error.log"					 filePattern="${LOG_HOME}/${BACKUP_HOME}/error/${BACK_FOLDER}/${SERVER_NAME}_error-%i.log${BACKUP_FILE_NAME_SUFFIX}">			<PatternLayout pattern="${PATTERN}" />			<Policies>				<SizeBasedTriggeringPolicy size="${EVERY_FILE_SIZE}" />				<TimeBasedTriggeringPolicy interval="1" modulate="true" />			</Policies>			<Filters>				<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY" />			</Filters>			<CronTriggeringPolicy schedule="${SCHEDULE}"/>			<DefaultRolloverStrategy max="${MAX}">				<Delete basePath="${LOG_HOME}" maxDepth="${MAXDEPTH}">					<IfFileName glob="${BACKUP_HOME}/error/*/*.log*" />					<IfLastModified age="${AGE}" />				</Delete>			</DefaultRolloverStrategy>		</RollingFile>		<!-- 只显示warn级别的信息 后缀 suffix -->		<RollingFile name="RollingFileWarn"					 fileName="${LOG_HOME}/${SERVER_NAME}_warn.log"					 filePattern="${LOG_HOME}/${BACKUP_HOME}/warn/${BACK_FOLDER}/${SERVER_NAME}_warn-%i.log${BACKUP_FILE_NAME_SUFFIX}">			<PatternLayout pattern="${PATTERN}" />			<Policies>				<SizeBasedTriggeringPolicy size="${EVERY_FILE_SIZE}" />				<TimeBasedTriggeringPolicy interval="1" modulate="true" />			</Policies>			<Filters>				<!--				 使用自定义过滤器,过滤掉 指定类的 日志				 -->				<ThresholdFilter level="error" onMatch="DENY" onMismatch="NEUTRAL" />				<ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>			</Filters>			<CronTriggeringPolicy schedule="${SCHEDULE}"/>			<DefaultRolloverStrategy max="${MAX}">				<Delete basePath="${LOG_HOME}" maxDepth="${MAXDEPTH}">					<IfFileName glob="${BACKUP_HOME}/warn/*/*.log*" />					<IfLastModified age="${AGE}" />				</Delete>			</DefaultRolloverStrategy>		</RollingFile>		<!-- 只显示info级别的信息 -->		<RollingFile name="RollingFileInfo"					 fileName="${LOG_HOME}/${SERVER_NAME}_info.log"					 filePattern="${LOG_HOME}/${BACKUP_HOME}/info/${BACK_FOLDER}/${SERVER_NAME}_info-%i.log${BACKUP_FILE_NAME_SUFFIX}">			<PatternLayout pattern="${PATTERN}" />			<Policies>				<SizeBasedTriggeringPolicy size="${EVERY_FILE_SIZE}" />				<TimeBasedTriggeringPolicy interval="1"  modulate="true"  />			</Policies>			<Filters>				<!--				 使用自定义过滤器,过滤掉 指定类的 日志				 -->				<ThresholdFilter level="warn" onMatch="DENY" onMismatch="NEUTRAL" />				<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>			</Filters>			<CronTriggeringPolicy schedule="${SCHEDULE}"/>			<DefaultRolloverStrategy max="${MAX}">				<Delete basePath="${LOG_HOME}" maxDepth="${MAXDEPTH}">					<IfFileName glob="${BACKUP_HOME}/info/*/*.log*" />					<IfLastModified age="${AGE}" />				</Delete>			</DefaultRolloverStrategy>		</RollingFile>		<!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->		<!-- 重要的是,如果有多个ThresholdFilter,那么Filters是必须的,同时在Filters中,首先要过滤不符合的日志级别,把不需要的首先DENY掉,然后再ACCEPT需要的日志级别,这个次序不能搞颠倒。 -->		<RollingFile name="RollingFile"			fileName="${LOG_HOME}/${SERVER_NAME}.log"			filePattern="${LOG_HOME}/${BACKUP_HOME}/debug/${BACK_FOLDER}/${SERVER_NAME}-%i.log${BACKUP_FILE_NAME_SUFFIX}">			<PatternLayout pattern="${PATTERN}" />			<Policies>                <SizeBasedTriggeringPolicy size="${EVERY_FILE_SIZE}" />                <TimeBasedTriggeringPolicy interval="1" modulate="true" />            </Policies>			<Filters>				<ThresholdFilter level="info" onMatch="DENY" onMismatch="NEUTRAL" />				<ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY" />			</Filters>			<CronTriggeringPolicy schedule="${SCHEDULE}"/>			<DefaultRolloverStrategy max="${MAX}">				<Delete basePath="${LOG_HOME}" maxDepth="${MAXDEPTH}">					<IfFileName glob="${BACKUP_HOME}/debug/*/*.log*" />					<IfLastModified age="${AGE}" />				</Delete>			</DefaultRolloverStrategy>		</RollingFile>	</appenders>	<!--然后定义logger,只有定义了logger并引入的appender,appender才会生效 -->	<loggers>        <!-- 减少部分debug日志 -->        <logger name="org.apache.shiro" level="INFO"/>        <logger name="org.springframework" level="INFO"/>        <logger name="org.springframework.context" level="INFO"/>        <logger name="org.springframework.beans" level="INFO"/>        <logger name="com.baomidou.mybatisplus" level="INFO"/>        <logger name="org.apache.ibatis.io" level="INFO"/>        <logger name="org.apache.http" level="INFO"/>        <logger name="io.lettuce" level="INFO"/>        <logger name="com.alibaba.druid" level="INFO"/>        <logger name="org.mybatis.logging.Logger.debug" level="INFO"/>        <logger name="org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug" level="DEBUG"/>        <logger name="org.redisson.connection" level="INFO"/>        <logger name="springfox.documentation" level="WARN"/>        <!-- 业务debug日志 -->        <logger name="com.forhome.babyshop" level="${OUTPUT_LOG_LEVEL}" additivity="true"/>        <!-- 配置日志的根节点,建立一个默认的root的logger,需要在root的level中指定输出的级别  -->		<Root level="DEBUG">			<appender-ref ref="Console" />			<appender-ref ref="RollingFileError" />			<appender-ref ref="RollingFileWarn" />			<appender-ref ref="RollingFileInfo" />			<appender-ref ref="RollingFile" />		</Root >	</loggers></configuration>

该日志配置会输出 文件目录格式 :

log4j ├── backup │   ├── debug │   │   └── 20210603 │   │       └── zhelidu-1.log │   ├── error │   │   └── 20210603 │   │       └── zhelidu_error-1.log │   ├── info │   │   └── 20210603 │   │       └── zhelidu_info-1.log │   └── warn │       └── 20210603 │           └── zhelidu_warn-1.log ├── zhelidu.log ├── zhelidu_error.log ├── zhelidu_info.log └── zhelidu_warn.log

其中 backup 下为 备份日志,其他几个文件分别是对应的级别的日志,

现在我的业务场景中有个类 中会频繁调用,同时会输出 info 日志, 这个时候我需要把该类中的日志提取出来,放在单独的文件,于是我增加如下配置

<appenders> 节点下增加 RollingFile<RollingFile name="RollingFileDaHanRequest"			 fileName="${LOG_HOME}/${SERVER_NAME}_dahan.log"			 filePattern="${LOG_HOME}/${BACKUP_HOME}/dahan/${BACK_FOLDER}/${SERVER_NAME}_dahan-%i.log${BACKUP_FILE_NAME_SUFFIX}">	<PatternLayout pattern="${PATTERN}" />	<Policies>		<SizeBasedTriggeringPolicy size="${EVERY_FILE_SIZE}" />		<TimeBasedTriggeringPolicy interval="1" modulate="true" />	</Policies>	<Filters>		<!--<ThresholdFilter level="info" onMatch="DENY" onMismatch="NEUTRAL" />-->		<ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY" />	</Filters>	<CronTriggeringPolicy schedule="${SCHEDULE}"/>	<DefaultRolloverStrategy max="${MAX}">		<Delete basePath="${LOG_HOME}" maxDepth="${MAXDEPTH}">			<IfFileName glob="${BACKUP_HOME}/dahan/*/*.log*" />			<IfLastModified age="${AGE}" />		</Delete>	</DefaultRolloverStrategy></RollingFile><loggers> 节点下增加 <!-- 大汉请求 业务日志 --><logger name="com.zhijia.common.framework.dahan.DaHanGet" level="DEBUG" additivity="true">	<appender-ref ref="RollingFileDaHanRequest" /></logger>

再次测试后 ,目录结构变为 : 可以看到 增加了 zhelidu_dahan.log 相关的日志文件,

log4j ├── backup │   ├── debug │   │   └── 20210603 │   │       └── zhelidu-1.log │   ├── error │   │   └── 20210603 │   │       └── zhelidu_error-1.log │   ├── info │   │   └── 20210603 │   │       └── zhelidu_info-1.log │   └── warn │       └── 20210603 │           └── zhelidu_warn-1.log ├── zhelidu.log ├── zhelidu_dahan.log ├── zhelidu_error.log ├── zhelidu_info.log └── zhelidu_warn.log

但是有个问题, zhelidu_dahan,log 文件中的日志在 zhelidu_info.log 中 也会输出一遍,这会导致内容重复输出。而且因为量大的问题,导致查看日志不好查看,且浪费存储空间

于是需要从 zhelidu_info.log 中排除调 zhelidu_dahan,log 中的日志,

分析 zhelidu_dahan.log 的日志, 可以看到该日志中都是有 下面的类输出

com.zhijia.common.framework.dahan.DaHanGet

我们只要排除该类输出的文件即可,继续看如下 *_info的配置,

<!-- 只显示info级别的信息 --><RollingFile name="RollingFileInfo"             fileName="${LOG_HOME}/${SERVER_NAME}_info.log"             filePattern="${LOG_HOME}/${BACKUP_HOME}/info/${BACK_FOLDER}/${SERVER_NAME}_info-%i.log${BACKUP_FILE_NAME_SUFFIX}">    <PatternLayout pattern="${PATTERN}" />    <Policies>        <SizeBasedTriggeringPolicy size="${EVERY_FILE_SIZE}" />        <TimeBasedTriggeringPolicy interval="1"  modulate="true"  />    </Policies>    <Filters>        <ThresholdFilter level="warn" onMatch="DENY" onMismatch="NEUTRAL" />        <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>    </Filters>    <CronTriggeringPolicy schedule="${SCHEDULE}"/>    <DefaultRolloverStrategy max="${MAX}">        <Delete basePath="${LOG_HOME}" maxDepth="${MAXDEPTH}">            <IfFileName glob="${BACKUP_HOME}/info/*/*.log*" />            <IfLastModified age="${AGE}" />        </Delete>    </DefaultRolloverStrategy></RollingFile>

其中有一个 节点 <Filters> 是一个日志过滤器, 通过查看源码得知 <Filters>里面可以存放组合过滤器,里面定义了一些常用的过滤器。

可以看到很多个过滤器,具体各个filter的说明可以查看该文章

开始我将 使用 RegexFilter ,但是该类只能使用正则匹配 输出的自定义内容,不能直接只能类,除非将类名写到输出内容中,但是这样不太优雅 。

最后决定参考该 filter 自定义一个filter , 使用该filter 过滤指定的类

自定义FIlter 的代码如下 :

package com.zhijia.framework.log;import org.apache.logging.log4j.Level;import org.apache.logging.log4j.Marker;import org.apache.logging.log4j.core.Filter;import org.apache.logging.log4j.core.LogEvent;import org.apache.logging.log4j.core.Logger;import org.apache.logging.log4j.core.config.Node;import org.apache.logging.log4j.core.config.plugins.Plugin;import org.apache.logging.log4j.core.config.plugins.PluginAttribute;import org.apache.logging.log4j.core.config.plugins.PluginElement;import org.apache.logging.log4j.core.config.plugins.PluginFactory;import org.apache.logging.log4j.core.filter.AbstractFilter;import org.apache.logging.log4j.message.Message;import java.lang.reflect.Field;import java.util.Arrays;import java.util.Comparator;import java.util.regex.Matcher;import java.util.regex.Pattern;/** * 自定义 日志过滤器 */@Plugin(name = "CustomClassFilter", category = Node.CATEGORY, elementType = Filter.ELEMENT_TYPE, printObject = true)public final class CustomClassFilter extends AbstractFilter {    private static final int DEFAULT_PATTERN_FLAGS = 0;    private final Pattern pattern;    private final boolean useRawMessage;    private final boolean isEq; // 是否完全匹配    private CustomClassFilter(final boolean raw, final Pattern pattern, final boolean isEq, final Result onMatch, final Result onMismatch) {        super(onMatch, onMismatch);        this.pattern = pattern;        this.isEq = isEq;        this.useRawMessage = raw;    }    @Override    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,                         final Object... params) {        return filter(msg);    }    @Override    public Result filter(final Logger logger, final Level level, final Marker marker, final Object msg,                         final Throwable t) {        if (msg == null) {            return onMismatch;        }        return filter(msg.toString());    }    @Override    public Result filter(final Logger logger, final Level level, final Marker marker, final Message msg,                         final Throwable t) {        if (msg == null) {            return onMismatch;        }        final String text = useRawMessage ? msg.getFormat() : msg.getFormattedMessage();        return filter(text);    }    @Override    public Result filter(final LogEvent event) {        final String text = useRawMessage ? event.getMessage().getFormat() : event.getLoggerName();        return filter(text);    }    private Result filter(final String msg) {        if (msg == null) {            return onMismatch;        }        if (isEq){            return pattern.pattern().equals(msg)? onMatch : onMismatch ;        }        final Matcher m = pattern.matcher(msg);        return m.matches() ? onMatch : onMismatch;    }    @Override    public String toString() {        final StringBuilder sb = new StringBuilder();        sb.append("useRaw=").append(useRawMessage);        sb.append(", pattern=").append(pattern!=null?pattern.toString():"");        return sb.toString();    }    /**     * Creates a Filter that matches a regular expression.     *     * @param regex     *        The regular expression to match.     * @param patternFlags     *        An array of Stirngs where each String is a {@link Pattern#compile(String, int)} compilation flag.     * @param useRawMsg     *        If true, the raw message will be used, otherwise the formatted message will be used.     * @param match     *        The action to perform when a match occurs.     * @param mismatch     *        The action to perform when a mismatch occurs.     * @return The RegexFilter.     * @throws IllegalAccessException     * @throws IllegalArgumentException     */    // TODO Consider refactoring to use AbstractFilter.AbstractFilterBuilder    @PluginFactory    public static CustomClassFilter createFilter(            //@formatter:off            @PluginAttribute("regex") final String regex,            @PluginAttribute("isEq") final Boolean isEq,            @PluginElement("PatternFlags") final String[] patternFlags,            @PluginAttribute("useRawMsg") final Boolean useRawMsg,            @PluginAttribute("onMatch") final Result match,            @PluginAttribute("onMismatch") final Result mismatch)    //@formatter:on            throws IllegalArgumentException, IllegalAccessException {        if (regex == null) {            LOGGER.error("A regular expression must be provided for RegexFilter");            return null;        }        return new CustomClassFilter(useRawMsg, Pattern.compile(regex, toPatternFlags(patternFlags)),isEq, match, mismatch);    }    private static int toPatternFlags(final String[] patternFlags) throws IllegalArgumentException,            IllegalAccessException {        if (patternFlags == null || patternFlags.length == 0) {            return DEFAULT_PATTERN_FLAGS;        }        final Field[] fields = Pattern.class.getDeclaredFields();        final Comparator<Field> comparator = new Comparator<Field>() {            @Override            public int compare(final Field f1, final Field f2) {                return f1.getName().compareTo(f2.getName());            }        };        Arrays.sort(fields, comparator);        final String[] fieldNames = new String[fields.length];        for (int i = 0; i < fields.length; i++) {            fieldNames[i] = fields[i].getName();        }        int flags = DEFAULT_PATTERN_FLAGS;        for (final String test : patternFlags) {            final int index = Arrays.binarySearch(fieldNames, test);            if (index >= 0) {                final Field field = fields[index];                flags |= field.getInt(Pattern.class);            }        }        return flags;    }}

其中需要代码 是 如下这段 , event.getLoggerName() 为获取到的类名

@Overridepublic Result filter(final LogEvent event) {    final String text = useRawMessage ? event.getMessage().getFormat() : event.getLoggerName();    return filter(text);}    private Result filter(final String msg) {    if (msg == null) {        return onMismatch;    }    if (isEq){        return pattern.pattern().equals(msg)? onMatch : onMismatch ;    }    final Matcher m = pattern.matcher(msg);    return m.matches() ? onMatch : onMismatch;}   

重新修改 xml 中 info 的配置

<!-- 只显示info级别的信息 --><RollingFile name="RollingFileInfo"             fileName="${LOG_HOME}/${SERVER_NAME}_info.log"             filePattern="${LOG_HOME}/${BACKUP_HOME}/info/${BACK_FOLDER}/${SERVER_NAME}_info-%i.log${BACKUP_FILE_NAME_SUFFIX}">    <PatternLayout pattern="${PATTERN}" />    <Policies>        <SizeBasedTriggeringPolicy size="${EVERY_FILE_SIZE}" />        <TimeBasedTriggeringPolicy interval="1"  modulate="true"  />    </Policies>    <Filters>        <!--         使用自定义过滤器,过滤掉 指定类的 日志         -->        <CustomClassFilter regex="com.zhijia.common.framework.dahan.DaHanGet"  isEq = "true"  onMatch="DENY" onMismatch="NEUTRAL"/>        <CustomClassFilter regex="com.zhijia.common.framework.health.HealthGet"  isEq = "true"  onMatch="DENY" onMismatch="NEUTRAL"/>        <ThresholdFilter level="warn" onMatch="DENY" onMismatch="NEUTRAL" />        <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>    </Filters>    <CronTriggeringPolicy schedule="${SCHEDULE}"/>    <DefaultRolloverStrategy max="${MAX}">        <Delete basePath="${LOG_HOME}" maxDepth="${MAXDEPTH}">            <IfFileName glob="${BACKUP_HOME}/info/*/*.log*" />            <IfLastModified age="${AGE}" />        </Delete>    </DefaultRolloverStrategy></RollingFile>

增加如下两行

        <CustomClassFilter regex="com.zhijia.common.framework.dahan.DaHanGet"  isEq = "true"  onMatch="DENY" onMismatch="NEUTRAL"/>        <CustomClassFilter regex="com.zhijia.common.framework.health.HealthGet"  isEq = "true"  onMatch="DENY" onMismatch="NEUTRAL"/>

至此全部完成, 结尾放上 完整的log4j2.xml 的配置内容

注意 :

需要说明的是onMatch和onMismatch可以选择的值及其含义。

onMatch : 当条件匹配时;

onMismatch : 当条件不匹配时;

可选的值分别是,ACCEPT, DENY, NEUTRAL,ACCEP和DENY比较好理解就是接受和拒绝的意思,在使用单个过滤器的时候,一般就是使用这两个值。

但是在组合过滤器中,如果用接受ACCEPT的话,日志信息就会直接写入日志文件,后续的过滤器不再进行过滤。--- 有点像switch case break; 直接截断了 不会往下判断了。

在组合过滤器中,接受使用NEUTRAL(中立),被第一个过滤器接受的日志信息,会继续用后面的过滤器进行过滤,只有符合所有过滤器条件的日志信息,才会被最终写入日志文件。 --- 也就是层层过滤的意思,要都满足条件才能写入日志

可以从 源码中看到 :

位置 org.apache.logging.log4j.core.filter.CompositeFilter#filter(org.apache.logging.log4j.core.LogEvent)

@Override

public Result filter(final LogEvent event) {

Result result = Result.NEUTRAL;

for (int i = 0; i < filters.length; i++) {

result = filters[i].filter(event);

if (result == Result.ACCEPT || result == Result.DENY) {

return result;

}

}

return result;

}

其中 : filters 就是 组合过滤器, 可以看到 这行

result == Result.ACCEPT || result == Result.DENY 当某个过滤返回的结果为 ACCEPT ,

或者 DENY 直接结束循环, 只有 在 NEUTRAL 的时候才会继续走下一个过滤器

以下为完整的配置文件内容 :

<?xml version="1.0" encoding="UTF-8"?><!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL --><!-- status : 这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,会看到log4j2内部各种详细输出 ,默认OFF	 monitorInterval : Log4j能够自动检测修改配置文件和重新配置本身, 设置间隔秒数。 单位是s,最小是5s.	 %d{yyyy-MM-dd HH:mm:ss, SSS} : 日志生产时间      %p : 日志输出格式      %c : logger的名称       %m : 日志内容,即 logger.info("message")      %n : 换行符      %C : Java类名      %L : 日志输出所在行数      %M : 日志输出所在方法名      hostName : 本地机器名 hostAddress : 本地ip地址 --><configuration status="debug" monitorInterval="1">	<properties>		<!-- 配置日志文件输出目录 -->		<property name="LOG_HOME">/utle/zhelidu/log4j</property>		<!-- 日志备份目录 -->		<property name="BACKUP_HOME">backup</property>		<!-- 日志备份文件的后缀 -->		<property name="BACKUP_FILE_NAME_SUFFIX"></property>		<!-- 日志名称, 这里-i  -->		<property name="SERVER_NAME">zhelidu</property>		<!-- 日志切割的最小单位 -->		<property name="EVERY_FILE_SIZE">50M</property>		<!-- 日志输出级别 -->		<property name="OUTPUT_LOG_LEVEL">DEBUG</property>		<!-- 日志输出格式 -->		<property name="PATTERN">%date{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %level [%C{36}.%M] - %msg%n</property>		<!-- logger输出的日志级别 -->		<property name="LOGGER_LEVEL">DEBUG</property>		<!-- 备份文件夹名称夹 -->		<property name="BACK_FOLDER">%d{yyyyMMdd}</property>		<!--<property name="BACK_FOLDER">%d{yyyyMMddHH}</property>-->		<!-- 保留相同的日志文件的个数 -->		<property name="MAX">20</property>		<!-- 要访问的目录的最大级别数。值为0表示仅访问起始文件(基本路径本身),除非被安全管理者拒绝。			Integer.MAX_VALUE的值表示应该访问所有级别。默认为1,意思是指定基本目录中的文件。 -->		<property name="MAXDEPTH">5</property>		<!-- 多长时间异常的日志需要删除掉 10天以上的 -->		<property name="AGE">30d</property>		<!-- 多长时间异常的日志需要删除掉,每天0点跑一次 -->		<property name="SCHEDULE">0 0 0 * * ?</property>	</properties>		<appenders>		<!--这个输出控制台的配置 -->		<Console name="Console" target="SYSTEM_OUT" follow="true">			<!-- 输出日志的格式 -->			<PatternLayout pattern="${PATTERN}" />		</Console>		<!-- 只显示error级别的信息 -->		<RollingFile name="RollingFileError"					 fileName="${LOG_HOME}/${SERVER_NAME}_error.log"					 filePattern="${LOG_HOME}/${BACKUP_HOME}/error/${BACK_FOLDER}/${SERVER_NAME}_error-%i.log${BACKUP_FILE_NAME_SUFFIX}">			<PatternLayout pattern="${PATTERN}" />			<Policies>				<SizeBasedTriggeringPolicy size="${EVERY_FILE_SIZE}" />				<TimeBasedTriggeringPolicy interval="1" modulate="true" />			</Policies>			<Filters>				<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY" />			</Filters>			<CronTriggeringPolicy schedule="${SCHEDULE}"/>			<DefaultRolloverStrategy max="${MAX}">				<Delete basePath="${LOG_HOME}" maxDepth="${MAXDEPTH}">					<IfFileName glob="${BACKUP_HOME}/error/*/*.log*" />					<IfLastModified age="${AGE}" />				</Delete>			</DefaultRolloverStrategy>		</RollingFile>		<!-- 只显示warn级别的信息 后缀 suffix -->		<RollingFile name="RollingFileWarn"					 fileName="${LOG_HOME}/${SERVER_NAME}_warn.log"					 filePattern="${LOG_HOME}/${BACKUP_HOME}/warn/${BACK_FOLDER}/${SERVER_NAME}_warn-%i.log${BACKUP_FILE_NAME_SUFFIX}">			<PatternLayout pattern="${PATTERN}" />			<Policies>				<SizeBasedTriggeringPolicy size="${EVERY_FILE_SIZE}" />				<TimeBasedTriggeringPolicy interval="1" modulate="true" />			</Policies>			<Filters>				<!--				 使用自定义过滤器,过滤掉 指定类的 日志				 -->				<CustomClassFilter regex="com.zhijia.common.framework.dahan.DaHanGet"  isEq = "true"  onMatch="DENY" onMismatch="NEUTRAL"/>				<CustomClassFilter regex="com.zhijia.common.framework.health.HealthGet"  isEq = "true"  onMatch="DENY" onMismatch="NEUTRAL"/>				<ThresholdFilter level="error" onMatch="DENY" onMismatch="NEUTRAL" />				<ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>			</Filters>			<CronTriggeringPolicy schedule="${SCHEDULE}"/>			<DefaultRolloverStrategy max="${MAX}">				<Delete basePath="${LOG_HOME}" maxDepth="${MAXDEPTH}">					<IfFileName glob="${BACKUP_HOME}/warn/*/*.log*" />					<IfLastModified age="${AGE}" />				</Delete>			</DefaultRolloverStrategy>		</RollingFile>		<!-- 只显示info级别的信息 -->		<RollingFile name="RollingFileInfo"					 fileName="${LOG_HOME}/${SERVER_NAME}_info.log"					 filePattern="${LOG_HOME}/${BACKUP_HOME}/info/${BACK_FOLDER}/${SERVER_NAME}_info-%i.log${BACKUP_FILE_NAME_SUFFIX}">			<PatternLayout pattern="${PATTERN}" />			<Policies>				<SizeBasedTriggeringPolicy size="${EVERY_FILE_SIZE}" />				<TimeBasedTriggeringPolicy interval="1"  modulate="true"  />			</Policies>			<Filters>				<!--				 使用自定义过滤器,过滤掉 指定类的 日志				 -->				<CustomClassFilter regex="com.zhijia.common.framework.dahan.DaHanGet"  isEq = "true"  onMatch="DENY" onMismatch="NEUTRAL"/>				<CustomClassFilter regex="com.zhijia.common.framework.health.HealthGet"  isEq = "true"  onMatch="DENY" onMismatch="NEUTRAL"/>				<ThresholdFilter level="warn" onMatch="DENY" onMismatch="NEUTRAL" />				<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>			</Filters>			<CronTriggeringPolicy schedule="${SCHEDULE}"/>			<DefaultRolloverStrategy max="${MAX}">				<Delete basePath="${LOG_HOME}" maxDepth="${MAXDEPTH}">					<IfFileName glob="${BACKUP_HOME}/info/*/*.log*" />					<IfLastModified age="${AGE}" />				</Delete>			</DefaultRolloverStrategy>		</RollingFile>		<!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->		<!-- 重要的是,如果有多个ThresholdFilter,那么Filters是必须的,同时在Filters中,首先要过滤不符合的日志级别,把不需要的首先DENY掉,然后再ACCEPT需要的日志级别,这个次序不能搞颠倒。 -->		<RollingFile name="RollingFile"			fileName="${LOG_HOME}/${SERVER_NAME}.log"			filePattern="${LOG_HOME}/${BACKUP_HOME}/debug/${BACK_FOLDER}/${SERVER_NAME}-%i.log${BACKUP_FILE_NAME_SUFFIX}">			<PatternLayout pattern="${PATTERN}" />			<Policies>                <SizeBasedTriggeringPolicy size="${EVERY_FILE_SIZE}" />                <TimeBasedTriggeringPolicy interval="1" modulate="true" />            </Policies>			<Filters>				<ThresholdFilter level="info" onMatch="DENY" onMismatch="NEUTRAL" />				<ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY" />			</Filters>			<CronTriggeringPolicy schedule="${SCHEDULE}"/>			<DefaultRolloverStrategy max="${MAX}">				<Delete basePath="${LOG_HOME}" maxDepth="${MAXDEPTH}">					<IfFileName glob="${BACKUP_HOME}/debug/*/*.log*" />					<IfLastModified age="${AGE}" />				</Delete>			</DefaultRolloverStrategy>		</RollingFile>		<!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->		<!-- 重要的是,如果有多个ThresholdFilter,那么Filters是必须的,同时在Filters中,首先要过滤不符合的日志级别,把不需要的首先DENY掉,然后再ACCEPT需要的日志级别,这个次序不能搞颠倒。 -->		<RollingFile name="RollingFileDaHanRequest"					 fileName="${LOG_HOME}/${SERVER_NAME}_dahan.log"					 filePattern="${LOG_HOME}/${BACKUP_HOME}/dahan/${BACK_FOLDER}/${SERVER_NAME}_dahan-%i.log${BACKUP_FILE_NAME_SUFFIX}">			<PatternLayout pattern="${PATTERN}" />			<Policies>				<SizeBasedTriggeringPolicy size="${EVERY_FILE_SIZE}" />				<TimeBasedTriggeringPolicy interval="1" modulate="true" />			</Policies>			<Filters>				<!--<ThresholdFilter level="info" onMatch="DENY" onMismatch="NEUTRAL" />-->				<ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY" />			</Filters>			<CronTriggeringPolicy schedule="${SCHEDULE}"/>			<DefaultRolloverStrategy max="${MAX}">				<Delete basePath="${LOG_HOME}" maxDepth="${MAXDEPTH}">					<IfFileName glob="${BACKUP_HOME}/dahan/*/*.log*" />					<IfLastModified age="${AGE}" />				</Delete>			</DefaultRolloverStrategy>		</RollingFile>		<!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->		<!-- 重要的是,如果有多个ThresholdFilter,那么Filters是必须的,同时在Filters中,首先要过滤不符合的日志级别,把不需要的首先DENY掉,然后再ACCEPT需要的日志级别,这个次序不能搞颠倒。 -->		<RollingFile name="RollingFileHealthRequest"					 fileName="${LOG_HOME}/${SERVER_NAME}_health.log"					 filePattern="${LOG_HOME}/${BACKUP_HOME}/health/${BACK_FOLDER}/${SERVER_NAME}_health-%i.log${BACKUP_FILE_NAME_SUFFIX}">			<PatternLayout pattern="${PATTERN}" />			<Policies>				<SizeBasedTriggeringPolicy size="${EVERY_FILE_SIZE}" />				<TimeBasedTriggeringPolicy interval="1" modulate="true" />			</Policies>			<Filters>				<!--<ThresholdFilter level="info" onMatch="DENY" onMismatch="NEUTRAL" />-->				<ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY" />			</Filters>			<CronTriggeringPolicy schedule="${SCHEDULE}"/>			<DefaultRolloverStrategy max="${MAX}">				<Delete basePath="${LOG_HOME}" maxDepth="${MAXDEPTH}">					<IfFileName glob="${BACKUP_HOME}/health/*/*.log*" />					<IfLastModified age="${AGE}" />				</Delete>			</DefaultRolloverStrategy>		</RollingFile>	</appenders>	<!--然后定义logger,只有定义了logger并引入的appender,appender才会生效 -->	<loggers>        <!-- 减少部分debug日志 -->        <logger name="org.apache.shiro" level="INFO"/>        <logger name="org.springframework" level="INFO"/>        <logger name="org.springframework.context" level="INFO"/>        <logger name="org.springframework.beans" level="INFO"/>        <logger name="com.baomidou.mybatisplus" level="INFO"/>        <logger name="org.apache.ibatis.io" level="INFO"/>        <logger name="org.apache.http" level="INFO"/>        <logger name="io.lettuce" level="INFO"/>        <logger name="com.alibaba.druid" level="INFO"/>        <logger name="org.mybatis.logging.Logger.debug" level="INFO"/>        <logger name="org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug" level="DEBUG"/>        <logger name="org.redisson.connection" level="INFO"/>        <logger name="springfox.documentation" level="WARN"/>        <!-- 业务debug日志 -->        <logger name="com.forhome.babyshop" level="${OUTPUT_LOG_LEVEL}" additivity="true"/>		<!-- 大汉请求 业务日志 -->		<logger name="com.zhijia.common.framework.dahan.DaHanGet" level="DEBUG" additivity="true">			<appender-ref ref="RollingFileDaHanRequest" />		</logger>		<!-- 大汉请求 业务日志 -->		<logger name="com.zhijia.common.framework.health.HealthGet" level="DEBUG" additivity="true">			<appender-ref ref="RollingFileHealthRequest" />		</logger>        <!-- 配置日志的根节点,建立一个默认的root的logger,需要在root的level中指定输出的级别  -->		<Root level="DEBUG">			<appender-ref ref="Console" />			<appender-ref ref="RollingFileError" />			<appender-ref ref="RollingFileWarn" />			<appender-ref ref="RollingFileInfo" />			<appender-ref ref="RollingFile" />		</Root >	</loggers></configuration>

当然 这里可以使用另一种实现方案, 这个方案更简单点,就是 在输出是需要指定标记

MarkFilter

使用方式见连接 :

标签: #怎样让java输出日志内容