java - 如何在log4j2中以编程方式创建多个日志文件?

标签 java logging log4j2

我正在开发一个与许多设备通信的java应用程序。对于每个设备,我需要创建一个不同的日志文件来记录它与设备的通信。这是我开发的包装类。它创建两个日志文件,但数据仅写入第一个日志文件。第二个文件已创建,但未向其中写入任何内容。应发送到第二个文件的输出将发送到控制台。如果我在构造函数中取消注释 createRootLogger() ,则不会将任何内容写入这两个文件,所有内容都会转到控制台。我已经阅读了 log4j2 文档,但它写得很差,代码示例很少。这是我的包装类,错误在哪里?我正在使用 log4j-api-2.9.0.jar 和 log4j-core-2.9.0.jar。

package xyz;

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.ConsoleAppender;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.Configurator;
import org.apache.logging.log4j.core.config.builder.api.*;

import java.util.Hashtable;

public class LogManager
{
    static protected LogManager m_clsInstance = null;

    protected Hashtable<String, Logger> m_clsLoggers = new Hashtable<String, Logger>();

    private LogManager()
    {
        //createRootLogger();
    }
    /**
     * getInstance is used to get reference to the singalton class obj ......
     */
    static synchronized public LogManager getInstance()
    {
        try
        {
            if (m_clsInstance == null)
            {
                m_clsInstance = new LogManager();
                //Configurator.setRootLevel(Level.TRACE);
            }
        }
        catch (Exception xcpE)
        {
            System.err.println(xcpE);
        }

        return m_clsInstance;
    }

    static public Logger getLogger(String sLogger)
    {
        try
        {
            return getInstance().m_clsLoggers.get(sLogger);
        }
        catch (Exception xcpE)
        {
            System.err.println(xcpE);
        }

        return null;
    }

    public Logger createLogger(String strName, String sPath, int nBackupSize, long lngMaxSize, String strPattern, String strLevel)
    {
        try
        {
            ConfigurationBuilder builder = ConfigurationBuilderFactory.newConfigurationBuilder();

            builder.setStatusLevel(Level.getLevel(strLevel));
            builder.setConfigurationName("RollingBuilder"+strName);

            // create a console appender
            AppenderComponentBuilder appenderBuilder = builder.newAppender("Stdout", "CONSOLE").addAttribute("target",
                                                                                                             ConsoleAppender.Target.SYSTEM_OUT);
            appenderBuilder.add(builder.newLayout("PatternLayout")
                                       .addAttribute("pattern", strPattern));
            builder.add( appenderBuilder );

            // create a rolling file appender
            LayoutComponentBuilder layoutBuilder = builder.newLayout("PatternLayout")
                                                          .addAttribute("pattern", strPattern);
            ComponentBuilder triggeringPolicy = builder.newComponent("Policies")
                                                      // .addComponent(builder.newComponent("CronTriggeringPolicy").addAttribute("schedule", "0 0 0 * * ?"))
                                                       .addComponent(builder.newComponent("SizeBasedTriggeringPolicy").addAttribute("size", lngMaxSize));
             appenderBuilder = builder.newAppender("rolling"+strName, "RollingFile")
                                     .addAttribute("fileName", sPath)
                                     .addAttribute("filePattern",  "d:\\trash\\archive\\rolling-%d{MM-dd-yy}.log.gz")
                                     .add(layoutBuilder)
                                     .addComponent(triggeringPolicy);
            builder.add(appenderBuilder);

            // create the new logger
            builder.add( builder.newLogger( strName, Level.getLevel(strLevel) )
                                .add( builder.newAppenderRef( "rolling"+strName ) )
                                .addAttribute( "additivity", false ) );

            Configuration clsCnfg = (Configuration) builder.build();
            LoggerContext ctx = Configurator.initialize(clsCnfg);

            Logger clsLogger =  ctx.getLogger(strName);
            m_clsLoggers.put(strName, clsLogger);
            return clsLogger;
        }
        catch (Exception xcpE)
        {
            System.err.println(xcpE);
        }

        return null;
    }

    protected void createRootLogger()
    {
        try
        {
            ConfigurationBuilder builder = ConfigurationBuilderFactory.newConfigurationBuilder();

            builder.setStatusLevel(Level.getLevel("TRACE"));
            builder.setConfigurationName("rootConfig");

            // create a console appender
            AppenderComponentBuilder appenderBuilder = builder.newAppender("Stdout", "CONSOLE").addAttribute("target",
                                                                                                             ConsoleAppender.Target.SYSTEM_OUT);
            appenderBuilder.add(builder.newLayout("PatternLayout")
                                       .addAttribute("pattern", "[%d{yyyy-MMM-dd HH:mm:ss:SSS}][%-5p %l][%t] %m%n"));
            builder.add( appenderBuilder );

            builder.add( builder.newRootLogger( Level.getLevel("TRACE"))
                                .add( builder.newAppenderRef( "Stdout") ) );

            Configuration clsCnfg = (Configuration) builder.build();
            LoggerContext ctx = Configurator.initialize(clsCnfg);

            Logger clsLogger =  ctx.getRootLogger();
            m_clsLoggers.put("root", clsLogger);
        }
        catch (Exception xcpE)
        {
            System.err.println(xcpE);
        }
    }

