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

时间:2017-09-21 05:41:49

标签: 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)+"]");
        }
    }
}

2 个答案:

答案 0 :(得分:1)

方法getCellStyle以编程方式初始化,后来的配置被修改是不同的。您尝试使用初始化方法添加动态log4j2appender

因此,首先应该使用在代码中看似正确的初始化方法初始化RootLogger。

之后,使用提及here的方法添加动态loggerappender

答案 1 :(得分:1)

你说你的目标是:

  

对于每个设备,我需要创建一个不同的日志文件来记录它与设备的通信。

有许多不同的方法可以实现无需编程配置。程序化配置很糟糕,因为它会强制您依赖日志记录实现而不是公共接口。

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

执行所需操作的另一种方法是使用MapMessage中显示的log4j2 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