java 如何使用 SLF4J 和 Log4j2 记录 FATAL(或任何自定义日志级别)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30086459/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 16:26:32  来源:igfitidea点击:

How to log FATAL (or any custom log level) with SLF4J and Log4j2

javaslf4jlog4j2

提问by Daniel Marcotte

I have those specific requirements:

我有这些具体要求

  • Need to be able to log in FATALlevel
  • Need to use SLF4J
  • Need to use Log4j2
  • 需要能够登录FATAL级别
  • 需要使用SLF4J
  • 需要使用Log4j2

Right now, here's my implementation:

现在,这是我的实现

final Logger logger = LoggerFactory.getLogger(HelloWorld.class);
final Marker marker = MarkerFactory.getMarker("FATAL");
logger.error(marker, "!!! Fatal World !!!");

Here's my PatternLayout(in yaml):

这是我的PatternLayout (在 yaml 中)

PatternLayout:
  Pattern: "%d{ISO8601_BASIC} %-5level %marker [%t] %logger{3.} - %msg%n"

Here's my log output:

这是我的日志输出

20150506T155705,158 ERROR FATAL [main] - !!! Fatal World !!!

Do you have any idea about how to efficiently to remove the "ERROR" from the log output?

您知道如何有效地从日志输出中删除“错误”吗?

Thank you very much

非常感谢你

采纳答案by Daniel Marcotte

Here's the closest working solution I came with some colleagues :

这是我和一些同事一起来的最接近的工作解决方案:

  1. Create a FatalMarker class using SLF4JMarkers.
  2. Using a RoutingAppender, use the Markeras the routing pattern: "$${marker:}"
  3. Configure a Fatal-specificappender that has its own PatternLayout that doesn't include the LogLevel but a hardcoded FATAL level.
  1. 使用SLF4J标记创建致命标记类。
  2. 使用RoutingAppender,使用Marker作为路由模式: “$${marker:}”
  3. 配置一个特定Fatal 的appender,它有自己的 PatternLayout,它不包含 LogLevel,而是一个硬编码的 FATAL 级别。

Here's the Javasample :

这是Java示例:

Marker fatal = MarkerFactory.getMarker("FATAL");
// Usage example
final Logger logger = LoggerFactory.getLogger(FatalLogger.class);
logger.log(fatal, "this is a fatal message");

// Log sample : 
20150514T115144,279  FATAL [main] FatalLogger - this is a fatal message

Here's the YAMLsample :

这是YAML示例:

Configuration:
  status: debug

  Appenders:
    RandomAccessFile:
      - name: APPLICATION_APPENDER
        fileName: logs/application.log
        PatternLayout:
          Pattern: "%d{ISO8601_BASIC} %-5level %msg%n"
      - name: FATAL_APPENDER
        fileName: logs/application.log
        PatternLayout:
          Pattern: "%d{ISO8601_BASIC} FATAL %msg%n"

    Routing:
      name: ROUTING_APPENDER
      Routes:
        pattern: "$${marker:}"
        Route:
        - key: FATAL
          ref: FATAL_APPENDER
        - ref: APPLICATION_APPENDER #DefaultRoute

  Loggers:
    Root:
      level: trace
      AppenderRef:
        - ref: ROUTING_APPENDER

回答by SnakeDoc

Markeris not really what you want here. Markeris for "enriching" log messages, making them more easily searchable. You are trying to change the log level/priority, which is a little different.

Marker在这里并不是你真正想要的。Marker用于“丰富”日志消息,使它们更易于搜索。您正在尝试更改日志级别/优先级,这有点不同。

You're using logger.error()which will log the message as an ERRORlevel.

您正在使用logger.error()which 会将消息记录为ERROR级别。

If there is no FATALlevel pre-defined (usually there is, such as logger.fatal()), then use the generic logger.log()which allows you to specify the log level.

如果没有FATAL预定义级别(通常有,例如logger.fatal()),则使用logger.log()允许您指定日志级别的泛型。

logger.fatal(yourMessage);

OR

或者

logger.log(priorityLevel, yourMessage);

UPDATE:

更新:

From the SLF4J website:

从 SLF4J 网站:

The Marker interface, part of the org.slf4j package, renders the FATAL level largely redundant. If a given error requires attention beyond that allocated for ordinary errors, simply mark the logging statement with a specially designated marker which can be named "FATAL" or any other name to your liking.

Marker 接口是 org.slf4j 包的一部分,使 FATAL 级别在很大程度上是多余的。如果给定的错误需要注意超出为普通错误分配的注意力,只需使用专门指定的标记标记日志语句,该标记可以命名为“FATAL”或您喜欢的任何其他名称。

http://www.slf4j.org/faq.html#fatal

http://www.slf4j.org/faq.html#fatal

So, with SLF4J, it is not possible to have a FATALlog level. I strongly disagree with the rationale behind this decision, but it is what it is.

因此,对于 SLF4J,不可能有FATAL日志级别。我强烈不同意这个决定背后的理由,但事实就是如此。

回答by thebiggestlebowski

I know the question is for log4j. I found this page when looking in relation to logback. Here's what sl4j recommends: https://www.slf4j.org/faq.html#fatal.

我知道问题是针对 log4j 的。在查看与 logback 相关的内容时,我发现了此页面。以下是 sl4j 推荐的内容:https://www.slf4j.org/faq.html#fatal 。

回答by Adam Gent

Here is what I did for log4jwhich I also recommend for log4j2....

这是我为log4j所做的,我也推荐用于log4j2....

