簡體   English   中英

Log4j2:為多個日志動態創建日志文件

[英]Log4j2: Dynamic creation of log files for multiple logs

我目前正在創建一個可以包含模塊(將它們視為插件)的系統,其中每個模塊都可以有自己的專用日志。

我想使用 log4j2 項目進行日志記錄,但我似乎在使用文件附加程序時遇到了一些問題。

主項目(模塊加載器和整個事情的“核心”)應該有自己的日志文件,而模塊應該有自己的(如mod_XXXXXXXX.log )。

通過閱讀有關 appenders 的文檔,我發現了FileAppender類,我打算使用它。 直到我發現我不能簡單地將附加程序添加到由LogManager.getLog()創建的默認記錄器中。

LogManager 返回的記錄器與Logger接口是不同的記錄器。

即使搜索也沒有給我任何接近的解決方案,我發現的只是 xml 配置中的預定義文件日志——這不是我想要的。

感謝您的閱讀; 即使是最輕微的線索也是受歡迎的:)

如果您確實需要動態確定日志文件,請查看Log4J2 RoutingAppender 一個較長的示例在常見問題解答中,這些 stackoverflow 問題可能很有趣: Log4j2 的 RoutingAppender 的通配符模式如何使用 log4j2(xml 中的 MDC)在不同的文件中寫入不同的日志?

請注意,您需要在 RoutingAppender 用來決定將日志事件路由到哪個附加程序的ThreadContext映射中設置值。 這意味着每次您的代碼進入不同的插件時,您都需要在 ThreadContext 映射中添加一些值。

但是,您真的需要它如此動態嗎? 如果你事先知道你有哪些插件,你可以為每個插件聲明一個記錄器(使用插件的包名是一種常用的方法),並將每個這樣的記錄器映射到一個單獨的附加程序。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
  <Appenders>
    <File name="MyFile" fileName="logs/app.log">
      <PatternLayout>
        <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
      </PatternLayout>
    </File>
    <File name="plugin1" fileName="logs/plugin1.log">
      <PatternLayout>
        <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
      </PatternLayout>
    </File>
    <File name="plugin2" fileName="logs/plugin2.log">
      <PatternLayout>
        <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
      </PatternLayout>
    </File>
  </Appenders>
  <Loggers>
    <Logger name="com.mycomp.project.plugin1" level="debug">
      <AppenderRef ref="plugin1" level="debug" />
    </Logger>
    <Logger name="com.mycomp.project.plugin2" level="debug">
      <AppenderRef ref="plugin2" level="debug" />
    </Logger>
    <Root level="trace">
      <AppenderRef ref="MyFile" level="trace" />
    </Root>
  </Loggers>
</Configuration>

我假設您希望您的模塊管理代碼定義記錄器配置,對嗎? 如果是這樣,您可能需要查看手冊的這一部分,該部分討論了擴展 LoggerConfig,它根據您的要求是我認為您正在尋找的。

http://logging.apache.org/log4j/2.x/manual/extending.html

值得一提的是,我之前曾參與過基於大型插件的系統(使用 OSGi),而且老實說,我們還沒有走這條路。 從單個日志文件中 grep 您感興趣的類或包通常更容易。

盡管 Remko Popma 的回答可能是進行日志記錄的最有效方法,但我構建了一個可以自行創建日志文件的小類。

我想我會使用公認答案的解決方案,所以這是我為解決 XML 文件內容而編寫的代碼:

import gnu.trove.map.hash.THashMap;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.FileAppender;
import org.apache.logging.log4j.core.async.AsyncLoggerContext;
import org.apache.logging.log4j.core.layout.PatternLayout;
import org.apache.logging.log4j.message.FormattedMessageFactory;
import org.apache.logging.log4j.message.MessageFactory;

import java.io.File;
import java.io.IOException;
import java.util.Map;

/**
 * Represents a manager for custom log files stored inside a log folder.
 */
public class LoggingManager {
    /** The default log file extension */
    public static final String FILE_EXTENSION = "log";

    /** The global context used for all loggers */
    private final LoggerContext context;

    /** The global message factory used for all loggers */
    private final MessageFactory msgFactory;

    /** A map of all created logs */
    private final Map<String, Logger> logCache;

    /** The folder containing the log files */
    private final File logFolder;


