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
How to log FATAL (or any custom log level) with SLF4J and Log4j2
提问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 :
这是我和一些同事一起来的最接近的工作解决方案:
- Create a FatalMarker class using SLF4JMarkers.
- Using a RoutingAppender, use the Markeras the routing pattern: "$${marker:}"
- Configure a Fatal-specificappender that has its own PatternLayout that doesn't include the LogLevel but a hardcoded FATAL level.
- 使用SLF4J标记创建致命标记类。
- 使用RoutingAppender,使用Marker作为路由模式: “$${marker:}”
- 配置一个特定于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
Marker
is not really what you want here. Marker
is 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 ERROR
level.
您正在使用logger.error()
which 会将消息记录为ERROR
级别。
If there is no FATAL
level 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 FATAL
log 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.
这是你要做的。
- You copy this code here: https://github.com/apache/logging-log4j2/tree/master/log4j-slf4j-impl
- You then want to edit the
Log4jLogger
class and change the marker methods (trace,error,warn,info, etc) to dispatch appropriately. ieif (marker.contains("FATAL")) fatal(....);
- Exclude the original
log4j-slf4j-impl
from your project and use your new code in place.
- 您在此处复制此代码:https: //github.com/apache/logging-log4j2/tree/master/log4j-slf4j-impl
- 然后,您想要编辑
Log4jLogger
类并更改标记方法(跟踪、错误、警告、信息等)以进行适当的调度。IEif (marker.contains("FATAL")) fatal(....);
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
fatal
is missing. It is not 80/20. Markers are for the 1% andfatal
is 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% 和fatal
99%。 - 许多开发人员认为以某种方式使用标记“致命”会将其映射为致命的。
- 很少有人知道什么是分离标记,包括我自己。
- 与 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 语句(调试和跟踪,当然)。