繁体   English   中英

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

[英]How to create multiple log file programatically in 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)+"]");
        }
    }
}

你说你的目标是:

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

有许多不同的方法可以在没有编程配置的情况下完成此操作。 编程配置很糟糕,因为它迫使您依赖日志记录实现而不是公共接口。

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

另一种做你想做的事情的方法是使用一个MapMessage ,如log4j2 手册中所示。

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

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,如下图所示。

生成的日志文件

第一个日志将仅包含标记为 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

方法log4j2以编程方式初始化,稍后修改的配置不同。 而您尝试使用初始化方法添加动态appenderlogger

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

之后,使用这里提到的方法添加动态appenderlogger

添加数据库答案:

我无法将此写入文件。 (是的,我尝试使用 log4j2 2.8.1 版,但仍然无效)

为了使它工作,我编辑了这部分

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

对此:

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

并且由于调试级别设置为 WARN

<Configuration status="WARN">

我们试图记录信息

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

不会写入信息日志(WARN 只会打印:警告、错误、致命检查此链接log4j 日志记录级别

你可以简单地改变

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

只是作为概念的证明。

暂无
暂无

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

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