    public LoggingManager(String name, File logFolder) throws IOException {
        this.logFolder = logFolder;

        if(!logFolder.exists()) {
            if(!logFolder.mkdirs()) {
                throw new IOException("Could not create log folder");
            }
        }

        this.logCache = new THashMap<String, Logger>();

        // Create logger context
        this.context = new AsyncLoggerContext(name);

        // Create formatted message factory
        this.msgFactory = new FormattedMessageFactory();
    }

    public Logger getLogger(String name) {
        Logger logger = logCache.get(name);

        // Create a new one
        if(logger == null) {
            logger = new SimpleLogger(name);

            FileAppender appender = FileAppender.createAppender(
                    new File(logFolder, name + "." + FILE_EXTENSION).getAbsolutePath(),
                    "true",
                    "false",
                    "file_appender-" + name,
                    "true",
                    "false",
                    "true",
                    PatternLayout.createLayout(PatternLayout.SIMPLE_CONVERSION_PATTERN, null, null, "UTF-8", "true"),
                    null,
                    "false",
                    null,
                    null
            );

            appender.start();
            logger.getContext().getConfiguration().getLoggerConfig("root").addAppender(appender, Level.ALL, null);

            // Add to log cache
            logCache.put(name, logger);
        }

        // Return the logger
        return logger;
    }

    private class SimpleLogger extends Logger {

        public SimpleLogger(String name) {
            super(context, name, msgFactory);

            // Set to all levels
            this.setLevel(Level.ALL);
        }

    }

}

如果您不使用trove ,您可以根據需要將其替換為普通的 java HashMap

***** Creating Dynamic Multiple Log Files using RoutingAppender and
                RollingFileAppender based on MDC *****

1) In the below file I am creating the three files dynamically 
       a) specialspecial.log
       b) rollingtest.log
       c) Queue.Name.log

 Note: we can create as many as you want just need change the keyname
 like ThreadContext.remove("keyname"); //removing previous key
      ThreadContext.put("keyname","fileNameWithPath") //adding new file
       log.info("Message"); //now onwards log the messages into above file

2)  I have added the IdlePurgePolicy( 1min) - if the log events are not coming for 1 min then 
    it released all resources attached with the appender and deletes the dormant appender

 and after deleting the appender if again log event is coming then it 
 will create the new appender and log the messages into our desired file 
 I have created my own and tested working fine in debug mode
 ---------------------------------------------------------------------------------------
log4j2.properties

status=debug
name=PropertiesConfig

filter.threshold.type=ThresholdFilter
filter.threshold.level=debug

appenders=routing
appender.routing.type=Routing
appender.routing.name=Routing

appender.routing.purge.type=IdlePurgePolicy
appender.routing.purge.timeToLive=1
appender.routing.purge.timeUnit=minutes

appender.routing.routes.type=Routes
appender.routing.routes.pattern=$${ctx:keyname}

appender.routing.routes.route.type=Route
appender.routing.routes.route.rolling.type=RollingFile
appender.routing.routes.route.rolling.name=RollingFile
appender.routing.routes.route.rolling.fileName=${ctx:keyname}.log
appender.routing.routes.route.rolling.filePattern=${ctx:keyname}-%d{MM-dd-yy-HH-mm-ss}-%i.log.gz
appender.routing.routes.route.rolling.layout.type=PatternLayout
appender.routing.routes.route.rolling.layout.pattern=%m%n
appender.routing.routes.route.rolling.policies.type=Policies
#appender.routing.routes.route.rolling.policies.time.type=TimeBasedTriggeringPolicy
#appender.routing.routes.route.rolling.policies.time.interval=2
#appender.routing.routes.route.rolling.policies.time.modulate=true
appender.routing.routes.route.rolling.policies.size.type=SizeBasedTriggeringPolicy
appender.routing.routes.route.rolling.policies.size.size=1KB
appender.routing.routes.route.rolling.strategy.type=DefaultRolloverStrategy
appender.routing.routes.route.rolling.strategy.max=5
appender.routing.routes.route2.type=Route
appender.routing.routes.route2.key=P:/TestLogging/specialspecial
#appender.routing.routes.route.ref=Routes

