Java Log4j 2.9.1以编程方式将ThresholdFilter添加到Appender
我对log4j2.9.x有一个严重的问题 我写“严肃”是因为log4j的文档实际上是垃圾! 此版本没有明确的最新文档。即使是现有的文档化代码也无法通过编译器,因为它们时不时地进行破坏性更改,并且您无法确定它们记录了哪个版本。我在谷歌上搜索了一整天,但我发现大部分内容也过时了。Java Log4j 2.9.1以编程方式将ThresholdFilter添加到Appender,java,log4j,log4j2,configure,programmatically,Java,Log4j,Log4j2,Configure,Programmatically,我对log4j2.9.x有一个严重的问题 我写“严肃”是因为log4j的文档实际上是垃圾! 此版本没有明确的最新文档。即使是现有的文档化代码也无法通过编译器,因为它们时不时地进行破坏性更改,并且您无法确定它们记录了哪个版本。我在谷歌上搜索了一整天,但我发现大部分内容也过时了。 因此,我对以编程方式配置log4j2有点困惑 我想要达到的目标: 1) 附加的“日志级别”,总是独立于当前日志级别打印到控制台(模拟gradles生命周期) 2) 登录到控制台和文件 3) 在运行时确定文件名 我找到了一种
因此,我对以编程方式配置log4j2有点困惑 我想要达到的目标: 1) 附加的“日志级别”,总是独立于当前日志级别打印到控制台(模拟gradles生命周期) 2) 登录到控制台和文件 3) 在运行时确定文件名 我找到了一种使用XML实现1)和2)的方法。我还没有找到适合我的方法。我不喜欢对文件名使用静态上下文或系统变量,因为我预期会出现并发问题 因此,我的方法是以编程方式配置log4j。这里是我的配置工厂:
package my.abc
import org.apache.logging.log4j.Level
import org.apache.logging.log4j.core.Filter
import org.apache.logging.log4j.core.LoggerContext
import org.apache.logging.log4j.core.config.Configuration
import org.apache.logging.log4j.core.config.ConfigurationFactory
import org.apache.logging.log4j.core.config.ConfigurationSource
import org.apache.logging.log4j.core.config.Order
import org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder
import org.apache.logging.log4j.core.config.builder.api.LoggerComponentBuilder
import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration
import org.apache.logging.log4j.core.config.plugins.Plugin
@Plugin(name = "CustomConfigurationFactory", category = ConfigurationFactory.CATEGORY)
@Order(50)
class CustomConfigurationFactory extends ConfigurationFactory {
private static String MESSAGE_PATTERN = "%d{HH:mm:ss.SSS} [%t] %-5level 123 %logger{36} - %msg%n"
Level logLevel
String packageToScan
CustomConfigurationFactory(Level logLevel, String packageToScan) {
this.logLevel = logLevel
this.packageToScan = packageToScan
}
private Configuration createConfiguration(final String name, ConfigurationBuilder<BuiltConfiguration> builder) {
builder.setConfigurationName(name)
builder.setStatusLevel(Level.ERROR)
//add appender
builder.add(createConsoleAppender(builder))
builder.add(createLifecycleAppender(builder))
//add logger
builder.add(createLogger(builder))
// builder.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.DENY)
// .addAttribute("level", logLevel))
builder.add(builder.newRootLogger(Level.TRACE).add(builder.newAppenderRef("stdout")))
return builder.build()
}
@Override
Configuration getConfiguration(final LoggerContext loggerContext, final ConfigurationSource source) {
return getConfiguration(loggerContext, source.toString(), null)
}
@Override
Configuration getConfiguration(final LoggerContext loggerContext, final String name, final URI configLocation) {
ConfigurationBuilder<BuiltConfiguration> builder = newConfigurationBuilder()
return createConfiguration(name, builder)
}
@Override
protected String[] getSupportedTypes() {
return [{ "*" }]
}
private AppenderComponentBuilder createConsoleAppender(ConfigurationBuilder<BuiltConfiguration> builder) {
AppenderComponentBuilder appenderBuilder = builder.newAppender("stdout", "CONSOLE")
appenderBuilder.add(builder.newLayout("PatternLayout").
addAttribute("pattern", MESSAGE_PATTERN))
appenderBuilder.add(builder.newFilter("MarkerFilter", Filter.Result.DENY,
Filter.Result.NEUTRAL).addAttribute("marker", "lifecycle"))
// appenderBuilder.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT,
// Filter.Result.DENY).addAttribute("level", logLevel))
return appenderBuilder
}
private AppenderComponentBuilder createLifecycleAppender(ConfigurationBuilder<BuiltConfiguration> builder) {
AppenderComponentBuilder appenderBuilder = builder.newAppender("lifecycle", "CONSOLE")
appenderBuilder.add(builder.newLayout("PatternLayout").
addAttribute("pattern", "%d{HH:mm:ss.SSS} [%t] LIFECYCLE %logger{36} - %msg%n"))
appenderBuilder.add(builder.newFilter("MarkerFilter", Filter.Result.ACCEPT, Filter.Result.DENY)
.addAttribute("marker", "lifecycle"))
return appenderBuilder
}
private LoggerComponentBuilder createLogger(ConfigurationBuilder<BuiltConfiguration> builder) {
builder.newLogger(packageToScan, "trace")
.add(builder.newAppenderRef("stdout"))
.add(builder.newAppenderRef("lifecycle"))
.addAttribute("additivity", false)
}
}
要在这里完成适用于eRequirement1)和2)的整个xml
错误
target/test.log
%d{HH:mm:ss.SSS}[%t]-5级别%logger{36}-%msg%n
%d%p%C{1.}[%t]%m%n
必须有一种方法将ThresholdFilter添加到appender。我找到了ThresholdFilter类。但我完全不知道如何使用它。实例化工作ThresholdFilter.createFilter(…)
但是我可以在哪里添加它
长话短说
如何在没有xml的情况下将ThresholdFilter添加到单个附加器中?供参考
我解决所有需求的方法:
我切换回XML并添加了一些动态属性。某些属性取自系统属性。如果它们不存在,将采用默认值(定义为xml属性)
对属性“logFile”进行特殊查看。它混合了系统属性(用于日志文件的固定路径)和由log4j动态确定的属性。这不是真正的线程安全。但在我们的情况下,这是可以接受的
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info" strict="true" name="XMLConfig"
packages="org.apache.logging.log4j.test">
<Properties>
<Property name="logLevel">INFO</Property>
<Property name="logFileDir">log/</Property>
<Property name="logLevelFile">OFF</Property>
<Property name="logFile">${sys:logFileDir}ConfigMgmt-${date:yyyyMMdd_HHmmss-SSS}.log</Property>
<Property name="packageName">com.hamburgsud</Property>
<Property name="messagePattern">%d{HH:mm:ss.SSS} (Test) %-5level %logger{1.} - %msg%n</Property>
</Properties>
<Appenders>
<!-- Console Logging -->
<Appender type="Console" name="STDOUT">
<Filters>
<Filter type="MarkerFilter" marker="lifecycle" onMatch="DENY" onMismatch="NEUTRAL"/>
<Filter type="ThresholdFilter" level="${sys:logLevel}" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
<Layout type="PatternLayout" pattern="${sys:messagePattern}"/>
</Appender>
<!-- LIFECYCLE is analog to gradles lifecycle log level - means always logging
When the marker for lifecycle-logging is added, the message will always be logged -->
<Appender type="Console" name="LIFECYCLE">
<Filters>
<Filter type="MarkerFilter" marker="lifecycle" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
<Layout type="PatternLayout" pattern="%logger{1.} - %msg%n"/>
</Appender>
<!-- File Logging -->
<Appender type="File" name="FILE" fileName="${sys:logFile}" createOnDemand="true">
<Filters>
<Filter type="MarkerFilter" marker="lifecycle" onMatch="DENY" onMismatch="NEUTRAL"/>
<Filter type="ThresholdFilter" level="${sys:logLevelFile}" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
<Layout type="PatternLayout" pattern="${sys:messagePattern}"/>
</Appender>
<!-- Counterpart to consoles LIFECYCLE logging. When file logging is activated and a log is marked with
lifecycle, the message will be logged to the file too. -->
<Appender type="File" name="FILELIFECYCLE" fileName="${sys:logFile}" createOnDemand="true">
<Filters>
<Filter type="MarkerFilter" marker="lifecycle" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
<Layout type="PatternLayout" pattern="%logger{1.} - %msg%n"/>
</Appender>
</Appenders>
<Loggers>
<Root level="trace" additivity="false">
<AppenderRef ref="STDOUT"/>
<AppenderRef ref="LIFECYCLE"/>
<AppenderRef ref="FILE"/>
<AppenderRef ref="FILELIFECYCLE"/>
</Root>
</Loggers>
</Configuration>
信息
日志/
关
${sys:logFileDir}ConfigMgmt-${date:yyyyymmdd_HHmmss-SSS}.log
汉堡大学
%d{HH:mm:ss.SSS}(测试)%-5级别%logger{1.}-%msg%n
供参考
我解决所有需求的方法:
我切换回XML并添加了一些动态属性。某些属性取自系统属性。如果它们不存在,将采用默认值(定义为xml属性)
对属性“logFile”进行特殊查看。它混合了系统属性(用于日志文件的固定路径)和由log4j动态确定的属性。这不是真正的线程安全。但在我们的情况下,这是可以接受的
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info" strict="true" name="XMLConfig"
packages="org.apache.logging.log4j.test">
<Properties>
<Property name="logLevel">INFO</Property>
<Property name="logFileDir">log/</Property>
<Property name="logLevelFile">OFF</Property>
<Property name="logFile">${sys:logFileDir}ConfigMgmt-${date:yyyyMMdd_HHmmss-SSS}.log</Property>
<Property name="packageName">com.hamburgsud</Property>
<Property name="messagePattern">%d{HH:mm:ss.SSS} (Test) %-5level %logger{1.} - %msg%n</Property>
</Properties>
<Appenders>
<!-- Console Logging -->
<Appender type="Console" name="STDOUT">
<Filters>
<Filter type="MarkerFilter" marker="lifecycle" onMatch="DENY" onMismatch="NEUTRAL"/>
<Filter type="ThresholdFilter" level="${sys:logLevel}" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
<Layout type="PatternLayout" pattern="${sys:messagePattern}"/>
</Appender>
<!-- LIFECYCLE is analog to gradles lifecycle log level - means always logging
When the marker for lifecycle-logging is added, the message will always be logged -->
<Appender type="Console" name="LIFECYCLE">
<Filters>
<Filter type="MarkerFilter" marker="lifecycle" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
<Layout type="PatternLayout" pattern="%logger{1.} - %msg%n"/>
</Appender>
<!-- File Logging -->
<Appender type="File" name="FILE" fileName="${sys:logFile}" createOnDemand="true">
<Filters>
<Filter type="MarkerFilter" marker="lifecycle" onMatch="DENY" onMismatch="NEUTRAL"/>
<Filter type="ThresholdFilter" level="${sys:logLevelFile}" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
<Layout type="PatternLayout" pattern="${sys:messagePattern}"/>
</Appender>
<!-- Counterpart to consoles LIFECYCLE logging. When file logging is activated and a log is marked with
lifecycle, the message will be logged to the file too. -->
<Appender type="File" name="FILELIFECYCLE" fileName="${sys:logFile}" createOnDemand="true">
<Filters>
<Filter type="MarkerFilter" marker="lifecycle" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
<Layout type="PatternLayout" pattern="%logger{1.} - %msg%n"/>
</Appender>
</Appenders>
<Loggers>
<Root level="trace" additivity="false">
<AppenderRef ref="STDOUT"/>
<AppenderRef ref="LIFECYCLE"/>
<AppenderRef ref="FILE"/>
<AppenderRef ref="FILELIFECYCLE"/>
</Root>
</Loggers>
</Configuration>
信息
日志/
关
${sys:logFileDir}ConfigMgmt-${date:yyyyymmdd_HHmmss-SSS}.log
汉堡大学
%d{HH:mm:ss.SSS}(测试)%-5级别%logger{1.}-%msg%n
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info" strict="true" name="XMLConfig"
packages="org.apache.logging.log4j.test">
<Properties>
<Property name="logLevel">INFO</Property>
<Property name="logFileDir">log/</Property>
<Property name="logLevelFile">OFF</Property>
<Property name="logFile">${sys:logFileDir}ConfigMgmt-${date:yyyyMMdd_HHmmss-SSS}.log</Property>
<Property name="packageName">com.hamburgsud</Property>
<Property name="messagePattern">%d{HH:mm:ss.SSS} (Test) %-5level %logger{1.} - %msg%n</Property>
</Properties>
<Appenders>
<!-- Console Logging -->
<Appender type="Console" name="STDOUT">
<Filters>
<Filter type="MarkerFilter" marker="lifecycle" onMatch="DENY" onMismatch="NEUTRAL"/>
<Filter type="ThresholdFilter" level="${sys:logLevel}" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
<Layout type="PatternLayout" pattern="${sys:messagePattern}"/>
</Appender>
<!-- LIFECYCLE is analog to gradles lifecycle log level - means always logging
When the marker for lifecycle-logging is added, the message will always be logged -->
<Appender type="Console" name="LIFECYCLE">
<Filters>
<Filter type="MarkerFilter" marker="lifecycle" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
<Layout type="PatternLayout" pattern="%logger{1.} - %msg%n"/>
</Appender>
<!-- File Logging -->
<Appender type="File" name="FILE" fileName="${sys:logFile}" createOnDemand="true">
<Filters>
<Filter type="MarkerFilter" marker="lifecycle" onMatch="DENY" onMismatch="NEUTRAL"/>
<Filter type="ThresholdFilter" level="${sys:logLevelFile}" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
<Layout type="PatternLayout" pattern="${sys:messagePattern}"/>
</Appender>
<!-- Counterpart to consoles LIFECYCLE logging. When file logging is activated and a log is marked with
lifecycle, the message will be logged to the file too. -->
<Appender type="File" name="FILELIFECYCLE" fileName="${sys:logFile}" createOnDemand="true">
<Filters>
<Filter type="MarkerFilter" marker="lifecycle" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
<Layout type="PatternLayout" pattern="%logger{1.} - %msg%n"/>
</Appender>
</Appenders>
<Loggers>
<Root level="trace" additivity="false">
<AppenderRef ref="STDOUT"/>
<AppenderRef ref="LIFECYCLE"/>
<AppenderRef ref="FILE"/>
<AppenderRef ref="FILELIFECYCLE"/>
</Root>
</Loggers>
</Configuration>