【问题标题】:How to destroy log4j logger instances如何销毁 log4j 记录器实例
【发布时间】:2019-02-17 21:08:37
【问题描述】:

我有一个同时运行的代码,每次运行都需要在文件中记录一些内容。每次执行 - 具有独特文件的新故事。

所以,我不能只获取类名的记录器、添加文件附加程序、写入日志、关闭和删除附加程序,因为当并发代码运行时 - 记录器将包含两个附加程序,并且日志将写入两个文件。

所以,我可以为每次执行Logger.getLogger(classname + counter)创建一个新的logger实例,但是工作完成后如何将其标记为垃圾呢?

附:此外......我需要从所有这些记录器中打印出一些东西来控制台。

也许我做错了什么,也许 log4j 不是为此模式创建的,我必须实现它。但是 log4j - 优先选择我,因为它已经在这个大型应用程序中广泛使用。

提前谢谢你,安德烈!

【问题讨论】:

  • 请写一个非常简洁的描述,说明您实际需要做什么。我的直觉是,如果你描述问题,可能会有更好的方法来做你想做的事。
  • 您似乎误解了 log4j 的功能。当您获得类名的记录器时,它实际上只是一个符号,而不是记录器的实例 log4j 自己处理创建和删除记录器。它确实有非常好的异步性能logging.apache.org/log4j/2.x/manual/async.html#Performance
  • 您可以使用dynamic routing,而不是创建/销毁记录器。
  • 好的,假设您有一个 servlet,它运行一些代码,并受 config 支持。大约有 100 种不同的配置。在该配置中,开发人员可以选择文件来查看输出。 @DCTID 不是实例是什么意思?这是。 logger 类的实例,包含一个 appender 列表。您可以使用配置文件或在运行时配置它。

标签: java log4j


【解决方案1】:

You can't 销毁/清理 Appender 实例。但是您可以使用 Log4j2 工具箱改进您的解决方案。

在 Log4j 中将事物路由到动态文件是可能的,但大多数情况下,文件中的 Marker 就足够了,或者至少是更复杂路由的起点。

请阅读其documentation。特别是最后一段对您的情况很重要:

在使用标记时必须考虑一些关于标记的重要规则。

  1. 标记必须是唯一的。它们按名称永久注册,因此应注意确保您的应用程序中使用的标记与应用程序依赖项中的标记不同,除非这是需要的。
  2. 可以动态添加或删除父标记。但是,这样做相当昂贵。相反,建议在第一次获取标记时识别父母,如上例所示。具体来说,set 方法在单个操作中替换所有标记,而 add 和 remove 一次仅作用于单个标记。
  3. 评估具有多个祖先的标记比没有父母的标记要昂贵得多。例如,在一组测试中,评估标记是否与其祖父母匹配的时间是评估标记本身的 3 倍。尽管如此,与解析调用者类名或行号相比,评估 Markers 成本较低。

然后,您可以在配置中预期模式的地方使用标记,如下所示:$${marker:}。虽然我没有在文件名中使用它并且怀疑它是否有效,但您可以基于the Marker 使用create routing

我使用了这个简单的测试脚本,请注意使用为扫描仪的每一行创建的Marker。在您的情况下,它将由 config 或 Servlet 输入或类似创建。

package toTest;

import java.util.Scanner;
import org.apache.logging.log4j.Level;
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 TestMe {
    private final Logger myOneAndOnlyLogger = LogManager.getLogger("MyCentralName");
    public static void main(String[] args) {
        new TestMe().doMyThing();
    }

    private void doMyThing() {
        Scanner input = new Scanner(System.in);
        String line = "";
        while(!line.equals("QUIT")) {
            System.out.println("Line: ");
            line = input.nextLine();
            Marker forThisRound = MarkerManager.getMarker(line);
            myOneAndOnlyLogger.log(Level.ERROR, forThisRound, "1");
            myOneAndOnlyLogger.log(Level.ERROR, forThisRound, "2");
            System.out.println("Line done.");
        }
    }
}

还有这个log4j2.properties(我手头的滚动文件示例,模式中有标记):

status = error
name = MarkerExample

#Make sure to change log file path as per your need
property.filename = /tmp/java/marker.log

filters = threshold

filter.threshold.type = ThresholdFilter
filter.threshold.level = debug

appenders = rolling

appender.rolling.type = RollingFile
appender.rolling.name = RollingFile
appender.rolling.fileName = ${filename}
appender.rolling.filePattern = /tmp/java/debug-backup-%d{MM-dd-yy-HH-mm-ss}-%i.log.gz
appender.rolling.layout.type = PatternLayout
appender.rolling.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} $${marker:} %-5p %c{1}:%L - %m%n
appender.rolling.policies.type = Policies
appender.rolling.policies.time.type = TimeBasedTriggeringPolicy
appender.rolling.policies.time.interval = 1
appender.rolling.policies.time.modulate = true
appender.rolling.policies.size.type = SizeBasedTriggeringPolicy
appender.rolling.policies.size.size=10MBONE
appender.rolling.strategy.type = DefaultRolloverStrategy
appender.rolling.strategy.max = 20

loggers = rolling

#Make sure to change the package structure as per your application

logger.rolling.name = MyCentralName
logger.rolling.level = debug
logger.rolling.additivity = false
logger.rolling.appenderRef.rolling.ref = RollingFile

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-06
    相关资源
    最近更新 更多