简体   繁体   English

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

[英]How to create multiple log file programatically in log4j2?

I am developing a java application which communicates with lots of devices.我正在开发一个与许多设备通信的 java 应用程序。 For each device I need to create a different log file to log it's communication with device.对于每个设备,我需要创建一个不同的日志文件来记录它与设备的通信。 This is the wrapper class I developed.这是我开发的包装类。 It creates two log files but the data is written to only the first one.它创建两个日志文件,但数据只写入第一个。 The second file is created but nothing is written to it.创建了第二个文件,但没有写入任何内容。 The output that should go to second file goes to console.应该转到第二个文件的输出转到控制台。 If I uncomment createRootLogger() in constructor nothing is written to both the files, everything goes to console.如果我在构造函数中取消对 createRootLogger() 的注释,则两个文件都不会写入任何内容,所有内容都会进入控制台。 I have gone through log4j2 documentation but it is poorly written with very few code samples.我已经阅读了 log4j2 文档,但它写得不好,代码示例很少。 Here is my wrapper class, where is the error?这是我的包装类,错误在哪里? I am using log4j-api-2.9.0.jar and log4j-core-2.9.0.jar.我正在使用 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)+"]");
        }
    }
}

You said your objective is:你说你的目标是:

For each device I need to create a different log file to log it's communication with device.对于每个设备,我需要创建一个不同的日志文件来记录它与设备的通信。

There are many different ways to accomplish this without programmatic configuration .有许多不同的方法可以在没有编程配置的情况下完成此操作。 Programmatic configuration is bad because it forces you to depend on the logging implementation rather than the public interface.编程配置很糟糕,因为它迫使您依赖日志记录实现而不是公共接口。

For example you could use a context map key in conjunction with a Routing Appender to separate your logs, similar to the example I gave in another answer .例如,您可以将上下文映射键与Routing Appender结合使用来分隔日志,类似于我在另一个答案中给出的示例。 Note that in the other answer I used the variable as the folder where the log is stored but you can use it for the log name if you wish.请注意,在另一个答案中,我使用变量作为存储日志的文件夹,但如果您愿意,可以将其用作日志名称。

Another way to do what you want would be to use a MapMessage as shown in the log4j2 manual .另一种做你想做的事情的方法是使用一个MapMessage ,如log4j2 手册中所示。

Yet another way would be to use markers in combination with a RoutingAppender .另一种方法是将标记RoutingAppender结合使用。 Here is some example code for this approach:以下是此方法的一些示例代码:

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");
    }
}

Configuration :配置

<?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>

Output :输出

This will generate 2 log files - DEVICE1.txt and DEVICE2.txt as shown in the image below.这将生成 2 个日志文件 - DEVICE1.txt 和 DEVICE2.txt,如下图所示。

生成的日志文件

The first log will contain only messages that were marked as DEVICE1 and the second will contain only DEVICE2 logs.第一个日志将仅包含标记为 DEVICE1 的消息,第二个将仅包含 DEVICE2 日志。

Ie the first log contains:即第一个日志包含:

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

and the second contains:第二个包含:

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

The approach log4j2 is initialize programmatically and later configuration is modified is different.方法log4j2以编程方式初始化,稍后修改的配置不同。 And you you trying to add dynamic appender and logger using initialization approach.而您尝试使用初始化方法添加动态appenderlogger

So, first you should initialize your RootLogger using initialization approach that seems correct in your code.因此,首先您应该使用在您的代码中似乎正确的初始化方法来初始化您的 RootLogger。

After that, add dynamic appender and logger using approach mentioned here之后,使用这里提到的方法添加动态appenderlogger

adding on DB answer:添加数据库答案:

I had trouble making this write to file.我无法将此写入文件。 (and yes I tried using log4j2 version 2.8.1 but still didn't work) (是的,我尝试使用 log4j2 2.8.1 版,但仍然无效)

To make it work I edited this part为了使它工作,我编辑了这部分

<Root level="WARN">
    <AppenderRef ref="STDOUT" />
</Root>

to this:对此:

<Root level="WARN">
    <AppenderRef ref="STDOUT" />
    <AppenderRef ref="MyRoutingAppender" />
</Root>

And since the Debug level is set to WARN并且由于调试级别设置为 WARN

<Configuration status="WARN">

and we trying to log info我们试图记录信息

log.info(DEVICE$, "The $ device now has input");

the info log wont be written (WARN will only print: warn, error, fatal check this link log4j logging level )不会写入信息日志(WARN 只会打印:警告、错误、致命检查此链接log4j 日志记录级别

you can simply change你可以简单地改变

log.info() --> log.warn() 

just as a proof of concept.只是作为概念的证明。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM