Log4j:事件出现在错误的日志文件中

发布于 2024-08-03 09:15:10 字数 3654 浏览 2 评论 0原文

为了能够记录和跟踪一些事件,我在我的 java 项目中添加了 LoggingHandler 类。在此类中,我使用两个不同的 log4j 记录器实例 - 一个用于记录事件,另一个用于将事件跟踪到不同的文件中。该类的初始化块如下所示:

public void initialize()
{
    System.out.print("starting logging server ...");

    // create logger instances
    logLogger = Logger.getLogger("log");
    traceLogger = Logger.getLogger("trace");

    // create pattern layout
    String conversionPattern = "%c{2} %d{ABSOLUTE} %r %p %m%n";
    try
    {
        patternLayout = new PatternLayout();
        patternLayout.setConversionPattern(conversionPattern);
    }
    catch (Exception e)
    {
        System.out.println("error: could not create logger layout pattern");
        System.out.println(e);
        System.exit(1);
    }

    // add pattern to file appender
    try
    {
        logFileAppender = new FileAppender(patternLayout, logFilename, false);
        traceFileAppender = new FileAppender(patternLayout, traceFilename, false);
    }
    catch (IOException e)
    {
        System.out.println("error: could not add logger layout pattern to corresponding appender");
        System.out.println(e);
        System.exit(1);
    }

    // add appenders to loggers
    logLogger.addAppender(logFileAppender);
    traceLogger.addAppender(traceFileAppender);

    // set logger level
    logLogger.setLevel(Level.INFO);
    traceLogger.setLevel(Level.INFO);

    // start logging server
    loggingServer = new LoggingServer(logLogger, traceLogger, serverPort, this);
    loggingServer.start();

    System.out.println(" done");
}

为了确保只有线程在使用记录器实例的功能,同时每个日志记录/跟踪方法都会调用同步块内的日志记录方法 .info()。一个示例如下所示:

    public void logMessage(String message)
{
    synchronized (logLogger)
    {
        if (logLogger.isInfoEnabled() && logFileAppender != null)
        {
            logLogger.info(instanceName + ": " + message);
        }
    }
} 

如果我查看日志文件,我会发现有时事件会出现在错误的文件中。一个例子:

trace 10:41:30,773 11080 INFO masterControl(192.168.2.21): string broadcast message was  pushed from 1267093 to vehicle 1055293 (slaveControl 1)
trace 10:41:30,784 11091 INFO masterControl(192.168.2.21): string broadcast message was pushed from 1156513 to vehicle 1105792 (slaveControl 1)
trace 10:41:30,796 11103 INFO masterControl(192.168.2.21): string broadcast message was pushed from 1104306 to vehicle 1055293 (slaveControl 1)
trace 10:41:30,808 11115 INFO masterControl(192.168.2.21): vehicle 1327879 was pushed to slave control 1
10:41:30,808 11115 INFO masterControl(192.168.2.21): string broadcast message was pushed from 1101572 to vehicle 106741 (slaveControl 1)
trace 10:41:30,820 11127 INFO masterControl(192.168.2.21): string broadcast message was pushed from 1055293 to vehicle 1104306 (slaveControl 1)

我认为每当两个事件同时发生时就会出现问题(此处:10:41:30,808)。有人知道如何解决我的问题吗?我已经尝试在方法调用后添加 sleep() ,但这没有帮助...

BR,

Markus

编辑:

logtrace  11:16:07,75511:16:07,755  1129711297  INFOINFO  masterControl(192.168.2.21): string broadcast message was pushed from 1291400 to vehicle 1138272 (slaveControl 1)masterControl(192.168.2.21): vehicle 1333770 was added to slave control 1

log 11:16:08,562 12104 INFO 11:16:08,562 masterControl(192.168.2.21): string broadcast message was pushed from 117772 to vehicle 1217744 (slaveControl 1)

12104 INFO masterControl(192.168.2.21):vehicle 1169775 was Push to Slave control 1

Edit 2:

It似乎只有从 RMI 线程内部调用日志记录方法(我的客户端/服务器使用 RMI 连接交换信息)时才会出现该问题。 ...

编辑3:

我自己解决了这个问题:似乎log4j并不是完全线程保存的。使用单独的对象同步所有日志/跟踪方法后,一切正常。也许库在将消息写入文件之前将消息写入线程不安全的缓冲区?

To be able to log and trace some events I've added a LoggingHandler class to my java project. Inside this class I'm using two different log4j logger instances - one for logging an event and one for tracing an event into different files. The initialization block of the class looks like this:

