gradle Logback筛选器-限制性错误日志消息

tnkciper  于 2022-12-19  发布在  其他
关注(0)|答案(1)|浏览(150)

在springboot,gradle和logback上仍然是新手,我需要帮助!我正在尝试创建我自己的logback过滤器。
主要目标是允许我的日志记录器只发送一个日志消息,如果一些日志与相同的错误消息是由应用程序发送。
为此,我只需要创建一个基本的gradle项目进行测试,其中包含2个类。
build.gradle
logback.xml
project_explorer_eclipse

I -记录一些错误的主类

package com.example.CDOP221logback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;

@SpringBootApplication
public class Cdop221LogbackApplication {

    private final static Logger log = LoggerFactory.getLogger("com.example.CDOP221log4j");
    
    public static void main(String[] args) {
        SpringApplication.run(Cdop221LogbackApplication.class, args);
        
        LoggerContext context = (LoggerContext)LoggerFactory.getILoggerFactory();
        context.reset();

        JoranConfigurator config = new JoranConfigurator();
        config.setContext(context);

        try {
          config.doConfigure("/home/mehdi/eclipse-workspace/CDOP-221-logback/logback.xml");
        } catch (JoranException e) {
          e.printStackTrace();
        }
        
        test();
    }
    
    private static void test() {
        log.debug("Application Cdop221 with LOGBACK logger launch succesful");
        log.error("ERROR_1");
        log.error("ERROR_1");
        log.error("ERROR_1");
        log.error("ERROR_1");
        log.error("ERROR_1");
        log.error("ERROR_1");
        log.error("ERROR_1");
        log.error("ERROR_1");
        int i = 0;
        while(i < 100) {
            log.error("ERROR_2");
            i++;
        }
        
    }
}

II -我自己的附加器,如果某些条目相同,则必须限制日志的数量

package com.logback;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.IThrowableProxy;
import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.classic.spi.StackTraceElementProxy;
import ch.qos.logback.core.filter.Filter;
import ch.qos.logback.core.spi.FilterReply;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * Improved {@link ch.qos.logback.classic.turbo.DuplicateMessageFilter} with a timeout feature added and time window error stacking #buzzwords
 * Indeed if there's some error logs that are the same (same hashcode) they are stacked and sent after {@link DuplicateErrorLogFilter#cacheTimeoutInSec}
 */

public class DuplicateErrorLogFilter extends Filter<ILoggingEvent> {

    /**
     * Repetition number MDC property
     */
    private static final String REP_NB = "repNb";

    /**
     * The default cache size.
     */
    private static final int DEFAULT_CACHE_SIZE = 100;
    /**
     * The default cache timeout in seconds
     */
    private static final int DEFAULT_CACHE_TIMEOUT_IN_SEC = 300;

    private String smtpAppenderName;
    private int cacheSize = DEFAULT_CACHE_SIZE;
    private int cacheTimeoutInSec = DEFAULT_CACHE_TIMEOUT_IN_SEC;
    private Map<Integer, FoldingTask> tasks = new ConcurrentHashMap<>(cacheSize);
    /**
     * Timer that will expire folding tasks
     */
    private Timer foldingTimer = new Timer("folding-timer", false);

    private final class FoldingTask extends TimerTask {

        private Integer key;
        private ILoggingEvent lastEvent;
        private int foldingCount;

        @Override
        public void run() {
            // Remove current task
            tasks.remove(key);

            // And send the event to SMTP appender
            sendEvent(lastEvent, foldingCount);
        }
    }

    /**
     * Append an event that has been folded
     *
     * @param event        the last seen event of this kind
     * @param foldingCount how many events were folded
     */
    protected void sendEvent(ILoggingEvent event, int foldingCount) {
        if (event != null) {
            if (foldingCount > 1) {
                // Do that to prevent UnsupportedOp from EmptyMap
                if (event.getMDCPropertyMap().isEmpty() && event instanceof LoggingEvent) {
                    ((LoggingEvent) event).setMDCPropertyMap(new HashMap<>());
                }
                event.getMDCPropertyMap().put(REP_NB, "[" + foldingCount + "x]");
            }
            ((Logger) (LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME))).getAppender(smtpAppenderName).doAppend(event);
        }
    }

    public void setSmtpAppenderName(String smtpAppenderName) {
        this.smtpAppenderName = smtpAppenderName;
    }

    public void setCacheSize(int cacheSize) {
        this.cacheSize = cacheSize;
    }

    public void setCacheTimeoutInSec(int cacheTimeoutInSec) {
        this.cacheTimeoutInSec = cacheTimeoutInSec;
    }

    @Override
    public void start() {
        super.start();
    }

    @Override
    public void stop() {
        tasks.clear();
        tasks = null;
        super.stop();
    }

    @Override
    public FilterReply decide(ILoggingEvent event) {
        if (!event.getLevel().isGreaterOrEqual(Level.ERROR)) {
            return FilterReply.NEUTRAL;
        }

        Integer key = eventHashCode(event);
        FoldingTask task = tasks.get(key);
        if (task == null) {
            // First time we encounter this event
            task = new FoldingTask();
            task.key = key;
            // lastEvent will be set at the first folded event
            tasks.put(key, task);

            // Arm timer for this task
            foldingTimer.schedule(task, TimeUnit.SECONDS.toMillis(cacheTimeoutInSec));

            // And log this event
            return FilterReply.NEUTRAL;
        } else {
            // Fold this event
            task.lastEvent = event;
            task.foldingCount++;
            return FilterReply.DENY;
        }
    }

    /**
     * Compute a signature for an event
     */
    private int eventHashCode(ILoggingEvent event) {
        IThrowableProxy thrInfo = event.getThrowableProxy();
        if (thrInfo == null || ArrayUtils.isEmpty(thrInfo.getStackTraceElementProxyArray())) {
            // No stacktrace
            String message = event.getFormattedMessage();
            return message.hashCode();
        }

        StackTraceElementProxy[] stack = thrInfo.getStackTraceElementProxyArray();
        int hashCode = 0;
        for (StackTraceElementProxy str : stack) {
            hashCode = 31 * hashCode + str.hashCode();
        }

        return hashCode;
    }
}

所以,当我运行我的代码时,它实际上并不工作...但我真的不能确定这是因为一个糟糕的配置(我是logback库的初学者)还是我的代码很糟糕?
提前感谢您的帮助
result code (doesn't work correctly)

lrl1mhuk

lrl1mhuk1#

连接筛选器(DuplicateErrorLogFilter)和回滚的回滚配置文件(logback.xml)中缺少一部分:

<filter class="com.logback.DuplicateErrorLogFilter"/>

有关如何使用过滤器的其他信息:https://logback.qos.ch/manual/filters.html

相关问题