    static public void main(String args[])
    {
        //Logger clsLogger = setLogger();

        Logger clsLogger = Emflex.LogManager.getInstance().createLogger(
                "AnsiAmrController_" + 5555,
                "d:\\trash\\LogManagerTest5555.log",
                10,
                100000000,
                "[%d{yyyy-MMM-dd HH:mm:ss:SSS}][%-5p %l][%t] %m%n",
                "TRACE"
                                                                       );

        Logger clsLogger2 = Emflex.LogManager.getInstance().createLogger(
                "AnsiAmrController_" + 6666,
                "d:\\trash\\LogManagerTest6666.log",
                10,
                100000000,
                "[%d{yyyy-MMM-dd HH:mm:ss:SSS}][%-5p %l][%t] %m%n",
                "TRACE"
                                                                       );

        for (int i=0;i<100;i++)
        {
            clsLogger.error("Testing - ["+i+"]");
            clsLogger2.error("Testing - ["+(i*i)+"]");
        }
    }
}

最佳答案

你说你的目标是:

For each device I need to create a different log file to log it's communication with device.

有许多不同的方法可以无需编程配置来实现此目的。编程配置很糟糕,因为它迫使您依赖日志记录实现而不是公共(public)接口(interface)。

例如,您可以使用 context map键与 Routing Appender 结合使用分离你的日志,类似于我在 another answer 中给出的示例。请注意,在另一个答案中,我使用变量作为存储日志的文件夹,但如果您愿意,可以将其用作日志名称。

做你想做的事情的另一种方法是使用 MapMessagelog4j2 manual所示.

另一种方法是使用 markersRoutingAppender 结合使用。以下是此方法的一些示例代码:

package example;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;

public class LogLvlByMarkerMain {
    private static final Logger log = LogManager.getLogger();
    private static final Marker DEVICE1 = MarkerManager.getMarker("DEVICE1");
    private static final Marker DEVICE2 = MarkerManager.getMarker("DEVICE2");

    public static void main(String[] args) {
        log.info(DEVICE1, "The first device got some input");
        log.info(DEVICE2, "The second device now has input");
    }
}

配置:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <Routing name="MyRoutingAppender">
            <Routes pattern="$${marker:}">
                <Route>
                    <File
                        fileName="logs/${marker:}.txt"
                        name="appender-${marker:}">
                        <PatternLayout>
                            <Pattern>[%date{ISO8601}][%-5level][%t] %m%n</Pattern>
                        </PatternLayout>
                    </File>
                </Route>
            </Routes>
        </Routing>
        <Console name="STDOUT" target="SYSTEM_OUT">
            <PatternLayout pattern="[%date{ISO8601}][%-5level][%t] %m%n" />
        </Console>
    </Appenders>
    <Loggers>
        <Logger name="example" level="TRACE" additivity="false">
            <AppenderRef ref="STDOUT" />
            <AppenderRef ref="MyRoutingAppender" />
        </Logger>
        <Root level="WARN">
            <AppenderRef ref="STDOUT" />
        </Root>
    </Loggers>
</Configuration>

输出:

这将生成 2 个日志文件 - DEVICE1.txt 和 DEVICE2.txt,如下图所示。

Generated Log Files

第一个日志将仅包含标记为 DEVICE1 的消息,第二个日志将仅包含 DEVICE2 日志。

即第一个日志包含:

[2017-09-21T09:52:04,171][INFO ][main] The first device got some input

第二个包含:

[2017-09-21T09:52:04,176][INFO ][main] The second device now has input

关于java - 如何在log4j2中以编程方式创建多个日志文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46336225/

相关文章:

java - Log4j2,在运行时为特定于线程设置日志级别

java - 将 mysql 正则表达式转换为 java 正则表达式(和/或相反)

java - log4j2.xml 未在 Eclipse 中加载

web-applications - Log4j2:无法使用 Servlet 上下文监听器设置 MDC key

java - Hibernate 抑制信息消息

c++ - 有没有比 #if DebugMode 更好的日志记录方法

java - Log4j2 替代 MonitorInterval ="30"

java - 有限时间内多次查询的最佳解决方案

java - 无法发送 SOAP 消息

java - 当程序需要整数时用户输入字符串时如何防止程序终止?