Write your own custom slf4j static binder aka bridge.This requires a little work but is well worth it for a variety of complicated reasons 1that I will blog about one day.

编写您自己的自定义 slf4j 静态绑定器又名桥。这需要一些工作,但由于各种复杂的原因1非常值得,我将在大约某一天写博客。

Here is what you do.

这是你要做的。

  1. You copy this code here: https://github.com/apache/logging-log4j2/tree/master/log4j-slf4j-impl
  2. You then want to edit the Log4jLoggerclass and change the marker methods (trace,error,warn,info, etc) to dispatch appropriately. ie if (marker.contains("FATAL")) fatal(....);
  3. Exclude the original log4j-slf4j-implfrom your project and use your new code in place.
  1. 您在此处复制此代码:https: //github.com/apache/logging-log4j2/tree/master/log4j-slf4j-impl
  2. 然后,您想要编辑Log4jLogger类并更改标记方法(跟踪、错误、警告、信息等)以进行适当的调度。IEif (marker.contains("FATAL")) fatal(....);
  3. log4j-slf4j-impl从您的项目中排除原始代码并就地使用新代码。

<soap-box-rant>

<肥皂盒咆哮>

I honestly think slf4j is severely flawed because

老实说,我认为 slf4j 存在严重缺陷,因为

  • it makes it very difficult/impossible to override hardcore static initialization along with also not providing logger.fatal(...).
  • Markers are not needed and are inherently complex:
    • Very very very few projects use markers. I actually looked/grepped open source projects and marker usage is close to zero low.
    • The ones that use marker are because fatalis missing. It is not 80/20. Markers are for the 1% and fatalis for the 99%.
    • Many developers think that somehow using the marker "fatal" will map it to fatal.
    • Few know what a detached marker is including myself.
    • There is overlap with what the MDC context provides. Given event dimension oriented databases (elasticsearch, druid, etc) the MDC context is superior (name/value pair).
  • 这使得覆盖核心静态初始化以及不提供logger.fatal(...).
  • 标记不是必需的,并且本质上很复杂:
    • 很少有项目使用标记。我实际上查看了/grepped 开源项目,并且标记使用率接近于零。
    • 使用标记的那些是因为fatal丢失了。它不是 80/20。标记适用于 1% 和fatal99%。
    • 许多开发人员认为以某种方式使用标记“致命”会将其映射为致命的。
    • 很少有人知道什么是分离标记,包括我自己
    • 与 MDC 上下文提供的内容有重叠。给定面向事件维度的数据库(elasticsearch、druid 等),MDC 上下文是优越的(名称/值对)。

</soap-box-rant>

</soap-box-rant>

1one of them being able to actually be part of the boot process of your logging framework opposed to hard to determine almost arbitrary static initialization

1其中之一实际上能够成为日志框架启动过程的一部分,而不是难以确定几乎任意的静态初始化

回答by Daniel Marcotte

The only solution I've found so far is to use have 5 markers :

到目前为止,我发现的唯一解决方案是使用有 5 个标记:

final Marker traceMarker = MarkerFactory.getMarker("TRACE");
final Marker debugMarker = MarkerFactory.getMarker("DEBUG");
final Marker infoMarker = MarkerFactory.getMarker("INFO");
final Marker warnMarker = MarkerFactory.getMarker("WARN");
final Marker errorMarker = MarkerFactory.getMarker("ERROR");
final Marker fatalMarker = MarkerFactory.getMarker("FATAL");

And log passing the marker everytime :

并记录每次传递标记:

logger.info(infoMarker, "!!! INFO World !!!");
logger.error(errorMarker, "!!! ERROR World !!!");
logger.error(fatalMarker, "!!! FATAL World !!!");

And modify the PatternLayoutto totally remove the LogLeveland always log the Marker, such as :

并修改PatternLayout以完全删除LogLevel并始终记录 Marker,例如:

PatternLayout:
  Pattern: "%d{ISO8601_BASIC} %marker [%t] %logger{3.} - %msg%n"

I kind of think this solution is a hack... It would also remove the log level of any external library using the LogLevel the right way.

我有点认为这个解决方案是一个黑客......它还会以正确的方式使用 LogLevel 删除任何外部库的日志级别。

Summary: This solution isn't a good solution.

摘要:此解决方案不是一个好的解决方案。

UPDATE: I tried another solution, writing a RewritePolicy :

更新:我尝试了另一种解决方案,编写了 RewritePolicy :

public class FatalRewritePolicy implements RewritePolicy {

    public static final String FATAL = "FATAL";

    @Override
    public LogEvent rewrite(final LogEvent logEvent) {

        final Marker marker = logEvent.getMarker();
        if (marker == null)
            return logEvent;

        // Log Level is final in the LogEvent, there's no way we can modify it.
        Level level = logEvent.getLevel();

        return null;
    }
}

There seems to be no way to change the LogLevel of a LogEvent in Log4j2(which make sense).

似乎无法更改Log4j2 中LogEvent 的 LogLevel (这是有道理的)。

Summary: Still no solution.

总结:还是没有解决办法。

回答by thebiggestlebowski

You could add "FATAL" at the beginning of your message. For example:

您可以在消息的开头添加“FATAL”。例如:

LOGGER.error("FATAL: database connection lost.");

You do lose some things, like filtering based on level, but this may be ok for many people, especially since you're unlikely to filter out FATAL statements (debug and trace, sure).

你确实会丢失一些东西,比如基于级别的过滤,但这对很多人来说可能没问题,特别是因为你不太可能过滤掉 FATAL 语句(调试和跟踪,当然)。