public void initialize()
{
    System.out.print("starting logging server ...");

    // create logger instances
    logLogger = Logger.getLogger("log");
    traceLogger = Logger.getLogger("trace");

    // create pattern layout
    String conversionPattern = "%c{2} %d{ABSOLUTE} %r %p %m%n";
    try
    {
        patternLayout = new PatternLayout();
        patternLayout.setConversionPattern(conversionPattern);
    }
    catch (Exception e)
    {
        System.out.println("error: could not create logger layout pattern");
        System.out.println(e);
        System.exit(1);
    }

    // add pattern to file appender
    try
    {
        logFileAppender = new FileAppender(patternLayout, logFilename, false);
        traceFileAppender = new FileAppender(patternLayout, traceFilename, false);
    }
    catch (IOException e)
    {
        System.out.println("error: could not add logger layout pattern to corresponding appender");
        System.out.println(e);
        System.exit(1);
    }

    // add appenders to loggers
    logLogger.addAppender(logFileAppender);
    traceLogger.addAppender(traceFileAppender);

    // set logger level
    logLogger.setLevel(Level.INFO);
    traceLogger.setLevel(Level.INFO);

    // start logging server
    loggingServer = new LoggingServer(logLogger, traceLogger, serverPort, this);
    loggingServer.start();

    System.out.println(" done");
}

To make sure that only only thread is using the functionality of a logger instance at the same time each logging / tracing method calls the logging method .info() inside a synchronized-block. One example looks like this:

    public void logMessage(String message)
{
    synchronized (logLogger)
    {
        if (logLogger.isInfoEnabled() && logFileAppender != null)
        {
            logLogger.info(instanceName + ": " + message);
        }
    }
} 

If I look at the log files, I see that sometimes a event appears in the wrong file. One example:

trace 10:41:30,773 11080 INFO masterControl(192.168.2.21): string broadcast message was  pushed from 1267093 to vehicle 1055293 (slaveControl 1)
trace 10:41:30,784 11091 INFO masterControl(192.168.2.21): string broadcast message was pushed from 1156513 to vehicle 1105792 (slaveControl 1)
trace 10:41:30,796 11103 INFO masterControl(192.168.2.21): string broadcast message was pushed from 1104306 to vehicle 1055293 (slaveControl 1)
trace 10:41:30,808 11115 INFO masterControl(192.168.2.21): vehicle 1327879 was pushed to slave control 1
10:41:30,808 11115 INFO masterControl(192.168.2.21): string broadcast message was pushed from 1101572 to vehicle 106741 (slaveControl 1)
trace 10:41:30,820 11127 INFO masterControl(192.168.2.21): string broadcast message was pushed from 1055293 to vehicle 1104306 (slaveControl 1)

I think that the problem occures everytime two event happen at the same time (here: 10:41:30,808). Does anybody has an idea how to solve my problem? I already tried to add a sleep() after the method call, but that doesn't helped ...

BR,

Markus

Edit:

logtrace  11:16:07,75511:16:07,755  1129711297  INFOINFO  masterControl(192.168.2.21): string broadcast message was pushed from 1291400 to vehicle 1138272 (slaveControl 1)masterControl(192.168.2.21): vehicle 1333770 was added to slave control 1

or

log 11:16:08,562 12104 INFO 11:16:08,562 masterControl(192.168.2.21): string broadcast message was pushed from 117772 to vehicle 1217744 (slaveControl 1)

12104 INFO masterControl(192.168.2.21): vehicle 1169775 was pushed to slave control 1

Edit 2:

It seems like the problem only occurs if logging methods are called from inside a RMI thread (my client / server exchange information using RMI connections). ...

Edit 3:

I solved the problem by myself: It seems like log4j is NOT completely thread-save. After synchronizing all log / trace methods using a separate object everything is working fine. Maybe the lib is writing the messages to a thread-unsafe buffer before writing them to file?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

苦笑流年记忆 2024-08-10 09:15:10

您不需要在记录器上同步,而是在输出流上同步。

如果您使用 log4j,则输出应该正确同步。获得您所看到的内容的唯一方法是两个线程同时写入同一个文件。

您是否可以使用相同的输出文件配置两个附加程序?不要那样做;每个附加程序都必须有自己的、不同的文件名。

如果您 100% 确定每个附加程序都写入不同的文件,那么剩下的唯一选择就是您有时使用了错误的记录器。

You don't need to synchronize on your logger but on the output stream.

If you use log4j, the output should be correctly synchronized. The only way to get what you see is that two threads write to the same file at the same time.

Is it possible that you configured two appenders with the same output file? Don't do that; every appender must have it's own, distinct file name.

If you're 100% sure that every appender writes to a different file, the only option left is that you're sometimes using the wrong logger.

空城仅有旧梦在 2024-08-10 09:15:10

难道是因为某种原因多次调用了initialize方法吗?每次调用都会添加两个新的附加程序,它们写入与现有附加程序相同的文件中。

Could it be that somehow the initialize method is called more than once? Every call would add two new appenders that write into the same file as the existing appenders.

人生百味 2024-08-10 09:15:10

这个问题已经有 4 年历史了,但我在 2013 年刚刚遇到了同样的问题,我想我已经通过为每个 Appender 创建一个新的 PatternLayout 来解决它。希望它能帮助其他人将来遇到同样的问题。

This question is 4 years old but I just came across this same problem in 2013 and I think I've fixed it by creating a new PatternLayout for each Appender. Hope it helps anyone else with the same issue in the future.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文