appender.routing.routes.route2.rolling.type=RollingFile
appender.routing.routes.route2.rolling.name=RollingFile
appender.routing.routes.route2.rolling.fileName=${ctx:keyname}.log
appender.routing.routes.route2.rolling.filePattern=${ctx:keyname}-%d{MM-dd-yy-HH-mm-ss}-%i.log.gz
appender.routing.routes.route2.rolling.layout.type=PatternLayout
appender.routing.routes.route2.rolling.layout.pattern=%d %p %C{1.} [%t] %m%n
appender.routing.routes.route2.rolling.policies.type=Policies
#appender.routing.routes.route2.rolling.policies.time.type=TimeBasedTriggeringPolicy
#appender.routing.routes.route2.rolling.policies.time.interval=2
#appender.routing.routes.route2.rolling.policies.time.modulate=true
appender.routing.routes.route2.rolling.policies.size.type=SizeBasedTriggeringPolicy
appender.routing.routes.route2.rolling.policies.size.size=1KB
appender.routing.routes.route2.rolling.strategy.type=DefaultRolloverStrategy
appender.routing.routes.route2.rolling.strategy.max = 5
loggers=routing
logger.routing.level=debug
logger.routing.name=com.infy.demo
logger.routing.additivity=false
logger.routing.appenderRef.routing.ref=Routing
rootLogger.level=debug
------------------------------------------------------------------------------------------------------------------
TestLog4j2Logging.class

 package com.infy.demo;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.Configurator;

public class TestLog4j2Logging {

private static final Logger log = LogManager.getLogger(TestLog4j2Logging.class);

public TestLog4j2Logging() {
    logInfo("Logging has been initalized");
}

static {
    ThreadContext.put("keyname","P:/TestLogging/TestLog4j2Logging");
    Configurator.initialize(null, "./properties/log4j2.properties");
}

public  void logTestLog4j2LoggingMesg()
{
    
    String[] arr = {"Msg1111111111111","Msg222222222222222","Msg3333333333333","Msg44444444444"};
    for (String string : arr) {
        logInfo(string);
        logError(string);
        log.debug(string);
    }
}

public void logMqMsg() throws Exception
{
    
    
    String[] mqArr = {"MQ111111111111111111","MQ222222222222222222222222","MQ3333333333333333333333"};
    for (String string : mqArr) {
        log.info(string);
    }
}


public void logSpecialKeyRouteMsgAppender()
{
    String[] mqArr = {"Special111111111111111111","Special222222222222222222222222","Special3333333333333333333333"};
    for (String string : mqArr) {
        log.info(string);
    }
}

public static void main(String[] args) throws Exception
{
    TestLog4j2Logging testLog4j2Logging = new TestLog4j2Logging();
 System.out.println("=================file TestLog4j2Logging.log creating and logging the messages==============================================");
//Logging the messages for the this class level Logging
    testLog4j2Logging.logTestLog4j2LoggingMesg();
    
    
 System.out.println("=================file Queue.Name.log creating and logging the messages c==============================================");
//Logging the messages for the MQ Logging file Queue.Name   
    ThreadContext.remove("keyname");
    ThreadContext.put("keyname", "P:/TestLogging/Queue.Name");
    testLog4j2Logging.logMqMsg();
    ThreadContext.remove("keyname");
    ThreadContext.put("keyname", "P:/TestLogging/TestLog4j2Logging");
    
    
System.out.println("=================file TestLog4j2Logging logging the messages==============================================");
    //Logging the messages for special key in the log4j.properties file 
    ThreadContext.remove("keyname");
    ThreadContext.put("keyname", "P:/TestLogging/specialspecial");
    testLog4j2Logging.logSpecialKeyRouteMsgAppender();
    ThreadContext.remove("keyname");
    ThreadContext.put("keyname", "P:/TestLogging/TestLog4j2Logging");
    
    Thread.sleep(61000);
    logInfo("Logging is Complted sucessfully");
    System.out.println("Messages are getting Logged");
}

private static String getCurrentDateAndTime() {
     DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");  

    return dtf.format(LocalDateTime.now());
}

private static void logInfo(String msg) {
    log.info("{} INFO  {} - {}",getCurrentDateAndTime(),TestLog4j2Logging.class.getName(),msg);
}

private static void logError(String msg) {
    log.info("{} ERROR {} - {}",getCurrentDateAndTime(),TestLog4j2Logging.class.getName(),msg);
}

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM