• Log4j/Log4j2自定义Appender来实现日志级别计数统计及监控


    一、简述

      本文主要讲如何基于Log4j2来实现自定义的Appender。一般用途是用于Log4j2自带的Appender不足以满足我们的需求,或者需要我们对日志进行拦截统计等操作时,需要我们自定义Appender。

    二、自定义Appender

      方法:实现一个类,让它继承自Log4j2的AbstractAppender,然后你重写其append方法,并添加一个@PluginFactory标记的createAppender方法。

      举例:例如,我们要实现一个通过日志输出的Level来统计计数来实现监控的一个Appender,并需要在配置日志时,实现对一些附加属性的配置,可以如下实现。

    package com.test.utils.logs;
    
    import org.apache.logging.log4j.core.Filter;
    import org.apache.logging.log4j.core.Layout;
    import org.apache.logging.log4j.core.LogEvent;
    import org.apache.logging.log4j.core.appender.AbstractAppender;
    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.layout.PatternLayout;
    
    import java.io.Serializable;
    
    @Plugin(name = "Statistics", category = "Core", elementType = "appender", printObject = true)
    public class StatisticsAppender extends AbstractAppender {
        /** 日志级别大于等于此级别及以上会进行判断错误。默认:ERROR */
        private String failedOnLogLevel;
        /** 指定时间内,出现多少次该日志级别,会被认为是错误。默认:10 */
        private Integer failedOnLogLevelCount;
        /** 该日志级别以上持续出现多长时间,会被认为是错误。默认:30000 */
        private Integer failedOnLogLevelInMisSecond;
        /** 当连续小于该日志级别多长时间后,恢复为正常状态。默认:120000 */
        private Integer recoveryOnLessLogLevelInMisSecond;
    
        protected StatisticsAppender(String name, Filter filter, Layout<? extends Serializable> layout,
                                     String failedOnLogLevel,
                                     Integer failedOnLogLevelCount,
                                     Integer failedOnLogLevelInMisSecond,
                                     Integer recoveryOnLessLogLevelInMisSecond) {
            super(name, filter, layout);
            this.failedOnLogLevel = failedOnLogLevel;
            this.failedOnLogLevelCount = failedOnLogLevelCount;
            this.failedOnLogLevelInMisSecond = failedOnLogLevelInMisSecond;
            this.recoveryOnLessLogLevelInMisSecond = recoveryOnLessLogLevelInMisSecond;
        }
    
    
        @Override
        public void append(LogEvent logEvent) {
            //此处省略告警过滤统计代码。
            // .....
            String msg = logEvent.getMessage().getFormattedMessage();
            System.out.println(msg);
        }
    
        @PluginFactory
        public static StatisticsAppender createAppender(@PluginAttribute("name") String name,
                                                        @PluginElement("Filter") final Filter filter,
                                                        @PluginElement("Layout") Layout<? extends Serializable> layout,
                                                        @PluginAttribute("failedOnLogLevel") String failedOnLogLevel,
                                                        @PluginAttribute("failedOnLogLevelCount") Integer failedOnLogLevelCount,
                                                        @PluginAttribute("failedOnLogLevelInMisSecond") Integer failedOnLogLevelInMisSecond,
                                                        @PluginAttribute("recoveryOnLessLogLevelInMisSecond") Integer recoveryOnLessLogLevelInMisSecond) {
            if (name == null) {
                LOGGER.error("No name provided for MyCustomAppenderImpl");
                return null;
            }
            if (layout == null) {
                layout = PatternLayout.createDefaultLayout();
            }
            if (failedOnLogLevel == null) {
                failedOnLogLevel = "ERROR";
            }
            if (failedOnLogLevelCount == null) {
                failedOnLogLevelCount = 10;
            }
            if (failedOnLogLevelInMisSecond == null) {
                failedOnLogLevelInMisSecond = 30000;
            }
            if (recoveryOnLessLogLevelInMisSecond == null) {
                recoveryOnLessLogLevelInMisSecond = 120000;
            }
            return new StatisticsAppender(name, filter, layout, failedOnLogLevel, failedOnLogLevelCount, failedOnLogLevelInMisSecond, recoveryOnLessLogLevelInMisSecond);
        }
    
    }

      说明:注意黄色区域的地方,另外createAppender方法中,红色的参数表示XML中要配置的Appender属性。

    三、配置log4j2.xml文件

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration status="ON" packages="org.apache.logging.log4j.core,io.sentry.log4j2,com.test.utils.logs">
        <appenders>
            <Console name="Console" target="SYSTEM_OUT">
                <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
            </Console>
            <RollingFile name="RollingFile" fileName="datamerge-logs/app.log"
                         filePattern="datamerge-logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
                <PatternLayout pattern="%d{yyyy.MM.dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/>
                <SizeBasedTriggeringPolicy size="300 MB"/>
            </RollingFile>
            <Sentry name="Sentry"/>
            <Statistics name="StatisticsMonitor" failedOnLogLevel="ERROR" failedOnLogLevelCount="10"
                        failedOnLogLevelInMisSecond="30000" recoveryOnLessLogLevelInMisSecond="120000"/>
        </appenders>
        <loggers>
            <root level="INFO">
                <appender-ref ref="Console"/>
                <!--<appender-ref ref="RollingFile"/>-->
                <!--<appender-ref ref="Sentry" level="ERROR" />-->
                <appender-ref ref="StatisticsMonitor"/>
            </root>
        </loggers>
    </configuration>

      说明,请仔细阅读黄色区域的内容。packages中要标注Appender所在的包名(不同的包名请使用","分隔)

    四、调用

      正常调用日志即可。需要说明的是,Appender会在程序启动后第一次调用日志时,实例化一次Appender,之后就不会再实例化了。之后会多次调用append方法。

  • 相关阅读:
    javascript高级编程笔记03(正则表达式)
    javascript高级编程笔记02(基本概念)
    javascript高级编程笔记01(基本概念)
    ExtJS4加载FormPanel数据的几种方式
    Extjs 更新数据集Ext.PagingToolbar的start参数重置的处理
    四川绵阳 晴
    四川绵阳 阴
    四川绵阳 晴
    在IntelliJ IDEA中添加repository模板
    List分组 用于客服对话分组场景
  • 原文地址:https://www.cnblogs.com/songxingzhu/p/10437598.html
Copyright © 2020-2023  润新知