diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/OrderComparator.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/OrderComparator.java index 94cb694f018..e0970f06c8b 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/OrderComparator.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/OrderComparator.java @@ -18,9 +18,11 @@ import java.util.Comparator; import java.util.Objects; +import java.util.OptionalInt; +import org.apache.logging.log4j.plugins.internal.util.AnnotationUtil; /** - * Comparator for classes annotated with {@link Order}. + * Comparator for classes annotated with {@link Order} or {@link org.apache.logging.log4j.plugins.Ordered}. * * @since 2.1 */ @@ -39,20 +41,32 @@ public static Comparator> getInstance() { @Override public int compare(final Class lhs, final Class rhs) { - final Order lhsOrder = Objects.requireNonNull(lhs, "lhs").getAnnotation(Order.class); - final Order rhsOrder = Objects.requireNonNull(rhs, "rhs").getAnnotation(Order.class); - if (lhsOrder == null && rhsOrder == null) { + Objects.requireNonNull(lhs, "lhs"); + Objects.requireNonNull(rhs, "rhs"); + final OptionalInt lhsOrder = getOrder(lhs); + final OptionalInt rhsOrder = getOrder(rhs); + if (lhsOrder.isEmpty() && rhsOrder.isEmpty()) { // both unannotated means equal priority return 0; } - // if only one class is @Order-annotated, then prefer that one - if (rhsOrder == null) { + // if only one class is annotated, then prefer that one + if (rhsOrder.isEmpty()) { return -1; } - if (lhsOrder == null) { + if (lhsOrder.isEmpty()) { return 1; } - // larger value means higher priority - return Integer.signum(rhsOrder.value() - lhsOrder.value()); + // larger value means higher priority (descending order) + return Integer.signum(rhsOrder.getAsInt() - lhsOrder.getAsInt()); + } + + private static OptionalInt getOrder(final Class clazz) { + // Check for legacy @Order annotation first + final Order order = clazz.getAnnotation(Order.class); + if (order != null) { + return OptionalInt.of(order.value()); + } + // Fall back to @Ordered via AnnotationUtil + return AnnotationUtil.getOrder(clazz); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/json/JsonConfigurationFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/json/JsonConfigurationFactory.java index 048b0a9f623..b5888ee258c 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/json/JsonConfigurationFactory.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/json/JsonConfigurationFactory.java @@ -20,13 +20,13 @@ 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.plugins.Namespace; +import org.apache.logging.log4j.plugins.Ordered; import org.apache.logging.log4j.plugins.Plugin; @Namespace(ConfigurationFactory.NAMESPACE) @Plugin("JsonConfigurationFactory") -@Order(6) +@Ordered(6) public class JsonConfigurationFactory extends ConfigurationFactory { /** diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfigurationFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfigurationFactory.java index 0e75d5cc201..122ed4de489 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfigurationFactory.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfigurationFactory.java @@ -20,8 +20,8 @@ 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.plugins.Namespace; +import org.apache.logging.log4j.plugins.Ordered; import org.apache.logging.log4j.plugins.Plugin; /** @@ -29,7 +29,7 @@ */ @Namespace(ConfigurationFactory.NAMESPACE) @Plugin("XmlConfigurationFactory") -@Order(5) +@Ordered(5) public class XmlConfigurationFactory extends ConfigurationFactory { /** diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/RequiredClass.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/RequiredClass.java index c2a329c8c66..5f6ca8bbccc 100644 --- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/RequiredClass.java +++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/RequiredClass.java @@ -25,7 +25,7 @@ import org.apache.logging.log4j.plugins.validation.validators.RequiredClassValidator; /** - * Marks a plugin builder field or plugin factory parameter as required. + * Requires that a given class be available. * * @since 3.0.0 */ diff --git a/src/site/antora/modules/ROOT/examples/manual/customconfig/ConfigurationBuilder/log4j2.json b/src/site/antora/modules/ROOT/examples/manual/customconfig/ConfigurationBuilder/log4j2.json new file mode 100644 index 00000000000..5ad06b4cd60 --- /dev/null +++ b/src/site/antora/modules/ROOT/examples/manual/customconfig/ConfigurationBuilder/log4j2.json @@ -0,0 +1,18 @@ +{ + "Configuration": { + "Appenders": { + "Console": { + "name": "CONSOLE", + "JsonTemplateLayout": {} + } + }, + "Loggers": { + "Root": { + "level": "WARN", + "AppenderRef": { + "ref": "CONSOLE" + } + } + } + } +} diff --git a/src/site/antora/modules/ROOT/examples/manual/customconfig/ConfigurationBuilder/log4j2.properties b/src/site/antora/modules/ROOT/examples/manual/customconfig/ConfigurationBuilder/log4j2.properties new file mode 100644 index 00000000000..bd45ad2d7b2 --- /dev/null +++ b/src/site/antora/modules/ROOT/examples/manual/customconfig/ConfigurationBuilder/log4j2.properties @@ -0,0 +1,22 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to you under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +appender.0.type = Console +appender.0.name = CONSOLE +appender.0.layout.type = JsonTemplateLayout + +rootLogger.level = WARN +rootLogger.appenderRef.0.ref = CONSOLE diff --git a/src/site/antora/modules/ROOT/examples/manual/customconfig/ConfigurationBuilder/log4j2.xml b/src/site/antora/modules/ROOT/examples/manual/customconfig/ConfigurationBuilder/log4j2.xml new file mode 100644 index 00000000000..3acc82eb214 --- /dev/null +++ b/src/site/antora/modules/ROOT/examples/manual/customconfig/ConfigurationBuilder/log4j2.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + diff --git a/src/site/antora/modules/ROOT/examples/manual/customconfig/ConfigurationBuilder/log4j2.yaml b/src/site/antora/modules/ROOT/examples/manual/customconfig/ConfigurationBuilder/log4j2.yaml new file mode 100644 index 00000000000..a46826acd48 --- /dev/null +++ b/src/site/antora/modules/ROOT/examples/manual/customconfig/ConfigurationBuilder/log4j2.yaml @@ -0,0 +1,28 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to you under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +Configuration: + + Appenders: + Console: + name: "CONSOLE" + JsonTemplateLayout: {} + + Loggers: + Root: + level: "WARN" + AppenderRef: + ref: "CONSOLE" diff --git a/src/site/antora/modules/ROOT/examples/manual/customconfig/ExampleConfiguration.java b/src/site/antora/modules/ROOT/examples/manual/customconfig/ExampleConfiguration.java new file mode 100644 index 00000000000..5d8a00b4241 --- /dev/null +++ b/src/site/antora/modules/ROOT/examples/manual/customconfig/ExampleConfiguration.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.AppenderRef; +import org.apache.logging.log4j.core.config.ConfigurationSource; +import org.apache.logging.log4j.core.config.LoggerConfig; + +public class ExampleConfiguration extends XmlConfiguration { + + public ExampleConfiguration(LoggerContext loggerContext, ConfigurationSource configSource) { + super(loggerContext, configSource); + } + + @Override + protected void doConfigure() { + Appender appender = createAppender("ExampleAppender"); + appender.start(); + addAppender(appender); + LoggerConfig loggerConfig = LoggerConfig.newBuilder() + .withConfig(this) + .withAdditivity(false) + .withLevel(Level.INFO) + .withLoggerName("com.example") + .withRefs(new AppenderRef[] {AppenderRef.createAppenderRef("ExampleAppender", null, null)}) + .build(); + loggerConfig.addAppender(appender, null, null); + addLogger("com.example", loggerConfig); + } +} diff --git a/src/site/antora/modules/ROOT/examples/manual/customconfig/ExampleConfigurationFactory.java b/src/site/antora/modules/ROOT/examples/manual/customconfig/ExampleConfigurationFactory.java new file mode 100644 index 00000000000..8b8b9e52315 --- /dev/null +++ b/src/site/antora/modules/ROOT/examples/manual/customconfig/ExampleConfigurationFactory.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example; + +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.plugins.Namespace; +import org.apache.logging.log4j.plugins.Ordered; +import org.apache.logging.log4j.plugins.Plugin; + +// tag::class[] +@Ordered(100) +@Namespace(ConfigurationFactory.NAMESPACE) +@Plugin(name = "ExampleConfigurationFactory") +public class ExampleConfigurationFactory extends ConfigurationFactory { + + @Override + public Configuration getConfiguration(LoggerContext loggerContext, ConfigurationSource source) { // <1> + // Return a `Configuration`... + } + + @Override + public Configuration getConfiguration(LoggerContext loggerContext, String name, URI configLocation) { + // Return a `Configuration`... + } + + @Override + public String[] getSupportedTypes() { + return new String[] {"*"}; + } +} +// end::class[] diff --git a/src/site/antora/modules/ROOT/examples/manual/customconfig/Usage.java b/src/site/antora/modules/ROOT/examples/manual/customconfig/Usage.java new file mode 100644 index 00000000000..bdd5dd6772c --- /dev/null +++ b/src/site/antora/modules/ROOT/examples/manual/customconfig/Usage.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example; + +import java.net.URI; +import java.util.Arrays; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.AbstractConfiguration; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.ConfigurationFactory; +import org.apache.logging.log4j.core.config.Configurator; +import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder; +import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory; +import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration; +import org.apache.logging.log4j.core.config.composite.CompositeConfiguration; + +final class Usage { + + private static Configuration createConfiguration() { + // tag::createConfiguration[] + ConfigurationBuilder configBuilder = + ConfigurationBuilderFactory.newConfigurationBuilder(); // <1> + Configuration configuration = configBuilder + .add( + configBuilder // <2> + .newAppender("CONSOLE", "List") + .add(configBuilder.newLayout("JsonTemplateLayout"))) + .add( + configBuilder // <3> + .newRootLogger(Level.WARN) + .add(configBuilder.newAppenderRef("CONSOLE"))) + .build(false); // <4> + // end::createConfiguration[] + } + + private static void useConfiguration() { + // tag::useConfiguration[] + Configuration configuration = createConfiguration(); + try (LoggerContext loggerContext = Configurator.initialize(configuration)) { + // Use `LoggerContext`... + } + // end::useConfiguration[] + } + + private static void reconfigureActiveLoggerContext() { + // tag::reconfigureActiveLoggerContext[] + Configuration configuration = createConfiguration(); + Configurator.reconfigure(configuration); + // end::reconfigureActiveLoggerContext[] + } + + private static Configuration loadConfigurationFile() { + // tag::loadConfigurationFile[] + ConfigurationFactory.getInstance() + .getConfiguration( + null, // <1> + null, // <2> + URI.create("uri://to/my/log4j2.xml")); // <3> + // end::loadConfigurationFile[] + } + + private static Configuration combineConfigurations() { + // tag::combineConfigurations[] + ConfigurationFactory configFactory = ConfigurationFactory.getInstance(); + AbstractConfiguration commonConfig = (AbstractConfiguration) // <2> + configFactory.getConfiguration(null, null, URI.create("classpath:log4j2-common.xml")); // <1> + AbstractConfiguration appConfig = (AbstractConfiguration) // <2> + configFactory.getConfiguration(null, null, URI.create("classpath:log4j2-app.xml")); // <1> + AbstractConfiguration runtimeConfig = ConfigurationBuilderFactory.newConfigurationBuilder() + // ... + .build(false); // <3> + return new CompositeConfiguration(Arrays.asList(commonConfig, appConfig, runtimeConfig)); // <4> + // end::combineConfigurations[] + } +} diff --git a/src/site/antora/modules/ROOT/images/Log4jClasses.jpg b/src/site/antora/modules/ROOT/images/Log4jClasses.jpg deleted file mode 100755 index ea16084bd68..00000000000 Binary files a/src/site/antora/modules/ROOT/images/Log4jClasses.jpg and /dev/null differ diff --git a/src/site/antora/modules/ROOT/pages/articles.adoc b/src/site/antora/modules/ROOT/pages/articles.adoc deleted file mode 100644 index bf1d3255f23..00000000000 --- a/src/site/antora/modules/ROOT/pages/articles.adoc +++ /dev/null @@ -1,145 +0,0 @@ -//// -Licensed to the Apache Software Foundation (ASF) under one or more - contributor license agreements. See the NOTICE file distributed with - this work for additional information regarding copyright ownership. - The ASF licenses this file to You under the Apache License, Version 2.0 - (the "License"); you may not use this file except in compliance with - the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -//// -= Articles and Tutorials - -A collection of external articles and tutorials about Log4j 2. -The xref:manual/index.adoc[Log4j 2 manual] is the ultimate guide for up-to-date and detailed information on how to configure and use Log4j 2. - -== Chinese - -* https://www.infoq.cn/news/2016/06/log4j-garbage-free/[Log4j 2.6免垃圾收集] (June 12, 2016) -* https://blog.csdn.net/autfish/article/details/51203709[详解log4j2(上) - 从基础到实战] (April 20, 2016) -* https://www.jianshu.com/p/7aec512a003c[Log4j2使用笔记] (November 3, 2015) -* https://www.infoq.cn/news/2015/09/interview-log4j-pmc/[过渡到全新Log4j:Log4j项目管理委员会访谈] (September 14, 2015) -* https://www.infoq.cn/news/2015/09/log4j-version-1-reaches-eol/[Log4j版本1生命周期终结] (September 3, 2015) -* https://www.infoq.cn/news/2014/08/apache-log4j2/[Apache Log4j 2.0值得升级吗] (August 5, 2014) -* https://blog.csdn.net/lrenjun/article/details/8178875[log4j2 使用详解] (November 13, 2012) -* https://web.archive.org/web/20211016221310/https://my.oschina.net/xianggao/blog/523401[Log4j2配置文件详解] (October 29, 2015) - -== English - -* https://medium.com/codex/log4j2-create-custom-log-levels-and-how-to-use-them-48685e133fd1[Log4J2 | Create custom log levels and how to use them] (April 29, 2021) -* http://makeseleniumeasy.com/2021/04/26/log4j2-tutorial-7-working-mechanism-of-default-rollover-strategy/[Log4j2 Tutorial 7 -- Working Mechanism Of Default Rollover Strategy] (April 26, 2021) -* http://makeseleniumeasy.com/2021/04/20/log4j2-tutorial-6-introduction-to-rollingfileappender-and-its-triggers-and-strategies/[Log4j2 Tutorial 6 -- Introduction To RollingFileAppender And Its Triggers And Strategies] (April 20, 2021) -* http://makeseleniumeasy.com/2021/04/13/log4j2-tutorial-5-xml-configuration-file-to-log-into-file-and-console-using-log4j2-together/[Log4j2 Tutorial 5 -- XML Configuration File To Log Into File And Console Using Log4j2 Together] (April, 13, 2021) -* http://makeseleniumeasy.com/2021/04/09/log4j2-tutorial-4-print-logs-in-external-file-using-xml-configuration-file-of-log4j2/[Log4j2 Tutorial 4 -- Print Logs In External File Using XML Configuration File Of Log4J2] (April 9, 2021) -* http://makeseleniumeasy.com/2021/03/24/log4j2-tutorial-3-setup-console-appender-using-xml-configuration-file/[Log4j2 Tutorial 3 -- Setup Console Appender Using XML Configuration File] (March 24, 2021) -* http://makeseleniumeasy.com/2021/03/17/log4j2-tutorial-2-creating-log4j2-maven-project-with-default-configuration-file/[Log4j2 Tutorial 2 -- Creating Log4j2 Maven Project With Default Configuration File] (March 17, 2021) -* http://makeseleniumeasy.com/2021/03/11/log4j2-tutorial-1-introduction-to-apache-log4j2/[Log4j2 Tutorial 1 -- Introduction To Apache Log4j2] (March 11, 2021) -* https://petrepopescu.tech/2021/03/how-to-make-a-custom-message-converter-for-log4j2/[How to make a custom message converter for Log4J2] (March 4, 2021) -* http://www.mastertheboss.com/jbossas/jboss-log/how-to-use-log4j2-in-your-wildfly-applications/[How to configure Log4j2 in your WildFly applications] (August 16, 2020) -* http://www.masterspringboot.com/configuration/logging/configuring-log4j2-in-spring-boot-applications[Configuring Log4j2 in a Spring Boot 2 application] (August 16, 2020) -* https://www.ralphgoers.com/post/getting-the-most-out-of-the-log4j-2-api[Getting the most out of the Log4j 2 API] (January 1, 2020) -* https://www.baeldung.com/log4j2-programmatic-config[Programmatic Configuration with Log4j 2] (December 31, 2019) -* https://www.ralphgoers.com/post/log4j-1-compatibility-in-log4j-2[Log4j 1 Compatibility in Log4j 2] (December 22, 2019) -* https://www.ralphgoers.com/post/why-was-log4j-2-created[Why was Log4j 2 created] (December 14, 2019) -* https://www.marcobehler.com/guides/java-logging[A Guide to Logging in Java] (June 23, 2019) -* https://www.alibabacloud.com/blog/exploring-the-secrets-of-java-logs-log4j-2-log-system_594821[Exploring the Secrets of Java Logs: Log4j 2 Log System] (May 17, 2019) -* https://mkyong.com/logging/apache-log4j-2-tutorials/[Apache Log4j 2 Tutorials] (March 27, 2019) -* https://stackify.com/compare-java-logging-frameworks/[Java Logging Frameworks: log4j vs logback vs log4j2] (October 30, 2018) -* https://howtodoinjava.com/log4j2/[Log4j2 Tutorial] (June 3, 2018) -* https://crunchify.com/java-how-to-create-your-own-logging-level-in-log4j-configuring-log4j/[In Java How to Create your own Logging Level using Log4j (Configuring Log4j 2)] {May 30, 2018) -* https://www.baeldung.com/log4j2-programmatic-config[Programmatic Configuration with Log4j 2] (May 22, 2018) -* https://www.javacodegeeks.com/2018/03/tales-from-the-field-migrating-from-log4j-to-log4j2.html[Tales from the Field: Migrating from Log4J to Log4J2] (March 12, 2018) -* https://examples.javacodegeeks.com/enterprise-java/log4j/log4j-2-best-practices-example/[Log4j 2 Best Practices example] (November 14, 2017) -* https://web.archive.org/web/20180308003803/http://musigma.org/logging/2017/11/06/logging.html[Logging Fundamentals] (November 6, 2017) -* http://www.rationaljava.com/2017/10/allocation-free-logging-with-log4j2.html[Allocation free logging with Log4j2] (October 27, 2017) -* https://www.loggly.com/blog/benchmarking-java-logging-frameworks/[Benchmarking Java logging frameworks] (October 25, 2017) -* https://www.baeldung.com/log4j-2-lazy-logging[Log4j 2 and Lambda Expressions] (August 22, 2017) -* https://www.callicoder.com/spring-boot-log4j-2-example/[How to use Log4j 2 with Spring Boot] (August 11, 2017) -* https://www.boraji.com/log4j-2-rollingfileappender-example[Log4j 2 - RollingFileAppender example] (July 26, 2017) -* https://stackify.com/log4j2-java/[How Log4J2 Works: 10 Ways to Get the Most Out Of It] (June 14, 2017) -* https://www.baeldung.com/log4j2-appenders-layouts-filters[Intro to Log4j2 -- Appenders, Layouts and Filters] (February 28, 2017) -* https://dzone.com/articles/getting-own-log4j2-file-for-mule-via-spring[Getting Your Own Log4j2 File for Mule via Spring] (December 29, 2016) -* https://garygregory.wordpress.com/2016/11/27/loading-a-log4j-configuration-for-a-specific-ejb/[Loading a Log4j Configuration for a specific EJB] (November 27, 2016) -* https://anishekagarwal.medium.com/log4j2-logging-a-primer-f10ed18e9de6[Log4j2 Logging: A Primer] (October 15, 2016) -* https://www.digitalocean.com/community/tutorials/log4j2-example-tutorial-configuration-levels-appenders[Log4j2 Example Tutorial -- Configuration, Levels, Appenders] (July 6, 2016) -* https://howtodoinjava.com/log4j2/log4j2-htmllayout-configuration-example/[Log4j2 HTMLLayout Configuration Example] (June 27, 2016) -* https://javaevangelist.blogspot.com/2016/06/log4j2-javautillogging-jul-adapter.html[Log4j2 java.util.logging (JUL) Adapter Example] (June 24, 2016) -* https://dzone.com/articles/log4j-2-configuration-using-properties-file[Log4J 2 Configuration: Using the Properties File] (May 18, 2016) -* https://springframework.guru/using-log4j-2-spring-boot/[Using Log4j 2 with Sprint Boot] (April 7, 2016) -* https://www.infoq.com/news/2016/05/log4j-garbage-free/[Log4j 2.6 Goes Garbage-Free] (May 30, 2016) -* https://web.archive.org/web/20180306104946/http://musigma.org/java/log4j/2016/05/29/log4j-2.6.html[What's New in Log4j 2.6] (May 29, 2016) -* https://springframework.guru/asynchronous-logging-with-log4j-2/[Asynchronous Logging With Log4j 2] (March 31, 2016) -* https://springframework.guru/log4j-2-configuration-using-yaml/[Log4J 2 Configuration: Using YAML] (March 26, 2016) -* https://springframework.guru/log4j-2-configuration-using-json/[Log4J 2 Configuration: Using JSON] (March 23, 2016) -* https://web.archive.org/web/20220315041422/https://qbox.io/blog/getting-logstash-2x-ready-for-log4j2[Getting Logstash 2.x Ready for Log4j2] (March 10, 2016) -* https://springframework.guru/log4j-2-configuration-using-xml/[Log4J 2 Configuration: Using XML] (March 10, 2016) -* https://springframework.guru/log4j-2-configuration-using-properties-file/[Log4J 2 Configuration: Using Properties File] (March 8, 2016) -* https://springframework.guru/introducing-log4j-enterprise-class-logging/[Introducing Log4j 2 -- Enterprise Class Logging] (February 8, 2016) -* https://www.javacodegeeks.com/2015/10/better-performing-non-logging-logger-calls-in-log4j2.html[Better Performing Non-Logging Logger Calls in Log4j2] (October 20, 2015) -* https://marxsoftware.blogspot.com/2015/10/log4j2-non-logging-performance.html[Better Performing Non-Logging Logger Calls in Log4j2] (October 15, 2015) -* https://www.javacodegeeks.com/2015/10/easy-and-consistent-log4j2-logger-naming.html[Easy and Consistent Log4j2 Logger Naming] (October 10, 2015) -* https://garygregory.wordpress.com/2015/09/16/a-gentle-introduction-to-the-log4j-api-and-lambda-basics/[Writing clean logging code using Java 8 lambdas] (September 16, 2015) -* https://garygregory.wordpress.com/2015/09/10/the-art-of-test-driven-development-understanding-logging/[The Art of Test Driven Development: Understanding Logging] (September 10, 2015) -* https://garygregory.wordpress.com/2015/09/08/the-art-of-test-driven-development-per-test-logging/[The Art of Test Driven Development: Per-Test Logging] (September 8, 2015) -* https://www.infoq.com/news/2015/09/interview-log4j-pmc/[The Transition to a New Log4j: a Q&A with Log4j's Project Management Committee] (September 8, 2015) -* https://www.infoq.com/news/2015/08/log4j-version-1-reaches-eol/[Log4j Version 1 Reaches End of Life] (August 26, 2015) -* https://news.apache.org/foundation/entry/apache_logging_services_project_announces[Apache Logging Services Project Announces Log4j 1 End-Of-Life; -Recommends Upgrade to Log4j 2] (August 6, 2015) -* https://www.innoq.com/en/blog/per-request-debugging-with-log4j2/[Per request debugging with Log4j 2 filters] (May 8, 2015) -* https://blog.oio.de/2015/04/27/log4j-2-configuration-depending-environment/[Log4j 2 configuration depending on environment] (April 27, 2015) -* http://www.journaldev.com/7128/apache-log4j-2-tutorial-configuration-levels-appenders-lookup-layouts-and-filters-example[Apache Log4j 2 Tutorial -- Configuration, Levels, Appenders, Lookup, Layouts and Filters Example] (March 16, 2015) -* https://blogs.mulesoft.com/dev-guides/how-to-tutorials/mule-3-6-asynchronous-logging/[Disrupting your Asynchronous Loggers] (March 5, 2015) -* https://andrew-flower.com/blog/Create_Custom_Log4j_Plugins[Extending Log4j2 - Creating Custom Log4j2 Plugins] (February 20, 2015) -* https://andrew-flower.com/blog/Basic_Log4j2_Configuration[Log4j2 - a crash course...] (February 10, 2015) -* https://memorynotfound.com/log4j2-with-log4j2-xml-configuration-example/[Log4j2 with log4j2.xml Configuration Example] (February 10, 2015) -* https://www.rapid7.com/blog/post/2015/02/05/logging-from-your-java-application-using-log4j2/[Logging From Your Java Application Using Log4j2] (February 5, 2015) -* https://blogs.mulesoft.com/dev-guides/how-to-tutorials/mule-3-6-asynchronous-logging/[Asynchronous Logging in Mule 3.6] (January 20, 2015) -* https://www.infoq.com/news/2014/07/apache-log4j2/[Apache Log4j 2.0 - Worth the Upgrade?] (July 31, 2014) -* https://mycuteblog.com/log4j2-xml-configuration-example/[log4j2 xml configuration example] (July 26, 2014) -* https://tech.finn.no/2014/07/01/log4j2-in-production-making-it-fly/[Log4j 2 in Production -- Making it Fly] (July 2, 2014) -* https://grobmeier.solutions/log4j-2-performance-close-to-insane-20072013.html[Log4j 2: Performance Close to Insane] (July 20, 2013) -* https://news.ycombinator.com/item?id=5612035[Hacker News: Asynchronous Loggers for Low-Latency Logging] (April 26, 2013) -* https://grobmeier.solutions/the-new-log4j-2-0-05122012.html[The New Log4j 2.0] (December 5, 2012) - -== English (Videos) - -* https://www.youtube.com/watch?v=sdOiA1Xql0o[Log4J2 and Java configuration with properties file] (February 18, 2018) -* https://www.youtube.com/watch?v=BbcSNOtEGWs[Apache Log4j 2 Configuration| Log4j2 with JDK 9.0] (January 8, 2018) -* https://www.youtube.com/watch?v=KKO5wGi_vEc[Spring Boot - log4j 2 configuration example] (December 30,2017) -* https://www.youtube.com/watch?v=-XNvCNHjIKw[Understanding and working with Log4j2 for logging in Selenium framework (Part B)] (December 20, 2016) -* https://www.youtube.com/watch?v=RWZ0gsfkkc4[Understanding and working with Log4j2 for logging in Selenium framework (Part A)] (December 18, 2016) -* https://vimeo.com/169542136[Matt Sicker - Asynchronous Logging in Log4j 2.6 (CJUG Lightning Talk)] (June 2, 2016) - ** Errata: "ThresholdFilter" should be "BurstFilter" -* https://www.youtube.com/watch?v=Yv0n-4AsOiI[Nancy M Schorr - Log4j2 with Java and Maven for Logging] (October 14, 2015) -* https://www.youtube.com/watch?v=EWftNoRhS_M[Ramesh Rajaram - Log4j Key Features] (April 10, 2015) -* https://www.youtube.com/watch?v=ZzVSs_JEhgs[Matt Sicker - Introducing Log4j 2.0] (May 6, 2014) -* https://www.youtube.com/watch?v=HB0r5DuxGPI[Nicholas Williams - Log4j 2 in Web Applications: A Deeper Look at Effective Java EE Logging] (May 6, 2014) - -== German - -* https://entwickler.de/java/apache-log4j-26-lauft-nun-auch-ohne-mull/[Apache Log4j 2.6 läuft nun auch ohne Müll] (May 31, 2016) -* https://www.innoq.com/en/articles/2015/01/logging-konsolidieren-log4j2/[Logging konsolidieren und Performance gewinnen] (January 23, 2015) - -== Japanese - -* https://tm-b.hatenablog.com/entry/2016/08/18/200715[中年プログラマーの息抜き] (August 18, 2016) -* https://minor.hatenablog.com/entry/2016/05/22/193556[【log4j2】ThreadContextを利用してすべてのログに追加情報を出力する] (May 22, 2016) -* https://qiita.com/kazurof/items/abbd42f11bfc125f3190[Log4j 2でログ出力をテストするサンプルソース] (February 22, 2016) -* https://www.infoq.com/jp/news/2015/09/interview-log4j-pmc/[新Log4jへの移行: Log4jプロジェクト管理グループとのQ&A] (September 27, 2015) -* https://www.infoq.com/jp/news/2015/09/log4j-version-1-reaches-eol/[Log4jバージョン1のサポートが終了] (September 23, 2015) -* https://qiita.com/pica/items/f801c74848f748f76b58[log4j2の設定ファイル(XML)] (July 27, 2015) -* https://yamashiro0110.hatenadiary.jp/entry/2014/08/24/093336[Log4j2の使い方めも] (August 24, 2014) -* https://www.infoq.com/jp/news/2014/08/apache-log4j2/[Apache Log4j 2.0 - アップグレードする価値はあるか?] (August 17, 2014) -* https://kazuhira-r.hatenablog.com/entry/20140628/1403959552[Log4j2を試してみる] (June 28, 2014) -* https://nabedge.blogspot.com/2013/10/log4j2.html[log4j2にログを集める] (October 26, 2013) - -== Korean - -* https://dveamer.github.io/java/Log4j2.html[Log4j 2 설정하기] (January 24, 2016) -* https://www.egovframe.go.kr/wiki/doku.php?id=egovframework:rte3:fdl:%EC%84%A4%EC%A0%95_%ED%8C%8C%EC%9D%BC%EC%9D%84_%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94_%EB%B0%A9%EB%B2%95[Log4j 2 환경설정 [설정 파일 사용 시\]] (May 14, 2014) diff --git a/src/site/antora/modules/ROOT/pages/faq.adoc b/src/site/antora/modules/ROOT/pages/faq.adoc index 67916b0c0c5..2cda5a81f74 100644 --- a/src/site/antora/modules/ROOT/pages/faq.adoc +++ b/src/site/antora/modules/ROOT/pages/faq.adoc @@ -153,7 +153,7 @@ There are several advantages to using Log4j API: * SLF4J forces your application to log ``String``s. Log4j API supports logging any `CharSequence` if you want to log text, but also supports logging any `Object` as is. It is the responsibility of the logging _implementation_ to handle this object, and we consider it a design mistake to limit applications to logging ``String``s. -* Log4j API offers support for logging {log4j2-url}/manual/messages.adoc[`Message` objects]. +* Log4j API offers support for logging {log4j2-url}/manual/messages.html[`Message` objects]. Messages allow support for interesting and complex constructs to be passed through the logging system and be efficiently manipulated. Users are free to create their own message types and write custom layouts, filters and lookups to manipulate them. * Log4j API supports {log4j2-url}/manual/api.adoc#fluent-api[lambda expressions] both in its plain and fluent API. diff --git a/src/site/antora/modules/ROOT/pages/manual/appenders.adoc b/src/site/antora/modules/ROOT/pages/manual/appenders.adoc index aee25f66224..8fd9dcc1f94 100644 --- a/src/site/antora/modules/ROOT/pages/manual/appenders.adoc +++ b/src/site/antora/modules/ROOT/pages/manual/appenders.adoc @@ -17,6 +17,8 @@ = Appenders += Appenders + Appenders are responsible for delivering log events to their destination. Every Appender must implement the link:../javadoc/log4j-core/org/apache/logging/log4j/core/Appender.html[`Appender`] @@ -116,7 +118,28 @@ This setting only guarantees that a byte representation of the log event is pass It does not ensure that the operating system writes the event to the underlying storage. ==== -[TIP] +[#collection] +== Collection + +Log4j bundles several predefined appenders to assist in several common deployment use cases. +Following sections explain all these in detail. + +[id=AsyncAppender] +=== [[asyncappender]] AsyncAppender + +The AsyncAppender accepts references to other Appenders and causes LogEvents to be written to them on a separate Thread. +Note that exceptions while writing to those Appenders will be hidden from the application. +The AsyncAppender should be configured after the appenders it references to allow it to shut down properly. + +By default, AsyncAppender uses +https://docs.oracle.com/javase/{java-target-version}/docs/api/java/util/concurrent/ArrayBlockingQueue.html[`ArrayBlockingQueue`] +which does not require any external libraries. +Note that multi-threaded applications should exercise care when using this appender as such: the blocking queue is susceptible to lock contention and our +xref:manual/performance.adoc#async[tests showed] performance may become worse when more threads are logging concurrently. +Consider using +xref:manual/async.adoc[lock-free Async Loggers] for optimal performance. + +[NOTE] ==== If you are using xref:manual/async.adoc[asynchronous loggers] @@ -136,445 +159,3899 @@ This behavior can be changed using the following configuration property: [#ignoreExceptions] ==== `ignoreExceptions` -[cols="1h,5"] -|=== -| Type | `boolean` -| Default value | `true` -|=== +|bufferSize |integer a| +Specifies the maximum number of events that can be queued. The default +is 1024. Note that when using a disruptor-style `BlockingQueue`, this +buffer size must be a power of 2. -If `false` logging exceptions will be forwarded to the caller. -Otherwise, they will be logged using the -{log4j2-url}/manual/status-logger.html[status logger]. +When the application is logging faster than the underlying appender can +keep up with for a long enough time to fill up the queue, the behavior +is determined by the +link:../javadoc/log4j-core/org/apache/logging/log4j/core/async/AsyncQueueFullPolicy.html[`AsyncQueueFullPolicy`]. -[TIP] -==== -If logging is important for your business, consider using a -xref:manual/appenders/delegating.adoc#FailoverAppender[`Failover` Appender] -to redirect log events to a different appender in case of exceptions. -==== +|errorRef |String |The name of the Appender to invoke if none of the +appenders can be called, either due to errors in the appenders or +because the queue is full. If not specified then errors will be ignored. -[#runtime-evaluation] -=== Runtime evaluation of attributes +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. -The following configuration attributes are also evaluated at runtime, so can contain escaped `$$+{...}+` property substitution expressions. +|name |String |The name of the Appender. -.List of attributes evaluated at runtime -[cols="1,1,1,1"] -|=== -| Component | Parameter | Event type | Evaluation context +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a >. -| xref:manual/appenders/network.adoc#HttpAppender[HTTP Appender] -| xref:manual/appenders/network.adoc#HttpAppender-element-Property[`Property/value`] -| Log event -| xref:manual/lookups.adoc#global-context[_global_] +|includeLocation |boolean |Extracting location is an expensive operation +(it can make logging 5 - 20 times slower). To improve performance, +location is not included by default when adding a log event to the +queue. You can change this by setting includeLocation="true". -| xref:manual/appenders/database.adoc#NoSqlAppender[NoSQL Appender] -| xref:manual/appenders/database.adoc#NoSqlAppender-element-KeyValuePair[`KeyValuePair/value`] -| Log event -| xref:manual/lookups.adoc#global-context[_global_] +|BlockingQueueFactory +|BlockingQueueFactory +|This element overrides what type of `BlockingQueue` to use. +See <> for more details. +|======================================================================= -| xref:manual/appenders/delegating.adoc#PropertiesRewritePolicy[PropertiesRewrite Policy] -| xref:manual/appenders/delegating.adoc#PropertiesRewritePolicy-element-Property[`Property/value`] -| Log event -| xref:manual/lookups.adoc#global-context[_global_] +There are also a few system properties that can be used to maintain application throughput even when the underlying appender cannot keep up with the logging rate and the queue is filling up. +See the details for system properties +xref:manual/systemproperties.adoc#log4j.async.queueFullPolicy.type[`log4j.async.queueFullPolicy.type`] +and +xref:manual/systemproperties.adoc#log4j.async.queueFullPolicy.discardThreshold[`log4j.async.queueFullPolicy.discardThreshold`]. -| xref:manual/appenders/delegating.adoc#Routes[Routes Container] -| xref:manual/appenders/delegating.adoc#Routes-attr-pattern[`pattern`] -| Log event -| xref:manual/lookups.adoc#event-context[_log event_] +A typical AsyncAppender configuration might look like this: -| xref:manual/appenders/rolling-file.adoc[Rolling File Appenders] -| xref:manual/appenders/rolling-file.adoc#attr-filePattern[`filePattern`] -| Rollover -| xref:manual/lookups.adoc#global-context[_global_] +[source,xml] +---- + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + + + +---- -| xref:manual/appenders/rolling-file.adoc#AbstractPathAction[Optional Rollover Actions] -| xref:manual/appenders/rolling-file.adoc#AbstractPathAction-attr-basePath[`basePath`] -| Rollover -| xref:manual/lookups.adoc#global-context[_global_] +[[BlockingQueueFactory]] +Starting in Log4j 2.7, a custom implementation of `BlockingQueue` or `TransferQueue` can be specified using a +link:../javadoc/log4j-core/org/apache/logging/log4j/core/async/BlockingQueueFactory.html[`BlockingQueueFactory`] +plugin. +To override the default `BlockingQueueFactory`, specify the plugin inside an `` element like so: -|=== +[source,xml] +---- + + + + + + + + + + + + + + +---- -The -xref:manual/appenders/delegating.adoc#Route[`Route`] -component of the -xref:manual/appenders/delegating.adoc#RoutingAppender[Routing Appender] -is special: its children are evaluated at runtime, but they are **not** evaluated at configuration time. -Inside the `Route` component you **should not** use escaped `$$+{...}+` property substitution expressions, but only unescaped `$+{...}+` property substitution expressions. +Log4j ships with the following implementations: + +.BlockingQueueFactory Implementations +[cols="25%,75%",options="header",] +|======================================================================= +|Plugin Name |Description +|ArrayBlockingQueue |This is the default implementation that uses +https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ArrayBlockingQueue.html[`ArrayBlockingQueue`]. + +|DisruptorBlockingQueue |This uses the +https://github.com/conversant/disruptor[Conversant Disruptor] +implementation of `BlockingQueue`. This plugin takes a single optional +attribute, `spinPolicy`, which corresponds to the `SpinPolicy` enum. + +|JCToolsBlockingQueue |This uses +https://jctools.github.io/JCTools/[JCTools], specifically the MPSC +bounded lock-free queue. +This implementation is provided by the `log4j-jctools` artifact. + +|LinkedTransferQueue |This uses the new Java 7 implementation +https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/LinkedTransferQueue.html[`LinkedTransferQueue`]. +Note that this queue does not use the `bufferSize` configuration +attribute from AsyncAppender as `LinkedTransferQueue` does not support a +maximum capacity. +|======================================================================= + +[id=consoleappender] +=== [[ConsoleAppender]] ConsoleAppender + +As one might expect, the ConsoleAppender writes its output to either +`System.out` or `System.err` with `System.out` being the default target. +A Layout must be provided to format the LogEvent. + +.ConsoleAppender Parameters +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. + +|layout |Layout |The Layout to use to format the LogEvent. If no layout +is supplied the default pattern layout of "%m%n" will be used. + +|follow |boolean |Identifies whether the appender honors reassignments +of `System.out` or `System.err` via `System.setOut` or `System.setErr` made +after configuration. Note that the follow attribute cannot be used with +Jansi on Windows. Cannot be used with `direct`. + +|direct |boolean |Write directly to `java.io.FileDescriptor` and bypass +`java.lang.System.out/.err`. Can give up to 10x performance boost when +the output is redirected to a file or other process. Cannot be used with +Jansi on Windows. Cannot be used with `follow`. The output will not respect +`java.lang.System.setOut()/.setErr()` and may get intertwined with other +output to `java.lang.System.out/.err` in a multi-threaded application. +_New since 2.6.2. Be aware that this is a new addition, and it has only +been tested with Oracle JVM on Linux and Windows so far._ + +|name |String |The name of the Appender. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a <>. + +|target |String |Either "SYSTEM_OUT" or "SYSTEM_ERR". The default is +"SYSTEM_OUT". +|======================================================================= + +A typical Console configuration might look like: + +[source,xml,prettyprint,linenums] +---- + + + + + + + + + + + + + +---- -See xref:manual/configuration.adoc#lazy-property-substitution[runtime property substitution] for more details. +[#FailoverAppender] +=== FailoverAppender -[#collection] -== Collection +The FailoverAppender wraps a set of appenders. +If the primary Appender fails the secondary appenders will be tried in order until one succeeds or there are no more secondaries to try. -Log4j bundles several predefined appenders to assist in several common deployment use cases. -They are documented in separate pages based on their target resource: +.FailoverAppender Parameters +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. -[#ConsoleAppender] -=== Console Appender +|primary |String |The name of the primary Appender to use. -As one might expect, the Console Appender writes its output to either the standard output or standard error output. -The appender supports three different ways to access the output streams: +|failovers |String[] |The names of the secondary Appenders to use. -`direct`:: -This mode gives the best performance. -It can be enabled by setting the <> attribute to `true`. +|name |String |The name of the Appender. -`default`:: -By default, the Console appender uses the values of `System.out` or `System.err` present at **configuration time**. -Any changes to those streams at runtime will be ignored. +|retryIntervalSeconds |integer |The number of seconds that should pass +before retrying the primary Appender. The default is 60. -`follow`:: -This mode always uses the **current** value of the `System.out` and `System.err` streams. -It can be enabled by setting the <> attribute to `true`. -+ -[TIP] -==== -This setting might be useful in multi-application environments. -Some application servers modify `System.out` and `System.err` to always point to the currently running application. -==== +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. -[#ConsoleAppender-attributes] -.Console Appender configuration attributes -[cols="1m,1,1,5"] -|=== -| Attribute | Type | Default value | Description +|target |String |Either "SYSTEM_OUT" or "SYSTEM_ERR". The default is +"SYSTEM_ERR". +|======================================================================= -4+h| Required +A Failover configuration might look like: -| [[ConsoleAppender-attr-name]]name -| `String` -| -| The name of the appender. +[source,xml] +---- + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + + + + + + + + + +---- -4+h| Optional +[id=fileappender] +=== [[FileAppender]] FileAppender + +The FileAppender is an OutputStreamAppender that writes to the File defined in the `fileName` parameter. +The FileAppender uses a FileManager (which extends OutputStreamManager) to perform the file I/O. +While FileAppenders from different Configurations cannot be shared, the FileManagers can be if the Manager is accessible. +For example, two web applications in a servlet container can have their configuration and safely write to the same file if Log4j is in a ClassLoader that is common to both of them. + +.FileAppender Parameters +[width="100%",cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|append |boolean |When true - the default, records will be appended to +the end of the file. When set to false, the file will be cleared before +new records are written. + +|bufferedIO |boolean |When true - the default, records will be written +to a buffer and the data will be written to disk when the buffer is full +or, if immediateFlush is set, when the record is written. File locking +cannot be used with `bufferedIO`. Performance tests have shown that using +buffered I/O significantly improves performance, even if `immediateFlush` +is enabled. + +|bufferSize |int |When `bufferedIO` is true, this is the buffer size, the +default is 8192 bytes. + +|createOnDemand |boolean |The appender creates the file on-demand. The +appender only creates the file when a log event passes all filters and +is routed to this appender. Defaults to false. + +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. + +|fileName |String |The name of the file to write to. If the file, or any +of its parent directories, do not exist, they will be created. + +|immediateFlush |boolean a| +When set to true - the default, each write will be followed by a flush. +This will guarantee that the data is passed to the operating system for writing; +it does not guarantee that the data is written to a physical device +such as a disk drive. + +Note that if this flag is set to false, and the logging activity is sparse, +there may be an indefinite delay in the data eventually making it to the +operating system, because it is held up in a buffer. +This can cause surprising effects such as the logs not +appearing in the tail output of a file immediately after writing to the log. + +Flushing after every write is only useful when using this appender with +synchronous loggers. Asynchronous loggers and appenders will +automatically flush at the end of a batch of events, even if +immediateFlush is set to false. This also guarantees the data is passed +to the operating system but is more efficient. + +|layout |Layout |The Layout to use to format the LogEvent. If no layout +is supplied the default pattern layout of "%m%n" will be used. + +|locking |boolean |When set to true, I/O operations will occur only +while the file lock is held allowing FileAppenders in multiple JVMs and +potentially multiple hosts to write to the same file simultaneously. +This will significantly impact performance so should be used carefully. +Furthermore, on many systems, the file lock is "advisory" meaning that +other applications can perform operations on the file without acquiring +a lock. The default value is false. + +|name |String |The name of the Appender. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a <>. + +|filePermissions |String a| +File attribute permissions in POSIX format to apply whenever the file is +created. + +The underlying files system shall support +https://docs.oracle.com/javase/7/docs/api/java/nio/file/attribute/PosixFileAttributeView.html[POSIX] +file attribute view. + +Examples: `rw-------` or `rw-rw-rw-` etc... + +|fileOwner |String a| +File owner to define whenever the file is created. + +Changing the file's owner may be restricted for security reasons and +Operation not permitted IOException thrown. Only processes with an +effective user ID equal to the user ID of the file or with appropriate +privileges may change the ownership of a file if +http://www.gnu.org/software/libc/manual/html_node/Options-for-Files.html[_POSIX_CHOWN_RESTRICTED] +is in effect for path. + +The underlying files system shall support file +https://docs.oracle.com/javase/7/docs/api/java/nio/file/attribute/FileOwnerAttributeView.html[owner] +attribute view. + +|fileGroup |String a| +File group to define whenever the file is created. + +The underlying files system shall support +https://docs.oracle.com/javase/7/docs/api/java/nio/file/attribute/PosixFileAttributeView.html[POSIX] +file attribute view. + +|======================================================================= + +Here is a sample File configuration: + +[source,xml] +---- + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + +---- -| [[ConsoleAppender-attr-bufferSize]]bufferSize -| `int` -| xref:manual/systemproperties.adoc#log4j.gc.encoderByteBufferSize[`8192`] -a| -The size of the -https://docs.oracle.com/javase/{java-target-version}/docs/api/java/nio/ByteBuffer.html[`ByteBuffer`] -internally used by the appender. +[#FlumeAppender] +=== FlumeAppender -See <> for more details. +_This is an optional component supplied in a separate jar._ -| [[ConsoleAppender-attr-direct]]direct -| `boolean` -| `false` -a| -If set to `true`, log events will be written directly to either -https://docs.oracle.com/javase/8/docs/api/java/io/FileDescriptor.html#out[`FileDescriptor.out`] -or -https://docs.oracle.com/javase/8/docs/api/java/io/FileDescriptor.html#err[`FileDescriptor.err`]. +http://flume.apache.org/index.html[Apache Flume] is a distributed, reliable, and available system for efficiently collecting, aggregating, and moving large amounts of log data from many different sources to a centralized data store. +The FlumeAppender takes LogEvents and sends them to a Flume agent as serialized Avro events for consumption. -This setting bypasses the buffering of `System.out` and `System.err` and might provide a performance comparable to a xref:manual/appenders/file.adoc[file appender]. +The Flume Appender supports three modes of operation. -[CAUTION] -==== +1. It can act as a remote Flume client which sends Flume events via Avro to a Flume Agent configured with an Avro Source. +2. It can act as an embedded Flume Agent where Flume events pass directly into Flume for processing. +3. It can persist events to a local BerkeleyDB data store and then asynchronously send the events to Flume, similar to the embedded Flume Agent but without most of the Flume dependencies. -If other logging backends or the application itself uses `System.out/System.err`, setting this to `true` might cause interleaved output. +Usage as an embedded agent will cause the messages to be directly passed to the Flume Channel and then control will be immediately returned to the application. +All interaction with remote agents will occur asynchronously. +Setting the "type" attribute to "Embedded" will force the use of the embedded agent. +In addition, configuring agent properties in the appender configuration will also cause the embedded agent to be used. -==== +.FlumeAppender Parameters +[width="100%",cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|agents |Agent[] |An array of Agents to which the logging events should +be sent. If more than one agent is specified the first Agent will be the +primary and subsequent Agents will be used in the order specified as +secondaries should the primary Agent fail. Each Agent definition +supplies the Agent's host and port. The specification of agents and +properties are mutually exclusive. If both are configured an error will +result. -This setting is incompatible with the -<>. +|agentRetries |integer |The number of times the agent should be retried +before failing to a secondary. This parameter is ignored when +`type="persistent"` is specified (agents are tried once before failing to +the next). -| [[ConsoleAppender-attr-follow]] -follow -| `boolean` -| `false` -| -If set to `true`, the appender will honor reassignments of `System.out` (resp. `System.err`) via -https://docs.oracle.com/javase/8/docs/api/java/lang/System.html#setOut-java.io.PrintStream-[`System.setOut`] -(resp. -https://docs.oracle.com/javase/8/docs/api/java/lang/System.html#setOut-java.io.PrintStream-[`System.setErr`]). +|batchSize |integer |Specifies the number of events that should be sent +as a batch. The default is 1. _This parameter only applies to the Flume +Appender._ -Otherwise, the value of `System.out` (resp. `System.err`) at configuration time will be used. +|compress |boolean |When set to true the message body will be compressed +using gzip -This setting is incompatible with the -<>. +|connectTimeoutMillis |integer |The number of milliseconds Flume will +wait before timing out the connection. -| [[ConsoleAppender-attr-ignoreExceptions]] -ignoreExceptions -| `boolean` -| `true` -| If `false`, logging exception will be forwarded to the caller of the logging statement. -Otherwise, they will be ignored. +|dataDir |String |Directory where the Flume write-ahead log should be +written. Valid only when embedded is set to true and Agent elements are +used instead of Property elements. -Logging exceptions are always also logged to the -{log4j2-url}/manual/status-logger.html[] +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. -| [[ConsoleAppender-attr-immediateFlush]] -immediateFlush -| `boolean` -| `true` -| -If set to `true`, the appender will flush its internal buffer and the buffer of the `System.out/System.err` stream after each log event. +|eventPrefix |String |The character string to prepend to each event +attribute to distinguish it from MDC attributes. The default is +an empty string. -See xref:manual/appenders.adoc#buffering[Buffering] for more details. +|flumeEventFactory |FlumeEventFactory |Factory that generates the Flume +events from Log4j events. The default factory is the FlumeAvroAppender +itself. -| [[ConsoleAppender-attr-target]] -target -| link:../javadoc/log4j-core/org/apache/logging/log4j/core/appender/ConsoleAppender.Target.html[`Target`] -| link:../javadoc/log4j-core/org/apache/logging/log4j/core/appender/ConsoleAppender.Target.html#SYSTEM_OUT[`SYSTEM_OUT`] -a| -It specifies which standard output stream to use: +|layout |Layout |The Layout to use to format the LogEvent. If no layout +is specified RFC5424Layout will be used. -`SYSTEM_OUT`:: -It uses the standard output. +|lockTimeoutRetries |integer |The number of times to retry if a +LockConflictException occurs while writing to Berkeley DB. The default +is 5. -`SYSTEM_ERR`:: -It uses the standard error output. +|maxDelayMillis |integer |The maximum number of milliseconds to wait for +batchSize events before publishing the batch. -|=== +|mdcExcludes |String |A comma-separated list of mdc keys that should be +excluded from the FlumeEvent. This is mutually exclusive with the +mdcIncludes attribute. -[#ConsoleAppender-elements] -.Common nested elements -[cols="1m,1,4"] -|=== +|mdcIncludes |String |A comma-separated list of mdc keys that should be +included in the FlumeEvent. Any keys in the MDC not found in the list +will be excluded. This option is mutually exclusive with the mdcExcludes +attribute. -| Type | Multiplicity | Description +|mdcRequired |String |A comma-separated list of `mdc` keys that must be +present in the MDC. If a key is not present a LoggingException will be +thrown. -| [[ConsoleAppender-element-Filter]] -xref:manual/filters.adoc[`Filter`] -| zero or one -| -Allows filtering log events just before they are formatted and sent. +|mdcPrefix |String |A string that should be prepended to each MDC key to distinguish it from event attributes. The default string is +"mdc:". -See also xref:manual/filters.adoc#appender-stage[appender filtering stage]. +|name |String |The name of the Appender. -| [[ConsoleAppender-element-Layout]] -xref:manual/layouts.adoc[`Layout`] -| zero or one -| -Formats log events. +|properties |Property[] a| +One or more Property elements that are used to configure the Flume +Agent. The properties must be configured without the agent name (the +appender name is used for this) and no sources can be configured. +Interceptors can be specified for the source using +"sources.log4j-source.interceptors". All other Flume configuration +properties are allowed. Specifying both Agent and Property elements will +result in an error. -See xref:manual/layouts.adoc[] for more information. +When used to configure in Persistent mode the valid properties are: -|=== +1. `keyProvider` to specify the name of the plugin to provide the +secret key for encryption. -xref:plugin-reference.adoc#org-apache-logging-log4j_log4j-core_org-apache-logging-log4j-core-appender-ConsoleAppender[{plugin-reference-marker} Plugin reference for `Console`] +|requestTimeoutMillis |integer |The number of milliseconds Flume will +wait before timing out the request. -[#ConsoleAppender-examples] -==== Configuration examples +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a <>. + +|type |enumeration |One of "Avro", "Embedded", or "Persistent" to +indicate which variation of the Appender is desired. +|======================================================================= + +A sample FlumeAppender configuration that is configured with a primary and a secondary agent compresses the body and formats the body using the RFC5424Layout: -A typical configuration in a **development** environment might look like: +[source,xml] +---- + + + + + + + + + + + + + + + +---- -[tabs] -==== -XML:: -+ -.Snippet from an example {antora-examples-url}/manual/appenders/console-dev.xml[`log4j2.xml`] -[source,xml,indent=0] +A sample FlumeAppender configuration that is configured with a primary and a secondary agent compresses the body, formats the body using the RFC5424Layout, and persists encrypted events to disk: + +[source,xml] ---- -include::example$manual/appenders/console-dev.xml[tag=appender] + + + + + + + + MySecretProvider + + + + + + + + ---- -JSON:: -+ -.Snippet from an example {antora-examples-url}/manual/appenders/console-dev.json[`log4j2.json`] -[source,json,indent=0] +A sample FlumeAppender configuration that is configured with a primary and a secondary agent compresses the body, and formats the body using RFC5424Layout and passes the events to an embedded Flume Agent. + +[source,xml] ---- -include::example$manual/appenders/console-dev.json[tag=appender] + + + + + + + + + + + + + + + + + + + + + ---- -YAML:: -+ -.Snippet from an example {antora-examples-url}/manual/appenders/console-dev.yaml[`log4j2.yaml`] -[source,yaml,indent=0] +A sample FlumeAppender configuration that is configured with a primary and a secondary agent using Flume configuration properties compresses the body, formats the body using RFC5424Layout and passes the events to an embedded Flume Agent. + +[source,xml] ---- -include::example$manual/appenders/console-dev.yaml[tag=appender] + + + + + file + file + target/file-channel/checkpoint + target/file-channel/data + agent1 agent2 + file + avro + 192.168.10.101 + 8800 + 100 + file + avro + 192.168.10.102 + 8800 + 100 + group1 + agent1 agent2 + failover + 10 + 5 + + + + + + + + + + + + + + + ---- -Properties:: -+ -.Snippet from an example {antora-examples-url}/manual/appenders/console-dev.properties[`log4j2.properties`] -[source,properties,indent=0] +[#JDBCAppender] +=== JDBCAppender + +As of Log4j 2.11.0, JDBC support has moved from the existing module +`log4j-core` to the new module `log4j-jdbc`. + +The JDBC Appender configured with a `DataSource` requires JNDI support so as of release 2.17.1 this appender will not function unless `log4j2.enableJndiJdbc=true` is configured as a system property or environment variable. +See the xref:manual/systemproperties.adoc#log4j.jndi.enableJdbc[`log4j.jndi.enableJdbc`] system property. + +The JDBCAppender writes log events to a relational database table using standard JDBC. +It can be configured to obtain JDBC connections using a JNDI `DataSource` or a custom factory method. +Whichever approach you take, it *_must_* be backed by a connection pool. +Otherwise, logging performance will suffer greatly. +If batch statements are supported by the configured JDBC driver and a `bufferSize` is configured to be a positive number, then log events will be batched. +Note that as of Log4j 2.8, there are two ways to configure log event to column mappings: the original `ColumnConfig` style that only allows strings and timestamps, and the new `ColumnMapping` plugin that uses Log4j's built-in type conversion to allow for more data types. + +To get off the ground quickly during development, an alternative to using a connection source based on JNDI is to use the non-pooling +`DriverManager` connection source. +This connection source uses a JDBC connection string, a username, and a password. +Optionally, you can also use properties. + +.JDBCAppender Parameters +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|name |String |_Required._ The name of the Appender. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a <>. + +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. + +|bufferSize |int |If an integer is greater than 0, this causes the appender +to buffer log events and flush whenever the buffer reaches this size. + +|connectionSource |ConnectionSource |_Required._ The connection source +from which database connections should be retrieved. + +|tableName |String |_Required._ The name of the database table to insert +log events into. + +|columnConfigs |ColumnConfig[] |_Required (and/or columnMappings)._ +Information about the columns that log event data should be inserted +into and how to insert that data. This is represented by multiple +`` elements. + +|columnMappings |ColumnMapping[] |_Required (and/or columnConfigs)._ A +list of column mapping configurations. Each column must specify a column +name. Each column can have a conversion type specified by its fully +qualified class name. By default, the conversion type is `String`. If +the configured type is assignment-compatible with +{log4j2-url}/javadoc/log4j-api/org/apache/logging/log4j/util/ReadOnlyStringMap.html[`ReadOnlyStringMap`] +/ +{log4j2-url}/javadoc/log4j-api/org/apache/logging/log4j/spi/ThreadContextMap.html[`ThreadContextMap`] +or +{log4j2-url}/javadoc/log4j-api/org/apache/logging/log4j/spi/ThreadContextStack.html[`ThreadContextStack`], +then that column will be populated with the MDC or NDC respectively +(this is database-specific how they handle inserting a `Map` or `List` +value). If the configured type is assignment-compatible with +`java.util.Date`, then the log timestamp will be converted to that +configured date type. If the configured type is assignment-compatible +with `java.sql.Clob` or `java.sql.NClob`, then the formatted event will +be set as a Clob or NClob respectively (similar to the traditional +ColumnConfig plugin). If a `literal` attribute is given, then its value +will be used as is in the `INSERT` query without any escaping. +Otherwise, the layout or pattern specified will be converted into the +configured type and stored in that column. + +|immediateFail |boolean | When set to true, log events will not +wait to try to reconnect and will fail immediately if the JDBC resources +are not available. New in 2.11.2. + +|reconnectIntervalMillis |long |If set to a value greater than 0, +after an error, the JDBCDatabaseManager will attempt to reconnect to the database +after waiting the specified number of milliseconds. If the reconnect +fails then an exception will be thrown (which can be caught by the +application if `ignoreExceptions` is set to `false`). New in 2.11.2. +|======================================================================= + +When configuring the JDBCAppender, you must specify a `ConnectionSource` +implementation from which the Appender gets JDBC connections. +You must use exactly one of the following nested elements: + +* <`>>: Uses JNDI. +* <`>>: Points to a class-method pair to provide JDBC connections. +* <`>>: A quick and dirty way to get off the ground, no connection pooling. +* <`>>: Uses Apache Commons DBCP to provide connection pooling. + +[#JDBCDataSource] +.DataSource Parameters +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|jndiName |String |_Required._ The full, prefixed JNDI name that the +`javax.sql.DataSource` is bound to, such as +`java:/comp/env/jdbc/LoggingDatabase`. The `DataSource` must be backed +by a connection pool; otherwise, logging will be very slow. +|======================================================================= + +[#JDBCConnectionFactory] +.ConnectionFactory Parameters +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|class |Class |_Required._ The fully qualified name of a class +containing a static factory method for obtaining JDBC connections. + +|method |Method |_Required._ The name of a static factory method for +obtaining JDBC connections. This method must have no parameters and its +return type must be either `java.sql.Connection` or `DataSource`. If the +method returns `Connection`, it must obtain them from a connection pool +(and they will be returned to the pool when Log4j is done with them); +otherwise, logging will be very slow. If the method returns a +`DataSource`, the `DataSource` will only be retrieved once, and it must +be backed by a connection pool for the same reasons. +|======================================================================= + +[#JDBCDriverManager] +.DriverManager Parameters +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|connectionString |String |_Required._ The driver-specific JDBC +connection string. + +|userName |String |The database user name. You cannot specify both +properties and a username or password. + +|password |String |The database password. You cannot specify both +properties and a username or password. + +|driverClassName |String |The JDBC driver class name. Some old JDBC +driver can only be discovered by explicitly loading them by class name. + +|properties |Property[] |A list of properties. You cannot specify both +properties and a username or password. +|======================================================================= + +[#JDBCPoolingDriver] +.PoolingDriver Parameters (Apache Commons DBCP) +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|DriverManager parameters |DriverManager parameters |This connection +source inherits all parameters from the DriverManager connection source. + +|poolName |String |The pool name used to pool JDBC Connections. Defaults +to `example`. You can use the JDBC connection string prefix +`jdbc:apache:commons:dbcp:` followed by the pool name if you want to use +a pooled connection elsewhere. For example: +`jdbc:apache:commons:dbcp:example`. + +|PoolableConnectionFactory |PoolableConnectionFactory element |Defines a PoolableConnectionFactory. +|======================================================================= + +[#JDBCPoolableConnectionFactory] +.PoolableConnectionFactory Parameters (Apache Commons DBCP) +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|autoCommitOnReturn |boolean | See https://commons.apache.org/proper/commons-dbcp/configuration.html[Apache Commons DBCP configuration]. +|cacheState |boolean | See https://commons.apache.org/proper/commons-dbcp/configuration.html[Apache Commons DBCP configuration]. +|connectionInitSqls |Strings | See https://commons.apache.org/proper/commons-dbcp/configuration.html[Apache Commons DBCP configuration]. +|defaultAutoCommit |Boolean | See https://commons.apache.org/proper/commons-dbcp/configuration.html[Apache Commons DBCP configuration]. +|defaultCatalog |String | See https://commons.apache.org/proper/commons-dbcp/configuration.html[Apache Commons DBCP configuration]. +|defaultQueryTimeoutSeconds |Integer | See https://commons.apache.org/proper/commons-dbcp/configuration.html[Apache Commons DBCP configuration]. +|defaultReadOnly |Boolean | See https://commons.apache.org/proper/commons-dbcp/configuration.html[Apache Commons DBCP configuration]. +|defaultTransactionIsolation |int | See https://commons.apache.org/proper/commons-dbcp/configuration.html[Apache Commons DBCP configuration]. +|disconnectionSqlCodes |Strings | See https://commons.apache.org/proper/commons-dbcp/configuration.html[Apache Commons DBCP configuration]. +|fastFailValidation |boolean | See https://commons.apache.org/proper/commons-dbcp/configuration.html[Apache Commons DBCP configuration]. +|maxConnLifetimeMillis |long | See https://commons.apache.org/proper/commons-dbcp/configuration.html[Apache Commons DBCP configuration]. +|maxOpenPreparedStatements |int | See https://commons.apache.org/proper/commons-dbcp/configuration.html[Apache Commons DBCP configuration]. +|poolStatements |boolean | See https://commons.apache.org/proper/commons-dbcp/configuration.html[Apache Commons DBCP configuration]. +|rollbackOnReturn |boolean | See https://commons.apache.org/proper/commons-dbcp/configuration.html[Apache Commons DBCP configuration]. +|validationQuery |String | See https://commons.apache.org/proper/commons-dbcp/configuration.html[Apache Commons DBCP configuration]. +|validationQueryTimeoutSeconds |int | See https://commons.apache.org/proper/commons-dbcp/configuration.html[Apache Commons DBCP configuration]. +|======================================================================= + +When configuring the JDBCAppender, use the nested `` elements to specify which columns in the table should be written to and how to write to them. +The JDBCAppender uses this information to formulate a +`PreparedStatement` to insert records without SQL injection vulnerability. + +.Column Parameters +[width="100%",cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|name |String |_Required._ The name of the database column. + +|pattern |String |Use this attribute to insert a value or values from +the log event in this column using a `PatternLayout` pattern. Simply +specify any legal pattern in this attribute. Either this attribute, +`literal`, or `isEventTimestamp="true"` must be specified, but not more +than one of these. + +|literal |String |Use this attribute to insert a literal value in this +column. The value will be included directly in the insert SQL, without +any quoting (which means that if you want this to be a string, your +value should contain single quotes around it like this: +`literal="'Literal String'"`). This is especially useful for databases +that don't support identity columns. For example, if you are using +Oracle you could specify `literal="NAME_OF_YOUR_SEQUENCE.NEXTVAL"` to +insert a unique ID in an ID column. Either this attribute, `pattern`, or +`isEventTimestamp="true"` must be specified, but not more than one of +these. + +|parameter |String a| +Use this attribute to insert an expression with a parameter marker '?' +in this column. The value will be included directly in the insert SQL, +without any quoting (which means that if you want this to be a string, +your value should contain single quotes around it like this: + +`` + +You can only specify one of `literal` or `parameter`. + +|isEventTimestamp |boolean |Use this attribute to insert the event +timestamp in this column, which should be a SQL `datetime`. The value will +be inserted as a `java.sql.Types.TIMESTAMP`. Either this attribute +(equal to `true`), `pattern`, or `isEventTimestamp` must be specified, +but not more than one of these. + +|isUnicode |boolean |This attribute is ignored unless `pattern` is +specified. If `true` or omitted (default), the value will be inserted as +unicode (`setNString` or `setNClob`). Otherwise, the value will be +inserted non-Unicode (`setString` or `setClob`). + +|isClob |boolean |This attribute is ignored unless `pattern` is +specified. Use this attribute to indicate that the column stores +Character Large Objects (CLOBs). If `true`, the value will be inserted +as a CLOB (`setClob` or `setNClob`). If `false` or omitted (default), +the value will be inserted as a VARCHAR or NVARCHAR (`setString` or +`setNString`). +|======================================================================= + +.ColumnMapping Parameters +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|name |String |_Required._ The name of the database column. + +|pattern |String |Use this attribute to insert a value or values from +the log event in this column using a `PatternLayout` pattern. Simply +specify any legal pattern in this attribute. Either this attribute, +`literal`, or `isEventTimestamp="true"` must be specified, but not more +than one of these. + +|literal |String |Use this attribute to insert a literal value in this +column. The value will be included directly in the insert SQL, without +any quoting (which means that if you want this to be a string, your +value should contain single quotes around it like this: +`literal="'Literal String'"`). This is especially useful for databases +that don't support identity columns. For example, if you are using +Oracle you could specify `literal="NAME_OF_YOUR_SEQUENCE.NEXTVAL"` to +insert a unique ID in an ID column. Either this attribute, `pattern`, or +`isEventTimestamp="true"` must be specified, but not more than one of +these. + +|layout |Layout |The Layout to format the LogEvent. + +|type |String |Conversion type name, a fully qualified class name. +|======================================================================= + +Here are a couple of sample configurations for the JDBCAppender, as well as a sample factory implementation that uses Commons Pooling and Commons DBCP to pool database connections: + +[source,xml] ---- -include::example$manual/appenders/console-dev.properties[tag=appender] + + + + + + + + + + + + + + + + + + ---- -==== -A typical configuration for a **production** environment might look like +[source,xml] +---- + + + + + + + + + + + + + + + + + + + +---- -[tabs] -==== -XML:: -+ -.Snippet from an example {antora-examples-url}/manual/appenders/console-prod.xml[`log4j2.xml`] -[source,xml,indent=0] +[source,java] ---- -include::example$manual/appenders/console-prod.xml[tag=appender] +package net.example.db; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Properties; + +import javax.sql.DataSource; + +import org.apache.commons.dbcp.DriverManagerConnectionFactory; +import org.apache.commons.dbcp.PoolableConnection; +import org.apache.commons.dbcp.PoolableConnectionFactory; +import org.apache.commons.dbcp.PoolingDataSource; +import org.apache.commons.pool.impl.GenericObjectPool; + +public class ConnectionFactory { + private interface Singleton { + ConnectionFactory INSTANCE = new ConnectionFactory(); + } + + private final DataSource dataSource; + + private ConnectionFactory() { + Properties properties = new Properties(); + properties.setProperty("user", "logging"); + properties.setProperty("password", "abc123"); // or get properties from some configuration file + + GenericObjectPool pool = new GenericObjectPool(); + DriverManagerConnectionFactory connectionFactory = new DriverManagerConnectionFactory( + "jdbc:mysql://example.org:3306/exampleDb", properties + ); + new PoolableConnectionFactory( + connectionFactory, pool, null, "SELECT 1", 3, false, false, Connection.TRANSACTION_READ_COMMITTED + ); + + this.dataSource = new PoolingDataSource(pool); + } + + public static Connection getDatabaseConnection() throws SQLException { + return Singleton.INSTANCE.dataSource.getConnection(); + } +} ---- -JSON:: -+ -.Snippet from an example {antora-examples-url}/manual/appenders/console-prod.json[`log4j2.json`] -[source,json,indent=0] +This appender is {log4j2-url}/manual/messages.html#MapMessage[`MapMessage`]-aware. + +The following configuration uses no layout to indicate that the appender should match the keys of a `MapMessage` to the names of +`ColumnMapping`s when setting the values of the Appender's SQL INSERT +statement. This lets you insert rows for custom values in a database +table based on a Log4j `MapMessage` instead of values from `LogEvent`. + +[source,xml] ---- -include::example$manual/appenders/console-prod.json[tag=appender] + + + + + + + + + + + + + + + + + + + + + + + + + ---- -YAML:: -+ -.Snippet from an example {antora-examples-url}/manual/appenders/console-prod.yaml[`log4j2.yaml`] -[source,yaml,indent=0] +[#jms-appender] +=== [[JMSAppender]]JMS Appender + +The JMS Appender sends the formatted log event to a JMS Destination. + +The JMS Appender requires JNDI support so as of release 2.17.0, this appender will not function unless `log4j2.enableJndiJms=true` is configured as a system property or environment variable. +See the https://logging.apache.org/log4j/2.x/manual/configuration.html#enableJndiJms[enableJndiJms] system property. + +Note that in Log4j 2.0, this appender was split into a JMSQueueAppender and a JMSTopicAppender. +Starting in Log4j 2.1, these appenders were combined into the JMS Appender, which makes no distinction between queues and topics. +However, configurations written for 2.0 that use the `` or `` elements will continue to work with the new `` configuration element. + +.JMS Appender Parameters +[cols="1,1,1,3",options="header"] +|=== +| Type | `boolean` +| Default value | `true` +|=== + +Here is a sample JMS Appender configuration: + +[source,xml] ---- -include::example$manual/appenders/console-prod.yaml[tag=appender] + + + + + + + + + + + + + ---- -Properties:: -+ -.Snippet from an example {antora-examples-url}/manual/appenders/console-prod.properties[`log4j2.properties`] -[source,properties,indent=0] +To map your Log4j `MapMessage` to JMS `javax.jms.MapMessage`, set the layout of the appender to `MessageLayout` with `<MessageLayout />` (Since 2.9.): + +[source,xml] ---- -include::example$manual/appenders/console-prod.properties[tag=appender] + + + + + + + + + + + + + ---- -==== -<1> Improve performance by setting <> to `true`. -<2> Use a structured layout. -Additional dependencies are required, see xref:manual/json-template-layout.adoc[]. +[[JPAAppender]] +=== JPAAppender -[#file-appenders] -=== File appenders +As of Log4j 2.11.0, JPA support has moved from the existing module `log4j-core` to the new module `log4j-jpa`. -File appenders write logs to the filesystem. -They can be further split into: +The JPAAppender writes log events to a relational database table using the Java Persistence API 2.1. +It requires the API and a provider implementation to be on the classpath. +It also requires a decorated entity configured to persist to the table desired. -Single file appenders::: -See xref:manual/appenders/file.adoc[] for details. +If you want to use the default mappings, you can extend `org.apache.logging.log4j.core.appender.db.jpa.BasicLogEventEntity` and provide an `@Id` property. +If you want to significantly customize the mappings, you can extend `org.apache.logging.log4j.core.appender.db.jpa.AbstractLogEventWrapperEntity`. -Rolling file appenders::: -See xref:manual/appenders/rolling-file.adoc[] for details. +See the Javadoc or source code for these two classes for more information and examples. -[#database-appenders] -=== Database appenders +[width="100%",options="header"] +|=== +|Parameter Name |Type |Description -The appenders write log events directly to a database. +|name +|String +|_Required._ The name of the Appender. -xref:manual/appenders/database.adoc#JdbcAppender[JDBC appender]:: -Sends log events to a JDBC driver +|ignoreExceptions +|boolean +|The default is `true`, causing exceptions encountered while appending events to be internally logged and then ignored. When set to `false` exceptions will be propagated to the caller, instead. You must set this to `false` when wrapping this Appender in a FailoverAppender. -xref:manual/appenders/database.adoc#NoSqlAppender[NoSQL appender]:: -Store log events to a document-oriented database +|filter +|Filter +|A Filter to determine if the event should be handled by this Appender. More than one Filter may be used by using a CompositeFilter. -See xref:manual/appenders/database.adoc[] for details. +|bufferSize +|int +|If an integer is greater than 0, this causes the appender to buffer log events and flush whenever the buffer reaches this size. -[#network-appenders] -=== Network appenders +|entityClassName +|String +|_Required._ The fully qualified name of the concrete LogEventWrapperEntity implementation that has JPA annotations mapping it to a database table. -These appenders use simple network protocols to transmit log events to a remote host. -The supported network protocols are: +|persistenceUnitName +|String +|_Required._ The name of the JPA persistence unit that should be used for persisting log events. +|=== -`UDP`:: -`TCP`:: -These are handled by the xref:manual/appenders/network.adoc#SocketAppender[Socket Appender]. +Here is a sample configuration for the JPAAppender. +The first XML sample is the Log4j configuration file, the second is the `persistence.xml` file. +EclipseLink is assumed here, but any JPA 2.1 or higher provider will do. +You should _always_ create a _separate_ persistence unit for logging, for two reasons. +First, `` _must_ be set to "NONE," which is usually not desired in normal JPA usage. +Also, for performance reasons the logging entity should be isolated in its persistence unit away from all other entities and you should use a non-JTA data source. +Note that your persistence unit _must_ also contain `` elements for all of the `org.apache.logging.log4j.core.appender.db.jpa.converter` converter classes. -`HTTP`:: -This is handled by the xref:manual/appenders/network.adoc#HttpAppender[HTTP Appender]. +[source,xml] +---- + + + + + + + + + + + +---- -`SMTP`:: -This is handled by the xref:manual/appenders/network.adoc#HttpAppender[SMTP Appender]. +[source,xml] +---- + + + + + org.eclipse.persistence.jpa.PersistenceProvider + org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapAttributeConverter + org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapJsonAttributeConverter + org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackAttributeConverter + org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackJsonAttributeConverter + org.apache.logging.log4j.core.appender.db.jpa.converter.MarkerAttributeConverter + org.apache.logging.log4j.core.appender.db.jpa.converter.MessageAttributeConverter + org.apache.logging.log4j.core.appender.db.jpa.converter.StackTraceElementAttributeConverter + org.apache.logging.log4j.core.appender.db.jpa.converter.ThrowableAttributeConverter + com.example.logging.JpaLogEntity + jdbc/LoggingDataSource + NONE + + + +---- -See xref:manual/appenders/network.adoc[] for details. +[source,java] +---- +package com.example.logging; +... +@Entity +@Table(name="application_log", schema="dbo") +public class JpaLogEntity extends BasicLogEventEntity { + private static final long serialVersionUID = 1L; + private long id = 0L; + + public TestEntity() { + super(null); + } + public TestEntity(LogEvent wrappedEvent) { + super(wrappedEvent); + } + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + public long getId() { + return this.id; + } + + public void setId(long id) { + this.id = id; + } + + // If you want to override the mapping of any properties mapped in BasicLogEventEntity, + // just override the getters and re-specify the annotations. +} +---- -[#message-queue-appenders] -=== Message queue appenders +[source,java] +---- +package com.example.logging; +... +@Entity +@Table(name="application_log", schema="dbo") +public class JpaLogEntity extends AbstractLogEventWrapperEntity { + private static final long serialVersionUID = 1L; + private long id = 0L; + + public TestEntity() { + super(null); + } + public TestEntity(LogEvent wrappedEvent) { + super(wrappedEvent); + } + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "logEventId") + public long getId() { + return this.id; + } + + public void setId(long id) { + this.id = id; + } + + @Override + @Enumerated(EnumType.STRING) + @Column(name = "level") + public Level getLevel() { + return this.getWrappedEvent().getLevel(); + } + + @Override + @Column(name = "logger") + public String getLoggerName() { + return this.getWrappedEvent().getLoggerName(); + } + + @Override + @Column(name = "message") + @Convert(converter = MyMessageConverter.class) + public Message getMessage() { + return this.getWrappedEvent().getMessage(); + } + ... +} +---- -Message queue appenders forward log events to a message broker. -The following systems are supported: +[#HttpAppender] +=== HttpAppender -xref:manual/appenders/message-queue.adoc#FlumeAppender[Flume appender]:: -Forwards log events to an -https://flume.apache.org/[Apache Flume] server. +The HttpAppender sends log events over HTTP. +A Layout must be provided to format the LogEvent. -xref:manual/appenders/message-queue.adoc#JmsAppender[JMS appender]:: -Forwards log events to a -https://jakarta.ee/specifications/messaging/2.0/[Jakarta Message 2.0] broker. +It will set the `Content-Type` header according to the layout. +Additional headers can be specified with embedded Property elements. -See xref:manual/appenders/message-queue.adoc[] for details. +It will also wait for a response from the server, and throw an error if no 2xx response is received. -[#ServletAppender] -=== Servlet Appender +Implemented with +https://docs.oracle.com/javase/{java-target-version}/docs/api/java/net/HttpURLConnection.html[`HttpURLConnection`]. -The Servlet appender allows users to forward all logging calls to the -https://jakarta.ee/specifications/servlet/5.0/apidocs/jakarta/servlet/servletcontext#log(java.lang.String,java.lang.Throwable)[`ServletContext.log()`] -methods. +.HttpAppender Parameters +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|name |String |The name of the Appender. -[CAUTION] -==== -The `ServletContext.log(String, Throwable)` method predates modern logging APIs. -By using Servlet appender, you typically will not be able to differentiate log events by log level or logger name. -==== +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. -The Servlet Appender has no configuration attributes. +|layout |Layout |The Layout to use to format the LogEvent. -xref:plugin-reference.adoc#org-apache-logging-log4j_log4j-jakarta-web_org-apache-logging-log4j-web-appender-ServletAppender[{plugin-reference-marker} Plugin reference for `Servlet`] +|Ssl |SslConfiguration |Contains the configuration for the KeyStore and +TrustStore for https. Optional, uses Java runtime defaults if not +specified. See <>. -You can use it by declaring an appender of type `Servlet` in your configuration file: +|verifyHostname |boolean |Whether to verify server hostname against +certificate. Only valid for https. Optional, defaults to true -[tabs] -==== -XML:: -+ -[source,xml,indent=0] +|url |string |The URL to use. The URL scheme must be "http" or "https". + +|method |string |The HTTP method to use. Optional, default is "POST". + +|connectTimeoutMillis |integer |The connect timeout in milliseconds. +Optional, default is 0 (infinite timeout). + +|readTimeoutMillis |integer |The socket read timeout in milliseconds. +Optional, default is 0 (infinite timeout). + +|headers |Property[] |Additional HTTP headers to use. The values support +xref:manual/lookups.adoc[lookups]. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a <>. +|======================================================================= + +Here is a sample HttpAppender configuration snippet: + +[source,xml] +---- + + + + + + + + + + + + + + + +---- + +[[KafkaAppender]] +=== KafkaAppender + +The KafkaAppender logs events to an https://kafka.apache.org/[Apache Kafka] topic. +Each log event is sent as a Kafka record. + +[width="100%",options="header"] +|=== +|Parameter Name |Type |Description + +|topic +|String +|The Kafka topic to use. Required. + +|key +|String +|The key that will be sent to Kafka with every message. Optional value defaulting to `null`. Any of the xref:manual/lookups.adoc[Lookups] can be included. + +|filter +|Filter +|A Filter to determine if the event should be handled by this Appender. More than one Filter may be used by using a CompositeFilter. + +|layout +|Layout +|The Layout to use to format the LogEvent. Required, there is no default. _New since 2.9, in previous versions `` was default._ + +|name +|String +|The name of the Appender. Required. + +|ignoreExceptions +|boolean +|The default is `true`, causing exceptions encountered while appending events to be internally logged and then ignored. When set to `false` exceptions will be propagated to the caller, instead. You must set this to `false` when wrapping this Appender in a <>. + +|syncSend +|boolean +|The default is `true`, causing sends to block until the record has been acknowledged by the Kafka server. When set to `false`, sends a return immediately, allowing for lower latency and significantly higher throughput. _New since 2.8. Be aware that this is a new addition, and it has not been extensively tested. +Any failure sending to Kafka will be reported as an error to {log4j2-url}/manual/status-logger.html[status logger] and the log event will be dropped (the ignoreExceptions parameter will not be effective). +Log events may arrive out of order on the Kafka server._ + +|properties +|Property[] +|You can set properties in https://kafka.apache.org/documentation.html#producerconfigs[Kafka producer properties]. You need to set the `bootstrap.servers` property, there are sensible default values for the others. Do not set the `value.serializer` nor `key.serializer` properties. +|=== + +Here is a sample KafkaAppender configuration snippet: + +[source,xml] ---- -include::example$manual/appenders/servlet-appender.xml[tag=servlet] + + + + + + + localhost:9092 + + + + ---- -JSON:: -+ -[source,xml,indent=0] +This appender is synchronous by default and will block until the record has been acknowledged by the Kafka server, timeout for this can be set with the `timeout.ms` property (defaults to 30 seconds). +Wrap with https://logging.apache.org/log4j/2.x/manual/appenders.html#AsyncAppender[Async appender] and/or set syncSend to `false` to log asynchronously. + +This appender requires the https://kafka.apache.org/[Kafka client library]. +Note that you need to use a version of the Kafka client library matching the Kafka server used. + +_Note:_ Make sure to not let `org.apache.kafka` log to a Kafka appender on DEBUG level, since that will cause recursive logging: + +[source,xml] ---- -include::example$manual/appenders/servlet-appender.json[tag=servlet] + + + + + + + + + + + ---- -YAML:: -+ -[source,xml,indent=0] +[#MemoryMappedFileAppender] +=== MemoryMappedFileAppender + +_New since 2.1. Be aware that this is a new addition, and although it has been tested on several platforms, it does not have as much track record as the other file appenders._ + +The MemoryMappedFileAppender maps a part of the specified file into memory and writes log events to this memory, relying on the operating system's virtual memory manager to synchronize the changes to the storage device. +The main benefit of using memory-mapped files is I/O performance. +Instead of making system calls to write to disk, this appender can simply change the program's local memory, which is orders of magnitude faster. +Also, in most operating systems the memory region mapped is the kernel's +http://en.wikipedia.org/wiki/Page_cache[page cache] (file cache), meaning that no copies need to be created in user space. + +// TODO: +// performance tests that compare performance of this appender to +// RandomAccessFileAppender and FileAppender.) + +There is some overhead with mapping a file region into memory, especially very large regions (half a gigabyte or more). +The default region size is 32 MB, which should strike a reasonable balance between the frequency and the duration of remap operations. + +// (TODO: performance test remapping various sizes.) + +Similar to the FileAppender and the RandomAccessFileAppender, MemoryMappedFileAppender uses a MemoryMappedFileManager to actually perform the file I/O. While MemoryMappedFileAppender from different Configurations cannot be shared, the MemoryMappedFileManagers can be if the manager is accessible. +For example, two web applications in a servlet container can have its own configuration and safely write to the same file if Log4j is in a ClassLoader that is common to both of them. + +.MemoryMappedFileAppender Parameters +[width="100%",cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|append |boolean |When true - the default, records will be appended to +the end of the file. When set to false, the file will be cleared before +new records are written. + +|fileName |String |The name of the file to write to. If the file, or any +of its parent directories, do not exist, they will be created. + +|filters |Filter |A Filter to determine if the event should be handled +by this Appender. More than one Filter may be used by using a +CompositeFilter. + +|immediateFlush |boolean a| +When set to true, each write will be followed by a call to +https://docs.oracle.com/javase/{java-target-version}/docs/api/java/nio/MappedByteBuffer.html#force()[`MappedByteBuffer#force()`]. +This will guarantee the data is written to the storage device. + +The default for this parameter is `false`. This means that the data is +written to the storage device even if the Java process crashes, but +there may be data loss if the operating system crashes. + +Note that manually forcing a sync on every log event loses most of the +performance benefits of using a memory-mapped file. + +Flushing after every write is only useful when using this appender with +synchronous loggers. Asynchronous loggers and appenders will +automatically flush at the end of a batch of events, even if +immediateFlush is set to false. This also guarantees the data is written +to disk but is more efficient. + +|regionLength |int |The length of the mapped region, defaults to 32 MB +(32 * 1024 * 1024 bytes). This parameter must be a value between 256 and +1,073,741,824 (1 GB or 2^30); values outside this range will be adjusted +to the closest valid value. Log4j will round the specified value up to +the nearest power of two. + +|layout |Layout |The Layout to use to format the LogEvent. If no layout +is supplied the default pattern layout of "%m%n" will be used. + +|name |String |The name of the Appender. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a <>. +|======================================================================= + +Here is a sample MemoryMappedFile configuration: + +[source,xml] ---- -include::example$manual/appenders/servlet-appender.yaml[tag=servlet] + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + ---- -Properties:: -+ -[source,xml,indent=0] +[#NoSQLAppender] +=== NoSQLAppender + +The NoSQLAppender writes log events to a NoSQL database using an internal lightweight provider interface. +Provider implementations currently exist for MongoDB, and writing a custom provider is quite simple. + +.NoSQLAppender Parameters +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|name |String |_Required._ The name of the Appender. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a <>. + +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. + +|bufferSize |int |If an integer is greater than 0, this causes the appender +to buffer log events and flush whenever the buffer reaches this size. + +|NoSqlProvider |NoSQLProvider>> |_Required._ The NoSQL provider that provides +connections to the chosen NoSQL database. +|======================================================================= + +You specify which NoSQL provider to use by specifying the appropriate configuration element within the `` element. +The only type currently supported is ``. +To create your custom provider, read the JavaDoc for the `NoSQLProvider`, `NoSQLConnection`, and `NoSQLObject` classes and the documentation about creating Log4j plugins. +We recommend you review the source code for the MongoDB providers as a guide for creating your provider. + +The following example demonstrates how log events are persisted in NoSQL databases if represented in a JSON format: + +[source,json] ---- -include::example$manual/appenders/servlet-appender.properties[tag=servlet] +{ + "level": "WARN", + "loggerName": "com.example.application.MyClass", + "message": "Something happened that you might want to know about.", + "source": { + "className": "com.example.application.MyClass", + "methodName": "exampleMethod", + "fileName": "MyClass.java", + "lineNumber": 81 + }, + "marker": { + "name": "SomeMarker", + "parent" { + "name": "SomeParentMarker" + } + }, + "threadName": "Thread-1", + "millis": 1368844166761, + "date": "2013-05-18T02:29:26.761Z", + "thrown": { + "type": "java.sql.SQLException", + "message": "Could not insert record. Connection lost.", + "stackTrace": [ + { "className": "org.example.sql.driver.PreparedStatement$1", "methodName": "responder", "fileName": "PreparedStatement.java", "lineNumber": 1049 }, + { "className": "org.example.sql.driver.PreparedStatement", "methodName": "executeUpdate", "fileName": "PreparedStatement.java", "lineNumber": 738 }, + { "className": "com.example.application.MyClass", "methodName": "exampleMethod", "fileName": "MyClass.java", "lineNumber": 81 }, + { "className": "com.example.application.MainClass", "methodName": "main", "fileName": "MainClass.java", "lineNumber": 52 } + ], + "cause": { + "type": "java.io.IOException", + "message": "Connection lost.", + "stackTrace": [ + { "className": "java.nio.channels.SocketChannel", "methodName": "write", "fileName": null, "lineNumber": -1 }, + { "className": "org.example.sql.driver.PreparedStatement$1", "methodName": "responder", "fileName": "PreparedStatement.java", "lineNumber": 1032 }, + { "className": "org.example.sql.driver.PreparedStatement", "methodName": "executeUpdate", "fileName": "PreparedStatement.java", "lineNumber": 738 }, + { "className": "com.example.application.MyClass", "methodName": "exampleMethod", "fileName": "MyClass.java", "lineNumber": 81 }, + { "className": "com.example.application.MainClass", "methodName": "main", "fileName": "MainClass.java", "lineNumber": 52 } + ] + } + }, + "contextMap": { + "ID": "86c3a497-4e67-4eed-9d6a-2e5797324d7b", + "username": "JohnDoe" + }, + "contextStack": [ + "topItem", + "anotherItem", + "bottomItem" + ] +} ---- -==== -<1> Encodes events using xref:manual/pattern-layout.adoc[] and forwards the call to -`ServletContext.log()`. -Setting `alwaysWriteExceptions` to `false` prevents the stacktrace from appearing as both part of the `message` argument and as `throwable` argument: -this usually results in the stacktrace being printed to the log file twice. +[#NoSQLAppenderMongoDB] +==== NoSQL providers for MongoDB -Additional runtime dependencies are required for using the servlet appender: +[#mongo-installation] +===== Installation -include::partial$features/servlet-support.adoc[] +Starting with version 2.11.0, Log4j supplies providers for the +https://www.mongodb.com/[MongoDB] +NoSQL database engine, based on the +https://www.mongodb.com/docs/drivers/java/sync/current/[MongoDB synchronous Java driver]. +The choice of the provider to user depends on: -See xref:jakarta.adoc[] for more information. +* the major version of the MongoDB Java driver your application uses: Log4j supports all major versions starting from version 2. +* the type of driver API used: either the _Legacy API_ or the _Modern API_. +See https://www.mongodb.com/docs/drivers/java/sync/current/legacy/[MongoDB documentation] +for the difference between APIs. -[#delegating-appenders] -=== Delegating appenders +[NOTE] +==== +The list of dependencies of your application provides a hint as to which driver API your application is using. +If your application contains any one of these dependencies, it might use the **Legacy API**: + +* `org.mongodb:mongo-java-driver` +* `org.mongodb:mongodb-driver-legacy` + +If you application only uses `org.mongodb:mongodb-driver-sync`, it uses the **Modern API**. +==== -Delegating appenders are intended to decorate other appenders: +[WARNING] +==== +The version of the MongoDB Java driver is not the same as the version of the MongoDB server. +See +https://www.mongodb.com/docs/drivers/java/sync/current/compatibility/[MongoDB compatibility matrix] +for more information. +==== -xref:manual/appenders/delegating.adoc#AsyncAppender[Asynchronous appender]:: -Perform all I/O on a dedicated thread +In order to use a Log4j MongoDB appender you need to add the following dependencies to your application: -xref:manual/appenders/delegating.adoc#FailoverAppender[Failover appender]:: -Provide a backup appender in case an appender fails +.MongoDB providers compatibility table +[cols="2,2,2,5"] +|=== +| Driver version | Driver API | Log4j artifact | Notes -xref:manual/appenders/delegating.adoc#RewriteAppender[Rewrite appender]:: -Modify log events prior to delivering them to the target +| `2.x` +| Legacy +| https://central.sonatype.com/artifact/org.apache.logging.log4j/log4j-mongodb2[`log4j-mongodb2`] +| Reached end-of-support. -xref:manual/appenders/delegating.adoc#RoutingAppender[Routing appender]:: -Dynamically choose a different appender for each log event +Last released version: `2.12.4` -See xref:manual/appenders/delegating.adoc[] for details. +| [[NoSQLAppenderMongoDB3]]`3.x` +| Legacy +| https://central.sonatype.com/artifact/org.apache.logging.log4j/log4j-mongodb3[`log4j-mongodb3`] +| Reached end-of-support. + +Last released version: `2.23.1` + +| `4.x` +| Modern +| https://central.sonatype.com/artifact/org.apache.logging.log4j/log4j-mongodb4[`log4j-mongodb4`] +| Reached end-of-support. + +Last released version: `2.23.1` + +| `5.x` or later +| Modern +| https://central.sonatype.com/artifact/org.apache.logging.log4j/log4j-mongodb[`log4j-mongodb`] +| +|=== + +[TIP] +==== +If logging is important for your business, consider using a +xref:manual/appenders/delegating.adoc#FailoverAppender[`Failover` Appender] +to redirect log events to a different appender in case of exceptions. +==== + +[#log4j-mongodb] +===== NoSQL provider for MongoDB (current) + +The following configuration attributes are also evaluated at runtime, so can contain escaped `$$+{...}+` property substitution expressions. + +.List of attributes evaluated at runtime +[cols="1,1,1,1"] +|=== +| Component | Parameter | Event type | Evaluation context + +| xref:manual/appenders/network.adoc#HttpAppender[HTTP Appender] +| xref:manual/appenders/network.adoc#HttpAppender-element-Property[`Property/value`] +| Log event +| xref:manual/lookups.adoc#global-context[_global_] + +| xref:manual/appenders/database.adoc#NoSqlAppender[NoSQL Appender] +| xref:manual/appenders/database.adoc#NoSqlAppender-element-KeyValuePair[`KeyValuePair/value`] +| Log event +| xref:manual/lookups.adoc#global-context[_global_] + +| xref:manual/appenders/delegating.adoc#PropertiesRewritePolicy[PropertiesRewrite Policy] +| xref:manual/appenders/delegating.adoc#PropertiesRewritePolicy-element-Property[`Property/value`] +| Log event +| xref:manual/lookups.adoc#global-context[_global_] + +| xref:manual/appenders/delegating.adoc#Routes[Routes Container] +| xref:manual/appenders/delegating.adoc#Routes-attr-pattern[`pattern`] +| Log event +| xref:manual/lookups.adoc#event-context[_log event_] + +| xref:manual/appenders/rolling-file.adoc[Rolling File Appenders] +| xref:manual/appenders/rolling-file.adoc#attr-filePattern[`filePattern`] +| Rollover +| xref:manual/lookups.adoc#global-context[_global_] + +| xref:manual/appenders/rolling-file.adoc#AbstractPathAction[Optional Rollover Actions] +| xref:manual/appenders/rolling-file.adoc#AbstractPathAction-attr-basePath[`basePath`] +| Rollover +| xref:manual/lookups.adoc#global-context[_global_] + +|=== + +[source,xml] +---- + + + + + + + + + + + + + + + + + +---- + +[#OutputStreamAppender] +=== OutputStreamAppender + +The OutputStreamAppender provides the base for many of the other Appenders such as the File and Socket appenders that write the event to an Output Stream. +It cannot be directly configured. +Support for immediateFlush and buffering is provided by the OutputStreamAppender. +The OutputStreamAppender uses an OutputStreamManager to handle the actual I/O, allowing the stream to be shared by Appenders in multiple configurations. + +[#RandomAccessFileAppender] +=== RandomAccessFileAppender + +The RandomAccessFileAppender is similar to the standard +<> except it is always buffered (this cannot be switched off) and internally it uses a +`ByteBuffer + RandomAccessFile` instead of a `BufferedOutputStream`. +We saw a 20-200% performance improvement compared to FileAppender with "bufferedIO=true" in our +measurements. +Similar to the FileAppender, RandomAccessFileAppender uses a RandomAccessFileManager to perform the file I/O. While RandomAccessFileAppender from different Configurations cannot be shared, the RandomAccessFileManagers can be if the Manager is accessible. +For example, two web applications in a servlet container can have their configuration and safely write to the same file if Log4j is in a ClassLoader that is common to both of them. + +.RandomAccessFileAppender Parameters +[width="100%",cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|append |boolean |When true - the default, records will be appended to +the end of the file. When set to false, the file will be cleared before +new records are written. + +|fileName |String |The name of the file to write to. If the file, or any +of its parent directories, do not exist, they will be created. + +|filters |Filter |A Filter to determine if the event should be handled +by this Appender. More than one Filter may be used by using a +CompositeFilter. + +|immediateFlush |boolean a| +When set to true - the default, each write will be followed by a flush. +This will guarantee that the data is passed to the operating system for writing; +it does not guarantee that the data is written to a physical device +such as a disk drive. + +Note that if this flag is set to false, and the logging activity is sparse, +there may be an indefinite delay in the data eventually making it to the +operating system, because it is held up in a buffer. +This can cause surprising effects such as the logs not +appearing in the tail output of a file immediately after writing to the log. + +Flushing after every write is only useful when using this appender with +synchronous loggers. Asynchronous loggers and appenders will +automatically flush at the end of a batch of events, even if +immediateFlush is set to false. This also guarantees the data is passed +to the operating system but is more efficient. + +|bufferSize |int |The buffer size, defaults to 262,144 bytes (256 * +1024). + +|layout |Layout |The Layout to use to format the LogEvent. If no layout +is supplied the default pattern layout of "%m%n" will be used. + +|name |String |The name of the Appender. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a <>. +|======================================================================= + +Here is a sample RandomAccessFile configuration: + +[source,xml] +---- + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + +---- + +[#RewriteAppender] +=== RewriteAppender + +The RewriteAppender allows the LogEvent to be manipulated before it is processed by another Appender. +This can be used to mask sensitive information such as passwords or to inject information into each event. +The RewriteAppender must be configured with a RewritePolicy. +The RewriteAppender should be configured after any Appenders it references to allow it to shut down properly. + +.RewriteAppender Parameters +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|AppenderRef |String |The name of the Appenders to call after the +LogEvent has been manipulated. Multiple AppenderRef elements can be +configured. + +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. + +|name |String |The name of the Appender. + +|rewritePolicy |RewritePolicy |The RewritePolicy that will manipulate +the LogEvent. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a <>. +|======================================================================= + +[#RewritePolicy] +==== RewritePolicy + +RewritePolicy is an interface that allows implementations to inspect and possibly modify LogEvents before they are passed to Appender. +RewritePolicy declares a single method named rewrite that must be implemented. +The method is passed the LogEvent and can return the same event or create a new one. + +===== MapRewritePolicy + +MapRewritePolicy will evaluate LogEvents that contain a MapMessage and will add or update elements of the Map. + +[cols="20%,20%,60%",options="header",] +|================================================================ +|Parameter Name |Type |Description +|mode |String |"Add" or "Update" +|keyValuePair |KeyValuePair[] |An array of keys and their values. +|================================================================ + +The following configuration shows a RewriteAppender configured to add a product key and its value to the MapMessage.: + +[source,xml] +---- + + + + + + + + + + + + + + + + + + + +---- + +===== PropertiesRewritePolicy + +PropertiesRewritePolicy will add properties configured on the policy to the ThreadContext Map being logged. +The properties will not be added to the actual ThreadContext Map. +The property values may contain variables that will be evaluated when the configuration is processed as well as when the event is logged. + +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|properties |Property[] |One of more Property elements to define the +keys and values to be added to the ThreadContext Map. +|======================================================================= + +The following configuration shows a RewriteAppender configured to add a product key and its value to the MapMessage: + +[source,xml] +---- + + + + + + + + + + ${sys:user.name} + ${sys:environment} + + + + + + + + + +---- + +===== LoggerNameLevelRewritePolicy + +You can use this policy to make loggers in third-party code less chatty by changing event levels. +The LoggerNameLevelRewritePolicy will rewrite log event levels for a given logger name prefix. +You configure a LoggerNameLevelRewritePolicy with a logger name prefix and a pair of levels, where a pair defines a source level and a target level. + +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|logger |String |A logger name used as a prefix to test each event's +logger name. + +|LevelPair |KeyValuePair[] |An array of keys and their values, each key +is a source level, each value a target level. +|======================================================================= + +The following configuration shows a RewriteAppender configured to map level INFO to DEBUG and level WARN to INFO for all loggers that start with `com.foo.bar`. + +[source,xml] +---- + + + + + + + + + + + + + + + + + + + + +---- + +[id=rollingfileappender] +=== [[RollingFileAppender]] RollingFileAppender + +The RollingFileAppender is an OutputStreamAppender that writes to the file named in the fileName parameter and rolls the file over according to the `TriggeringPolicy` and the `RolloverPolicy`. +The `RollingFileAppender` +uses a `RollingFileManager` (which extends `OutputStreamManager`) to perform the file I/O and perform the rollover. +While `RolloverFileAppenders` from different Configurations cannot be shared, the `RollingFileManagers` can be if the Manager is accessible. +For example, two web applications in a servlet container can have their configuration and safely write to the same file if Log4j is in a +`ClassLoader` that is common to both of them. + +A RollingFileAppender requires a <> and a <>. +The triggering policy determines if a rollover should be performed while the `RolloverStrategy` +defines how the rollover should be done. +If no `RolloverStrategy` is configured, `RollingFileAppender` will use the +<>. +Since log4j-2.5, a <> can be configured in the DefaultRolloverStrategy to run at rollover. +Since 2.8 if no file name is configured then +<> will be used instead of DefaultRolloverStrategy. +Since log4j-2.9, a +<> can be configured in the DefaultRolloverStrategy to run at rollover, if not defined, the inherited POSIX file attribute view from the RollingFileAppender will be applied. + +File locking is not supported by the RollingFileAppender. + +.RollingFileAppender Parameters +[width="100%",cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|append |boolean |When true - the default, records will be appended to +the end of the file. When set to false, the file will be cleared before +new records are written. + +|bufferedIO |boolean |When true - the default, records will be written +to a buffer and the data will be written to disk when the buffer is full +or, if immediateFlush is set, when the record is written. File locking +cannot be used with bufferedIO. Performance tests have shown that using +buffered I/O significantly improves performance, even if immediateFlush +is enabled. + +|bufferSize |int |When bufferedIO is true, this is the buffer size, the +default is 8192 bytes. + +|createOnDemand |boolean |The appender creates the file on-demand. The +appender only creates the file when a log event passes all filters and +is routed to this appender. Defaults to false. + +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. + +|fileName |String |The name of the file to write to. If the file, or any +of its parent directories, do not exist, they will be created. + +|filePattern |String |The pattern of the file name of the archived log +file. The format of the pattern is dependent on the `RolloverPolicy` that +is used. The DefaultRolloverPolicy will accept both a date/time pattern +compatible with +https://download.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html[`SimpleDateFormat`] +and/or a %i which represents an integer counter. The integer counter +allows specifying a padding, like %3i for space-padding the counter to +3 digits or (usually more useful) %03i for zero-padding the counter to +3 digits. The pattern also +supports interpolation at runtime so any of the Lookups (such as the +xref:manual/lookups.adoc#DateLookup[DateLookup]) can be included in the +pattern. + +|immediateFlush |boolean a| +When set to true - the default, each write will be followed by a flush. +This will guarantee that the data is passed to the operating system for writing; +it does not guarantee that the data is written to a physical device +such as a disk drive. + +Note that if this flag is set to false, and the logging activity is sparse, +there may be an indefinite delay in the data eventually making it to the +operating system, because it is held up in a buffer. +This can cause surprising effects such as the logs not +appearing in the tail output of a file immediately after writing to the log. + +Flushing after every write is only useful when using this appender with +synchronous loggers. Asynchronous loggers and appenders will +automatically flush at the end of a batch of events, even if +immediateFlush is set to false. This also guarantees the data is passed +to the operating system but is more efficient. + +|layout |Layout |The Layout to use to format the LogEvent. If no layout +is supplied the default pattern layout of "%m%n" will be used. + +|name |String |The name of the Appender. + +|policy |TriggeringPolicy |The policy to use to determine if a rollover +should occur. + +|strategy |RolloverStrategy |The strategy to use to determine the name +and the location of the archive file. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a <>. + +|filePermissions |String a| +File attribute permissions in POSIX format to apply whenever the file is +created. + +The underlying files system shall support +https://docs.oracle.com/javase/7/docs/api/java/nio/file/attribute/PosixFileAttributeView.html[POSIX] +file attribute view. + +Examples: rw------- or rw-rw-rw- etc... + +|fileOwner |String a| +File owner to define whenever the file is created. + +Changing the file's owner may be restricted for security reasons and +Operation not permitted IOException thrown. Only processes with an +effective user ID equal to the user ID of the file or with appropriate +privileges may change the ownership of a file if +http://www.gnu.org/software/libc/manual/html_node/Options-for-Files.html[_POSIX_CHOWN_RESTRICTED] +is in effect for path. + +The underlying files system shall support file +https://docs.oracle.com/javase/7/docs/api/java/nio/file/attribute/FileOwnerAttributeView.html[owner] +attribute view. + +|fileGroup |String a| +File group to define whenever the file is created. + +The underlying files system shall support +https://docs.oracle.com/javase/7/docs/api/java/nio/file/attribute/PosixFileAttributeView.html[POSIX] +file attribute view. + +|======================================================================= + +[#TriggeringPolicies] +=== TriggeringPolicies + +==== Composite Triggering Policy + +The `CompositeTriggeringPolicy` combines multiple triggering policies and returns true if any of the configured policies return true. +The +`CompositeTriggeringPolicy` is configured simply by wrapping other policies in a `Policies` element. + +For example, the following XML fragment defines policies that rollover the log when the JVM starts when the log size reaches twenty megabytes, and when the current date no longer matches the log's start date. + +[source,xml] +---- + + + + + +---- + +==== Cron Triggering Policy + +The `CronTriggeringPolicy` triggers rollover based on a cron expression. +This policy is controlled by a timer and is asynchronous in processing log events, so it is possible that log events from the previous or next period may appear at the beginning or end of the log file. +The `filePattern` attribute of the Appender should contain a timestamp otherwise the target file will be overwritten on each rollover. + +.CronTriggeringPolicy Parameters +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|schedule |String |The cron expression. The expression is the same as +what is allowed in the Quartz scheduler. See +link:../javadoc/log4j-core/org/apache/logging/log4j/core/util/CronExpression.html[`CronExpression`] +for a full description of the expression. + +|evaluateOnStartup |boolean |On startup the cron expression will be +evaluated against the file's last modification timestamp. If the cron +expression indicates a rollover should have occurred between that time +and the current time the file will be immediately rolled over. +|======================================================================= + +==== OnStartup Triggering Policy + +The `OnStartupTriggeringPolicy` policy causes a rollover if the log file is older than the current JVM's start time and the minimum file size is met or exceeded. + +.OnStartupTriggeringPolicy Parameters +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|minSize |long |The minimum size the file must have to roll over. A size +of zero will cause a rollover no matter what the file size is. The +default value is 1, which will prevent rolling over an empty file. +|======================================================================= + +_Google App Engine note:_ + +When running in Google App Engine, the OnStartup policy causes a rollover if the log file is older than _the time when Log4J initialized_. +(Google App Engine restricts access to certain classes so Log4J cannot determine JVM start time with +`java.lang.management.ManagementFactory.getRuntimeMXBean().getStartTime()` +and falls back to Log4J initialization time instead.) + +[#sizebased-triggering-policy] +==== SizeBased Triggering Policy + +The `SizeBasedTriggeringPolicy` causes a rollover once the file has reached the specified size. +The size can be specified in bytes, with the suffix KB, MB, GB, or TB for example `20MB`. +size. +The size may also contain a fractional value such as `1.5 MB`. +The size is evaluated using the Java root Locale so a period must always be used for the fractional unit. +When combined with a time-based triggering policy the file pattern must contain a `%i`. +Otherwise, the target file will be overwritten on every rollover as the SizeBased Triggering Policy will not cause the timestamp value in the file name to change. +When used without a time-based triggering policy the SizeBased Triggering Policy will cause the timestamp value to change. + +[#timebased-triggering-policy] +==== TimeBased Triggering Policy + +The `TimeBasedTriggeringPolicy` causes a rollover once the date/time pattern no longer applies to the active file. +This policy accepts an +`interval` attribute which indicates how frequently the rollover should occur based on the time pattern and a `modulate` boolean attribute. + +.TimeBasedTriggeringPolicy Parameters +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|interval |integer |How often a rollover should occur based on the most +specific time unit in the date pattern. For example, with a date pattern +with hours as the most specific item, an increment of 4 rollovers +would occur every 4 hours. The default value is 1. + +|modulate |boolean |Indicates whether the interval should be adjusted to +cause the next rollover to occur on the interval boundary. For example, +if the item is hours, the current hour is 3 am and the interval is 4 +then the first rollover will occur at 4 am and then the next ones will occur +at 8 am, noon, 4 pm, etc. The default value is false. + +|maxRandomDelay |integer |Indicates the maximum number of seconds to +randomly delay a rollover. By default, this is 0 which indicates no +delay. This setting is useful on servers where multiple applications are +configured to roll over logfiles at the same time and can spread the +load of doing so across time. +|======================================================================= + +[#RolloverStrategies] +=== RolloverStrategies + +[#DefaultRolloverStrategy] +==== DefaultRolloverStrategy + +Default Rollover Strategy + +The default rollover strategy accepts both a date/time pattern and an integer from the `filePattern` attribute specified on the RollingFileAppender itself. +If the date/time pattern is present it will be replaced with the current date and time values. +If the pattern contains an integer it will be incremented on each rollover. +If the pattern contains both a date/time and integer in the pattern the integer will be incremented until the result of the date/time pattern changes. +If the file pattern ends with ".gz", ".zip", ".bz2", ".deflate", ".pack200", or ".xz" the resulting archive will be compressed using the compression scheme that matches the suffix. +The formats bzip2, Deflate, Pack200 and XZ require +https://commons.apache.org/proper/commons-compress/index.html[Apache Commons Compress]. +In addition, XZ requires +https://www.tukaani.org/xz/java.html[XZ for Java]. +The pattern may also contain lookup references that can be resolved at runtime such as shown in the example below. + +The default rollover strategy supports three variations for incrementing the counter. +To illustrate how it works, suppose that the min attribute is set to 1, the max attribute is set to 3, the file name is "foo.log", and the file name pattern is "foo-%i.log". + +[cols="15%,15%,15%,55%",options="header",] +|======================================================================= +|Number of rollovers |Active output target |Archived log files +|Description +|0 |foo.log |- |All logging is going to the initial file. + +|1 |foo.log |foo-1.log |During the first rollover foo.log is renamed to +foo-1.log. A new foo.log file is created and starts being written to. + +|2 |foo.log |foo-2.log, foo-1.log |During the second rollover foo.log is +renamed to foo-2.log. A new foo.log file is created and starts being +written to. + +|3 |foo.log |foo-3.log, foo-2.log, foo-1.log |During the third rollover +foo.log is renamed to foo-3.log. A new foo.log file is created and +starts being written to. + +|4 |foo.log |foo-3.log, foo-2.log, foo-1.log |In the fourth and +subsequent rollovers, foo-1.log is deleted, foo-2.log is renamed to +foo-1.log, foo-3.log is renamed to foo-2.log and foo.log is renamed to +foo-3.log. A new foo.log file is created and starts being written to. +|======================================================================= + +By way of contrast, when the `fileIndex` attribute is set to "min" all the other settings are the same the "fixed window" strategy will be performed. + +[cols="15%,15%,15%,55%",options="header",] +|======================================================================= +|Number of rollovers |Active output target |Archived log files +|Description +|0 |foo.log |- |All logging is going to the initial file. + +|1 |foo.log |foo-1.log |During the first rollover foo.log is renamed to +foo-1.log. A new foo.log file is created and starts being written to. + +|2 |foo.log |foo-1.log, foo-2.log |During the second rollover foo-1.log +is renamed to foo-2.log and foo.log is renamed to foo-1.log. A new +foo.log file is created and starts being written to. + +|3 |foo.log |foo-1.log, foo-2.log, foo-3.log |During the third rollover +foo-2.log is renamed to foo-3.log, foo-1.log is renamed to foo-2.log and +foo.log is renamed to foo-1.log. A new foo.log file is created and +starts being written to. + +|4 |foo.log |foo-1.log, foo-2.log, foo-3.log |In the fourth and +subsequent rollovers, foo-3.log is deleted, foo-2.log is renamed to +foo-3.log, foo-1.log is renamed to foo-2.log and foo.log is renamed to +foo-1.log. A new foo.log file is created and starts being written to. +|======================================================================= + +Finally, as of release 2.8, if the `fileIndex` attribute is set to `nomax` +then the min and max values will be ignored and file numbering will increment by 1 and each rollover will have an incrementally higher value with no maximum number of files. + +.DefaultRolloverStrategy Parameters +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|fileIndex |String |If set to "max" (the default), files with a higher +index will be newer than files with a smaller index. If set to "min", +file renaming and the counter will follow the Fixed Window strategy +described above. + +|min |integer |The minimum value of the counter. The default value is 1. + +|max |integer |The maximum value of the counter. Once this value is +reached older archives will be deleted on subsequent rollovers. The +default value is 7. + +|compressionLevel |integer |Sets the compression level, 0-9, where 0 = +none, 1 = best speed, through 9 = best compression. Only implemented for +ZIP files. + +|tempCompressedFilePattern |String |The pattern of the file name of the +archived log file during compression. +|======================================================================= + +[#DirectWriteRolloverStrategy] +==== DirectWriteRolloverStrategy + +DirectWrite Rollover Strategy + +The DirectWriteRolloverStrategy causes log events to be written directly to files represented by the file pattern. +With this strategy file renames are not performed. +If the size-based triggering policy causes multiple files to be written during the specified period they will be numbered starting at one and continually incremented until a time-based rollover occurs. + +Warning: If the file pattern has a suffix indicating compression should take place the current file will not be compressed when the application is shut down. +Furthermore, if the time changes such that the file pattern no longer matches the current file it will not be compressed at startup either. + +.DirectWriteRolloverStrategy Parameters +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|maxFiles |String |The maximum number of files to allow in the period matching +the file pattern. If the number of files is exceeded the +oldest file will be deleted. If specified, the value must be greater +than 1. If the value is less than zero or omitted then the number of +files will not be limited. + +|compressionLevel |integer |Sets the compression level, 0-9, where 0 = +none, 1 = best speed, through 9 = best compression. Only implemented for +ZIP files. + +|tempCompressedFilePattern |String |The pattern of the file name of the +archived log file during compression. +|======================================================================= + +Below is a sample configuration that uses a RollingFileAppender with both the time and size-based triggering policies will create up to 7 archives on the same day (1-7) that are stored in a directory based on the current year and month, and will compress each archive using gzip: + +[source,xml] +---- + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + + + + +---- + +This second example shows a rollover strategy that will keep up to 20 files before removing them. + +[source,xml] +---- + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + + + + + +---- + +Below is a sample configuration that uses a RollingFileAppender with both the time and size-based triggering policies will create up to 7 archives on the same day (1-7) that are stored in a directory based on the current year and month, and will compress each archive using gzip and will roll every 6 hours when the hour is divisible by 6: + +[source,xml] +---- + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + + + + +---- + +This sample configuration uses a RollingFileAppender with both the cron and size-based triggering policies, and writes directly to an unlimited number of archive files. +The cron trigger causes a rollover every hour while the file size is limited to 250MB: + +[source,xml] +---- + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + + + + +---- + +This sample configuration is the same as the previous one but limits the number of files saved each hour to 10: + +[source,xml] +---- + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + + + + + +---- + +[#CustomDeleteOnRollover] +==== CustomDeleteOnRollover + +Log Archive Retention Policy: Delete on Rollover + +Log4j-2.5 introduces a `Delete` action that gives users more control over what files are deleted at rollover time than what was possible with the DefaultRolloverStrategy `max` attribute. +The Delete action lets users configure one or more conditions that select the files to delete relative to a base directory. + +Note that it is possible to delete any file, not just rolled-over log files, so use this action with care! +With the `testMode` parameter you can test your configuration without accidentally deleting the wrong files. + +.Delete Parameters +[width="100%",cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|basePath |String |_Required._ Base path from where to start scanning +for files to delete. + +|maxDepth |int |The maximum number of levels of directories to visit. A +value of 0 means that only the starting file (the base path itself) is +visited unless denied by the security manager. A value of +Integer.MAX_VALUE indicates that all levels should be visited. The +default is 1, meaning only the files in the specified base directory. + +|followLinks |boolean |Whether to follow symbolic links. Default is +false. + +|testMode |boolean |If true, files are not deleted but instead a message +is printed to the +{log4j2-url}/manual/status-logger.html[status logger] +at INFO level. Use this to do a dry run to test if the configuration +works as expected. The default is false. + +|pathSorter |PathSorter |A plugin implementing the +link:../javadoc/log4j-core/org/apache/logging/log4j/core/appender/rolling/action/PathSorter.html[`PathSorter`] +interface to sort the files before selecting the files to delete. The +default is to sort the most recently modified files first. + +|pathConditions [[DeletePathCondition]] |PathCondition[] a| +_Required if no ScriptCondition is specified._ One or more PathCondition +elements. + +If more than one condition is specified, they all need to accept a path +before it is deleted. Conditions can be nested, in which case the inner +condition(s) are evaluated only if the outer condition accepts the path. +If conditions are not nested they may be evaluated in any order. + +Conditions can also be combined with the logical operators AND, OR and +NOT by using the `IfAll`, `IfAny` and `IfNot` composite conditions. + +Users can create custom conditions or use the built-in conditions: + +* <> - accepts files whose path +(relative to the base path) matches a +https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html[regular +expression] or a +https://docs.oracle.com/javase/7/docs/api/java/nio/file/FileSystem.html#getPathMatcher(java.lang.String)[glob]. +* <> - accepts files that are as +old as or older than the specified +link:../javadoc/log4j-core/org/apache/logging/log4j/core/appender/rolling/action/Duration.html#parse(CharSequence)[duration]. +* <> - accepts +paths after some count threshold is exceeded during the file tree walk. +* <> - accepts +paths after the accumulated file size threshold is exceeded during the +file tree walk. +* IfAll - accepts a path if all nested conditions accept it (logical +AND). Nested conditions may be evaluated in any order. +* IfAny - accepts a path if one of the nested conditions accepts it +(logical OR). Nested conditions may be evaluated in any order. +* IfNot - accepts a path if the nested condition does not accept it +(logical NOT). + +|scriptCondition [[DeleteScriptCondition]] |ScriptCondition a| +_Required if no PathConditions are specified._ A ScriptCondition element +specifying a script. + +The ScriptCondition should contain a <> element that specifies the logic to be +executed. (See also the xref:manual/filters.adoc#Script[ScriptFilter] +documentation for more examples of configuring ScriptFiles and +ScriptRefs.) + +The script is passed several <>, +including a list of paths found under the base path (up to `maxDepth`) +and must return a list with the paths to delete. + +|======================================================================= + +[#DeleteIfFileName] +=== DeleteIfFileName + +.IfFileName Condition Parameters +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|glob |String |_Required if regex is not specified._ Matches the relative +path (relative to the base path) using a limited pattern language that +resembles regular expressions but with a +https://docs.oracle.com/javase/7/docs/api/java/nio/file/FileSystem.html#getPathMatcher(java.lang.String)[simpler +syntax]. + +|regex |String |_Required if glob not specified._ Matches the relative +path (relative to the base path) using a regular expression as defined +by the +https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html[`Pattern`] +class. + +|nestedConditions |PathCondition[] |An optional set of nested +<>s. If any nested conditions +exist they all need to accept the file before it is deleted. Nested +conditions are only evaluated if the outer condition accepts a file (if +the path name matches). +|======================================================================= + +[#DeleteIfLastModified] +=== DeleteIfLastModified + +.IfLastModified Condition Parameters +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|age |String |_Required._ Specifies a +link:../javadoc/log4j-core/org/apache/logging/log4j/core/appender/rolling/action/Duration.html#parse(CharSequence)[`duration`]. +The condition accepts files that are as old or older than the specified +duration. + +|nestedConditions |PathCondition[] |An optional set of nested +<>s. If any nested conditions +exist they all need to accept the file before it is deleted. Nested +conditions are only evaluated if the outer condition accepts a file (if +the file is old enough). +|======================================================================= + +[#DeleteIfAccumulatedFileCount] +=== DeleteIfAccumulatedFileCount + +.IfAccumulatedFileCount Condition Parameters +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|exceeds |int |_Required._ The threshold count from which files will be +deleted. + +|nestedConditions |PathCondition[] |An optional set of nested +<>s. If any nested conditions +exist they all need to accept the file before it is deleted. Nested +conditions are only evaluated if the outer condition accepts a file (if +the threshold count has been exceeded). +|======================================================================= + +[#DeleteIfAccumulatedFileSize] +=== DeleteIfAccumulatedFileSize + +.IfAccumulatedFileSize Condition Parameters +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|exceeds |String |_Required._ The threshold accumulated file size from +which files will be deleted. The size can be specified in bytes, with +the suffix KB, MB, GB, or TB, for example `20MB`. + +|nestedConditions |PathCondition[] |An optional set of nested +<>s. If any nested conditions +exist they all need to accept the file before it is deleted. Nested +conditions are only evaluated if the outer condition accepts a file (if +the threshold accumulated file size has been exceeded). +|======================================================================= + +Below is a sample configuration that uses a RollingFileAppender with the cron triggering policy configured to trigger every day at midnight. +Archives are stored in a directory based on the current year and month. +All files under the base directory that match the "*/app-*.log.gz" glob and are 60 days old or older are deleted at rollover time. + +[source,xml] +---- + + + + logs + + + + + + + + + + + + + + + + + + + +---- + +Below is a sample configuration that uses a RollingFileAppender with both the time and size-based triggering policies will create up to 100 archives on the same day (1-100) that are stored in a directory based on the current year and month, and will compress each archive using gzip and will roll every hour. +During every rollover, this configuration will delete files that match "*/app-*.log.gz" and are 30 days old or older, but keep the most recent 100 GB or the most recent 10 files, whichever comes first. + +[source,xml] +---- + + + + logs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +---- + +[#ScriptCondition] +=== ScriptCondition + +.ScriptCondition Parameters +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|script |Script, ScriptFile or ScriptRef |The Script element that +specifies the logic to be executed. The script passes a list of paths +found under the base path and must return the paths to delete as a +`java.util.List`. See also the +xref:manual/filters.adoc#Script[ScriptFilter] documentation for an example of +how ScriptFiles and ScriptRefs can be configured. +|======================================================================= + +[#ScriptParameters] +=== ScriptParameters + +.Script Parameters +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|basePath |`java.nio.file.Path` |The directory from where the Delete +action started scanning for files to delete. Can be used to relativize +the paths in the `pathList`. + +|pathList |`java.util.List` |The list of paths found +under the base path up to the specified max depth, sorted most recently +modified files first. The script is free to modify and return this list. + +|statusLogger |StatusLogger |The {log4j2-url}/manual/status-logger.html[status logger] that can be used to log +internal events during script execution. + +|configuration |Configuration |The Configuration that owns this +ScriptCondition. + +|substitutor |StrSubstitutor |The StrSubstitutor used to replace lookup +variables. + +|? |String |Any properties declared in the configuration. +|======================================================================= + +Below is a sample configuration that uses a RollingFileAppender with the cron triggering policy configured to trigger every day at midnight. +Archives are stored in a directory based on the current year and month. +The script returns a list of rolled-over files under the base directory dated Friday the 13th. +The Delete action will delete all files returned by the script. + +[source,xml] +---- + + + + logs + + + + + + + + + + + + + + + + + + + + +---- + +[#CustomPosixViewAttributeOnRollover] +=== CustomPosixViewAttributeOnRollover + +Log Archive File Attribute View Policy: Custom file attribute on Rollover + +Log4j-2.9 introduces a `PosixViewAttribute` action that gives users more control over which file attribute permissions, owner and group should be applied. +The PosixViewAttribute action lets users configure one or more conditions that select the eligible files relative to a base directory. + +.PosixViewAttribute Parameters +[width="100%",cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|basePath |String |_Required._ Base path from where to start scanning +for files to apply attributes. + +|maxDepth |int |The maximum number of levels of directories to visit. A +value of 0 means that only the starting file (the base path itself) is +visited unless denied by the security manager. A value of +Integer.MAX_VALUE indicates that all levels should be visited. The +default is 1, meaning only the files in the specified base directory. + +|followLinks |boolean |Whether to follow symbolic links. Default is +false. + +|pathConditions |PathCondition[] |see <> + +|filePermissions |String a| +File attribute permissions in POSIX format to apply when action is +executed. + +The underlying files system shall support +https://docs.oracle.com/javase/7/docs/api/java/nio/file/attribute/PosixFileAttributeView.html[`POSIX`] +file attribute view. + +Examples: rw------- or rw-rw-rw- etc... + +|fileOwner |String a| +File owner to define when action is executed. + +Changing the file's owner may be restricted for security reasons and +Operation not permitted IOException thrown. Only processes with an +effective user ID equal to the user ID of the file or with appropriate +privileges may change the ownership of a file if +http://www.gnu.org/software/libc/manual/html_node/Options-for-Files.html[_POSIX_CHOWN_RESTRICTED] +is in effect for path. + +The underlying files system shall support file +https://docs.oracle.com/javase/7/docs/api/java/nio/file/attribute/FileOwnerAttributeView.html[`owner`] +attribute view. + +|fileGroup |String a| +File group to define when action is executed. + +The underlying files system shall support +https://docs.oracle.com/javase/7/docs/api/java/nio/file/attribute/PosixFileAttributeView.html[`POSIX`] +file attribute view. + +|======================================================================= + +Below is a sample configuration that uses a RollingFileAppender and defines different POSIX file attribute views for current and rolled log files. + +[source,xml] +---- + + + + logs + + + + + + + + + + + + + + + + + + + + +---- + +[#RollingRandomAccessFileAppender] +=== RollingRandomAccessFileAppender + +The RollingRandomAccessFileAppender is similar to the standard +<> except it is always buffered (this cannot be switched off) and internally it uses a +`ByteBuffer + RandomAccessFile` instead of a `BufferedOutputStream`. +We saw a 20-200% performance improvement compared to RollingFileAppender with "bufferedIO=true" in our measurements. +The +`RollingRandomAccessFileAppender` writes to the file named in the fileName parameter and rolls the file over according to the TriggeringPolicy and the RolloverPolicy. +Similar to the RollingFileAppender, RollingRandomAccessFileAppender uses a RollingRandomAccessFileManager to perform the file I/O and perform the rollover. +While RollingRandomAccessFileAppender from different Configurations cannot be shared, the RollingRandomAccessFileManagers can be if the Manager is accessible. +For example, two web applications in a servlet container can have their configuration and safely write to the same file if Log4j is in a ClassLoader that is common to both of them. + +A RollingRandomAccessFileAppender requires a +<> and a +<>. +The triggering policy determines if a rollover should be performed while the `RolloverStrategy` +defines how the rollover should be done. +If no RolloverStrategy is configured, RollingRandomAccessFileAppender will use the +<>. +Since log4j-2.5, a <> can be configured in the DefaultRolloverStrategy to run at rollover. + +File locking is not supported by the RollingRandomAccessFileAppender. + +.RollingRandomAccessFileAppender Parameters +[width="100%",cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|append |boolean |When true - the default, records will be appended to +the end of the file. When set to false, the file will be cleared before +new records are written. + +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. + +|fileName |String |The name of the file to write to. If the file, or any +of its parent directories, do not exist, they will be created. + +|filePattern |String |The pattern of the file name of the archived log +file. The format of the pattern should is dependent on the +RolloverPolicy that is used. The DefaultRolloverPolicy will accept both +a date/time pattern compatible with +https://download.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html[`SimpleDateFormat`] +and/or a %i which represents an integer counter. The pattern also +supports interpolation at runtime so any of the Lookups (such as the +xref:manual/lookups.adoc#DateLookup[DateLookup] can be included in the +pattern. + +|immediateFlush |boolean a| +When set to true - the default, each write will be followed by a flush. +This will guarantee the data is written to disk but could impact +performance. + +Flushing after every write is only useful when using this appender with +synchronous loggers. Asynchronous loggers and appenders will +automatically flush at the end of a batch of events, even if +immediateFlush is set to false. This also guarantees the data is written +to disk but is more efficient. + +|bufferSize |int |The buffer size, defaults to 262,144 bytes (256 * +1024). + +|layout |Layout |The Layout to use to format the LogEvent. If no layout +is supplied the default pattern layout of "%m%n" will be used. + +|name |String |The name of the Appender. + +|policy |TriggeringPolicy |The policy to use to determine if a rollover +should occur. + +|strategy |RolloverStrategy |The strategy to use to determine the name +and the location of the archive file. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a <>. + +|filePermissions |String a| +File attribute permissions in POSIX format to apply whenever the file is +created. + +The underlying files system shall support +https://docs.oracle.com/javase/7/docs/api/java/nio/file/attribute/PosixFileAttributeView.html[`POSIX`] +file attribute view. + +Examples: `rw-------` or `rw-rw-rw-` etc... + +|fileOwner |String a| +File owner to define whenever the file is created. + +Changing the file's owner may be restricted for security reasons and +Operation not permitted IOException thrown. Only processes with an +effective user ID equal to the user ID of the file or with appropriate +privileges may change the ownership of a file if +http://www.gnu.org/software/libc/manual/html_node/Options-for-Files.html[_POSIX_CHOWN_RESTRICTED] +is in effect for path. + +The underlying file system shall support file +https://docs.oracle.com/javase/7/docs/api/java/nio/file/attribute/FileOwnerAttributeView.html[`owner`] +attribute view. + +|fileGroup |String a| +File group to define whenever the file is created. + +The underlying files system shall support +https://docs.oracle.com/javase/7/docs/api/java/nio/file/attribute/PosixFileAttributeView.html[`POSIX`] +file attribute view. + +|======================================================================= + +==== Triggering Policies + +See <>. + +==== Rollover Strategies + +See <>. + +Below is a sample configuration that uses a RollingRandomAccessFileAppender with both the time and size-based triggering policies will create up to 7 archives on the same day (1-7) that are stored in a directory based on the current year and month, and will compress each archive using gzip: + +[source,xml] +---- + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + + + + +---- + +This second example shows a rollover strategy that will keep up to 20 files before removing them. + +[source,xml] +---- + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + + + + + +---- + +Below is a sample configuration that uses a RollingRandomAccessFileAppender with both the time and size-based triggering policies will create up to 7 archives on the same day (1-7) that are stored in a directory based on the current year and month, and will compress each archive using gzip and will roll every 6 hours when the hour is divisible by 6: + +[source,xml] +---- + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + + + + +---- + +[#RoutingAppender] +=== RoutingAppender + +The `RoutingAppender` evaluates LogEvents and then routes them to a subordinate Appender. +The target Appender may be an appender previously configured and may be referenced by its name or the Appender can be dynamically created as needed. +The `RoutingAppender` should be configured after any Appenders it references to allow it to shut down properly. + +You can also configure a `RoutingAppender` with scripts: you can run a script when the appender starts and when a route is chosen for an log event. + +.RoutingAppender Parameters +[width="100%",cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|Filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. + +|name |String |The name of the Appender. + +|RewritePolicy |RewritePolicy |The RewritePolicy that will manipulate +the LogEvent. + +|Routes |Routes |Contains one or more Route declarations to identify the +criteria for choosing Appenders. + +|Script |Script a| +This Script runs when Log4j starts the RoutingAppender and returns a +String Route key to determine the default Route. + +This script is passed the following variables: + +.RoutingAppender Script Parameters +[cols="20%,20%,60%",options="header",] +|======================================================================= + +|Parameter Name |Type |Description |configuration |Configuration |The active Configuration. + +|staticVariables |Map |A Map shared between all script invocations for this appender instance. +This is the same map passed to the Routes Script. + +|======================================================================= + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a <>. +|======================================================================= + +In this example, the script causes the "ServiceWindows" route to be the default route on Windows and "ServiceOther" on all other operating systems. +Note that the List Appender is one of our test appenders, any appender can be used, it is only used as a shorthand. + +[source,xml] +---- + + + + + + + + + + + + + + + + + + + + + +---- + +[#Routes] +==== Routes + +The `Routes` element accepts a single attribute named "pattern". +The pattern is evaluated against all the registered Lookups and the result is used to select a `Route`. +Each `Route` may be configured with a key. +If the key matches the result of evaluating the pattern then that `Route` +will be selected. +If no key is specified on a `Route` then that `Route` is the default. +Only one `Route` can be configured as the default. + +The `Routes` element may contain a `Script` child element. +If specified, the +`Script` is run for each log event and returns the String Route key to use. + +You must specify either the pattern attribute or the `Script` element, but not both. + +Each `Route` must reference an `Appender`. +If the `Route` contains a ref attribute then the `Route` will reference an `Appender` that was defined in the configuration. +If the `Route` contains an `Appender` definition then an +`Appender` will be created within the context of the `RoutingAppender` and will be reused each time a matching `Appender` name is referenced through a `Route`. + +This script is passed the following variables: + +.RoutingAppender Routes Script Parameters +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|configuration |Configuration |The active Configuration. + +|staticVariables |Map |A Map shared between all script invocations for +this appender instance. This is the same map passed to the Routes +Script. + +|logEvent |LogEvent |The log event. +|======================================================================= + +In this example, the script runs for each log event and picks a route based on the presence of a Marker named "AUDIT". + +[source,xml] +---- + + + + + + + + + + + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + + + + + + + +---- + +[#Purge] +==== Purge Policy + +The RoutingAppender can be configured with a PurgePolicy whose purpose is to stop and remove dormant Appenders that have been dynamically created by the RoutingAppender. +Log4j currently provides the IdlePurgePolicy is the only PurgePolicy available for cleaning up the Appenders. +The IdlePurgePolicy accepts 2 attributes; timeToLive, which is the number of timeUnits the Appender should survive without having any events sent to it, and timeUnit, the String representation of java.util.concurrent.TimeUnit which is used with the timeToLive attribute. + +Below is a sample configuration that uses a RoutingAppender to route all Audit events to a FlumeAppender and all other events will be routed to a RollingFileAppender captures only the specific event type. +Note that the AuditAppender was predefined while the RollingFileAppenders are created as needed. + +[source,xml] +---- + + + + + + + + + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + + + + + + +---- + +[[SMTPAppender]] +=== SMTPAppender + +Sends an e-mail when a specific logging event occurs, typically on errors or fatal errors. + +The number of logging events delivered in this e-mail depends on the value of the `BufferSize` option. +The `SMTPAppender` keeps only the last `BufferSize` logging events in its cyclic buffer. +This keeps memory requirements at a reasonable level while still delivering useful application context. +All events in the buffer are included in the email. +The buffer will contain the most recent events of level TRACE to WARN preceding the event that triggered the email. + +The default behavior is to trigger sending an email whenever an ERROR or higher severity event is logged and to format it as HTML. +The circumstances of when the email is sent can be controlled by setting one or more filters on the Appender. +As with other Appenders, the formatting can be controlled by specifying a Layout for the Appender. + +[width="100%",options="header"] +|=== +| Attribute | Type | Default value | Description + +4+h| Required + +| [[ConsoleAppender-attr-name]]name +| `String` +| +| The name of the appender. + +4+h| Optional + +| [[ConsoleAppender-attr-bufferSize]]bufferSize +| `int` +| xref:manual/systemproperties.adoc#log4j.gc.encoderByteBufferSize[`8192`] +a| +The size of the +https://docs.oracle.com/javase/{java-target-version}/docs/api/java/nio/ByteBuffer.html[`ByteBuffer`] +internally used by the appender. + +See <> for more details. + +| [[ConsoleAppender-attr-direct]]direct +| `boolean` +| `false` +a| +If set to `true`, log events will be written directly to either +https://docs.oracle.com/javase/8/docs/api/java/io/FileDescriptor.html#out[`FileDescriptor.out`] +or +https://docs.oracle.com/javase/8/docs/api/java/io/FileDescriptor.html#err[`FileDescriptor.err`]. + +This setting bypasses the buffering of `System.out` and `System.err` and might provide a performance comparable to a xref:manual/appenders/file.adoc[file appender]. + +[CAUTION] +==== + +If other logging backends or the application itself uses `System.out/System.err`, setting this to `true` might cause interleaved output. + +==== + +This setting is incompatible with the +<>. + +| [[ConsoleAppender-attr-follow]] +follow +| `boolean` +| `false` +| +If set to `true`, the appender will honor reassignments of `System.out` (resp. `System.err`) via +https://docs.oracle.com/javase/8/docs/api/java/lang/System.html#setOut-java.io.PrintStream-[`System.setOut`] +(resp. +https://docs.oracle.com/javase/8/docs/api/java/lang/System.html#setOut-java.io.PrintStream-[`System.setErr`]). + +Otherwise, the value of `System.out` (resp. `System.err`) at configuration time will be used. + +This setting is incompatible with the +<>. + +| [[ConsoleAppender-attr-ignoreExceptions]] +ignoreExceptions +| `boolean` +| `true` +| If `false`, logging exception will be forwarded to the caller of the logging statement. +Otherwise, they will be ignored. + +Logging exceptions are always also logged to the +{log4j2-url}/manual/status-logger.html[] + +| [[ConsoleAppender-attr-immediateFlush]] +immediateFlush +| `boolean` +| `true` +| +If set to `true`, the appender will flush its internal buffer and the buffer of the `System.out/System.err` stream after each log event. + +See xref:manual/appenders.adoc#buffering[Buffering] for more details. + +| [[ConsoleAppender-attr-target]] +target +| link:../javadoc/log4j-core/org/apache/logging/log4j/core/appender/ConsoleAppender.Target.html[`Target`] +| link:../javadoc/log4j-core/org/apache/logging/log4j/core/appender/ConsoleAppender.Target.html#SYSTEM_OUT[`SYSTEM_OUT`] +a| +It specifies which standard output stream to use: + +`SYSTEM_OUT`:: +It uses the standard output. + +`SYSTEM_ERR`:: +It uses the standard error output. + +|=== + +[source,xml] +---- + + + + + + + + + + + + +---- + +[#ScriptAppenderSelector] +=== ScriptAppenderSelector + +When the configuration is built, the `ScriptAppenderSelector` appender calls a `ScriptPlugin` to compute an appender name. +Log4j then creates one of the appender named listed under `AppenderSet` using the name of the +`ScriptAppenderSelector`. +After configuration, Log4j ignores the +`ScriptAppenderSelector`. +Log4j only builds the one selected appender from the configuration tree and ignores other `AppenderSet` child nodes. + +In the following example, the script returns the name "List2". +The appender name is recorded under the name of the +`ScriptAppenderSelector`, not the name of the selected appender, in this example, "SelectIt". + +[source,xml] +---- + + + + + + + + + + + + + + + + +---- + +[#SocketAppender] +=== SocketAppender + +The `SocketAppender` is an OutputStreamAppender that writes its output to a remote destination specified by a host and port. +The data can be sent over either TCP or UDP and can be sent in any format. +You can optionally secure communication with <>. +Note that the TCP and SSL variants write to the socket as a stream and do not expect a response from the target destination. +Due to limitations in the TCP protocol that means that when the target server closes its connection some log events may continue to appear to succeed until a closed connection exception is raised, causing those events to be lost. +If guaranteed delivery is required a protocol that requires acknowledgments must be used. + +.`SocketAppender` Parameters +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|name |String |The name of the Appender. + +|host |String |The name or address of the system that is listening for +log events. This parameter is required. + +|port |integer |The port on the host that is listening for log events. +This parameter must be specified. If the hostname resolves to multiple +IP addresses the TCP and SSL variations will fail over to the next IP +address when a connection is lost. + +|protocol |String |"TCP" (default), "SSL" or "UDP". + +|SSL |SslConfiguration |Contains the configuration for the KeyStore and +TrustStore. See <>. + +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. + +|immediateFail |boolean |When set to true, log events will not wait to +try to reconnect and will fail immediately if the socket is not +available. + +|immediateFlush |boolean |When set to true - the default, each write +will be followed by a flush. This will guarantee the data is written to +disk but could impact performance. + +|bufferedIO |boolean |When true - the default, events are written to a +buffer and the data will be written to the socket when the buffer is +full or, if immediateFlush is set when the record is written. + +|bufferSize |int |When bufferedIO is true, this is the buffer size, the +default is 8192 bytes. + +|layout |Layout |The Layout to use to format the LogEvent. Required, +there is no default. _New since 2.9, in previous versions +SerializedLayout was the default._ + +|reconnectionDelayMillis |integer |If set to a value greater than 0, +after an error, the SocketManager will attempt to reconnect to the server +after waiting for the specified number of milliseconds. If the reconnect +fails then an exception will be thrown (which can be caught by the +application if `ignoreExceptions` is set to `false`). + +|connectTimeoutMillis |integer |The connect timeout in milliseconds. The +default is 0 (infinite timeout, like `Socket.connect()` methods). + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a <>. +|======================================================================= + +This is an unsecured TCP configuration: + +[source,xml] +---- + + + + + + + + + + + + + +---- + +This is a secured <> configuration: + +[source,xml] +---- + + + + + + + + + + + + + + + + + +---- + +[#SSL] +=== SSL + +Several appenders can be configured to use either a plain network connection or a Secure Socket Layer (SSL) connection. +This section documents the parameters available for SSL configuration. + +.SSL Configuration Parameters +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|protocol |String |The SSL protocol to use, `TLS` if omitted. A single value +may enable multiple protocols, see the +https://docs.oracle.com/en/java/javase/11/docs/specs/security/standard-names.html#sslcontext-algorithms[JVM +documentation] for details. + +|KeyStore |KeyStore |Contains your private keys and certificates, and +determines which authentication credentials to send to the remote host. + +|TrustStore |TrustStore |Contains the CA certificates of the remote +counterparty. Determines whether the remote authentication credentials +(and thus the connection) should be trusted. +|======================================================================= + +[#KeyStore] +==== KeyStore + +The Keystore is meant to contain your private keys and certificates, and determines which authentication credentials to send to the remote host. + +.KeyStore Configuration Parameters +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|location |String |Path to the keystore file. + +|password |char[] |Plain text password to access the keystore. Cannot be +combined with either `passwordEnvironmentVariable` or `passwordFile`. + +|passwordEnvironmentVariable |String |Name of an environment variable +that holds the password. Cannot be combined with either `password` or +`passwordFile`. + +|passwordFile |String |Path to a file that holds the password. Cannot be +combined with either `password` or `passwordEnvironmentVariable`. + +|type |String |Optional KeyStore type, e.g. `JKS`, `PKCS12`, `PKCS11`, +`BKS`, `Windows-MY/Windows-ROOT`, `KeychainStore`, etc. The default is +JKS. See also +https://docs.oracle.com/javase/{java-target-version}/docs/technotes/guides/security/StandardNames.html#KeyStore[Standard +types]. + +|keyManagerFactoryAlgorithm |String |Optional KeyManagerFactory +algorithm. The default is `SunX509`. See also +https://docs.oracle.com/javase/{java-target-version}/docs/technotes/guides/security/StandardNames.html#KeyManagerFactory[Standard +algorithms]. +|======================================================================= + +[#TrustStore] +==== TrustStore + +The trust store is meant to contain the CA certificates you are willing to trust when a remote party presents its certificate. +Determines whether the remote authentication credentials (and thus the connection) should be trusted. + +In some cases, they can be the same store, although it is often better practice to use distinct stores (especially when they are file-based). + +.TrustStore Configuration Parameters +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|location |String |Path to the keystore file. + +|password |char[] |Plain text password to access the keystore. Cannot be +combined with either `passwordEnvironmentVariable` or `passwordFile`. + +|passwordEnvironmentVariable |String |Name of an environment variable +that holds the password. Cannot be combined with either `password` or +`passwordFile`. + +|passwordFile |String |Path to a file that holds the password. Cannot be +combined with either `password` or `passwordEnvironmentVariable`. + +|type |String |Optional KeyStore type, e.g. `JKS`, `PKCS12`, `PKCS11`, +`BKS`, `Windows-MY/Windows-ROOT`, `KeychainStore`, etc. The default is +JKS. See also +https://docs.oracle.com/javase/{java-target-version}/docs/technotes/guides/security/StandardNames.html#KeyStore[Standard +types]. + +|trustManagerFactoryAlgorithm |String |Optional TrustManagerFactory +algorithm. The default is `SunX509`. See also +https://docs.oracle.com/javase/{java-target-version}/docs/technotes/guides/security/StandardNames.html#TrustManagerFactory[Standard +algorithms]. +|======================================================================= + +[#Example] +==== Example + +[source,xml] +---- + + + + +---- + +[#SyslogAppender] +=== SyslogAppender + +The `SyslogAppender` is a `SocketAppender` that writes its output to a remote destination specified by a host and port in a format that conforms with either the BSD Syslog format or the RFC 5424 format. +The data can be sent over either TCP or UDP. + +.`SyslogAppender` Parameters +[cols="20%,20%,60%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|advertise |boolean |Indicates whether the appender should be +advertised. + +|appName |String |The value to use as the APP-NAME in the RFC 5424 +syslog record. + +|charset |String |The character set to use when converting the Syslog +String to a byte array. The String must be a valid +https://download.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html[`Charset`]. +If not specified, the default system Charset will be used. + +|connectTimeoutMillis |integer |The connect timeout in milliseconds. The +default is 0 (infinite timeout, like `Socket.connect()` methods). + +|enterpriseNumber |integer |The IANA enterprise number as described in +http://tools.ietf.org/html/rfc5424#section-7.2.2[RFC 5424] + +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. + +|facility |String |The facility is used to try to classify the message. +The facility option must be set to one of "KERN", "USER", "MAIL", +"DAEMON", "AUTH", "SYSLOG", "LPR", "NEWS", "UUCP", "CRON", "AUTHPRIV", +"FTP", "NTP", "AUDIT", "ALERT", "CLOCK", "LOCAL0", "LOCAL1", "LOCAL2", +"LOCAL3", "LOCAL4", "LOCAL5", "LOCAL6", or "LOCAL7". These values may be +specified as upper or lowercase characters. + +|format |String |If set to "RFC5424" the data will be formatted by RFC 5424. +Otherwise, it will be formatted as a BSD +Syslog record. Note that although BSD Syslog records are required to be +1024 bytes or shorter the SyslogLayout does not truncate them. The +RFC5424Layout also does not truncate records since the receiver must +accept records of up to 2048 bytes and may accept longer records. + +|host |String |The name or address of the system that is listening for +log events. This parameter is required. + +|id |String |The default structured data-id to use when formatting +according to RFC 5424. If the LogEvent contains a StructuredDataMessage +the id from the Message will be used instead of this value. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a <>. + +|immediateFail |boolean |When set to true, log events will not wait to +try to reconnect and will fail immediately if the socket is not +available. + +|immediateFlush |boolean |When set to true - the default, each write +will be followed by a flush. This will guarantee the data is written to +disk but could impact performance. + +|includeMDC |boolean |Indicates whether data from the ThreadContextMap +will be included in the RFC 5424 Syslog record. Defaults to true. + +|Layout |Layout |A custom layout that overrides the `format` setting. + +|loggerFields |List of KeyValuePairs |Allows arbitrary PatternLayout +patterns to be included as specified ThreadContext fields; no default +specified. To use, include a `LoggerFields` nested element, containing +one or more `KeyValuePair` elements. Each `KeyValuePair` must have a key +attribute, which specifies the key name that will be used to identify +the field within the MDC Structured Data element, and a value attribute, +which specifies the PatternLayout pattern to use as the value. + +|mdcExcludes |String |A comma-separated list of mdc keys that should be +excluded from the LogEvent. This is mutually exclusive with the +mdcIncludes attribute. This attribute only applies to RFC 5424 syslog +records. + +|mdcIncludes |String |A comma-separated list of mdc keys that should be +included in the FlumeEvent. Any keys in the MDC not found in the list +will be excluded. This option is mutually exclusive with the mdcExcludes +attribute. This attribute only applies to RFC 5424 syslog records. + +|mdcRequired |String |A comma-separated list of `mdc` keys that must be +present in the MDC. If a key is not present a LoggingException will be +thrown. This attribute only applies to RFC 5424 syslog records. + +|mdcPrefix |String |A string that should be prepended to each MDC key +to distinguish it from event attributes. The default string is +`mdc:`. This attribute only applies to RFC 5424 syslog records. + +|messageId |String |The default value to be used in the MSGID field of +RFC 5424 syslog records. + +|name |String |The name of the Appender. + +|newLine |boolean |If true, a newline will be appended to the end of the +syslog record. The default is false. + +|port |integer |The port on the host that is listening for log events. +This parameter must be specified. + +|protocol |String |"TCP" or "UDP". This parameter is required. + +|SSL |SslConfiguration |Contains the configuration for the KeyStore and +TrustStore. See <>. + +|reconnectionDelayMillis |integer |If set to a value greater than 0, +after an error, the SocketManager will attempt to reconnect to the server +after waiting for the specified number of milliseconds. If the reconnect +fails then an exception will be thrown (which can be caught by the +application if `ignoreExceptions` is set to `false`). +|======================================================================= + +A sample syslogAppender configuration that is configured with two `SyslogAppender`s, one using the BSD format and one using RFC 5424. + +[source,xml] +---- + + + + + + + + + + + + + + + +---- + +For <> this appender writes its output to a remote destination specified by a host and port over SSL in a format that conforms with either the BSD Syslog format or the RFC 5424 format. + +[source,xml] +---- + + + + + + + + + + + + + + + + +---- + +[[JeroMQAppender]] +=== ZeroMQ/JeroMQ Appender + +The ZeroMQ appender uses the https://github.com/zeromq/jeromq[JeroMQ] library to send log events to one or more ZeroMQ endpoints. + +This is a simple JeroMQ configuration: + +[source,xml] +---- + + + + + tcp://*:5556 + ipc://info-topic + + + + + + + + +---- + +The table below describes all options. +Please consult the JeroMQ and ZeroMQ documentation for details. + +[width="100%",options="header"] +|=== + +| Type | Multiplicity | Description + +| [[ConsoleAppender-element-Filter]] +xref:manual/filters.adoc[`Filter`] +| zero or one +| +Allows filtering log events just before they are formatted and sent. + +See also xref:manual/filters.adoc#appender-stage[appender filtering stage]. + +| [[ConsoleAppender-element-Layout]] +xref:manual/layouts.adoc[`Layout`] +| zero or one +| +Formats log events. + +See xref:manual/layouts.adoc[] for more information. + +|=== [#extending] == Extending @@ -584,7 +4061,7 @@ This section will guide you on how to create custom ones. [WARNING] ==== -*Implementing a reliable and efficient appender is a challenging task!* +*Implementing a reliable and efficient appender is a difficult task!* We strongly advise you to . Use existing appenders and/or managers whenever appropriate @@ -601,18 +4078,17 @@ include::partial$manual/plugin-preliminaries.adoc[] Appenders are xref:manual/plugins.adoc[plugins] implementing link:../javadoc/log4j-core/org/apache/logging/log4j/core/Appender.html[the `Appender` interface]. We recommend users to extend from link:../javadoc/log4j-core/org/apache/logging/log4j/core/appender/AbstractAppender.html[`AbstractAppender`], which provides implementation convenience. -While annotating your appender with `@Plugin`, you need to make sure that +While annotating your appender with `@Plugin` and `@Configurable`, you need to make sure that -* It has a unique `name` attribute across all available `Appender` plugins -* The `category` attribute is set to link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/Node.html#CATEGORY[`Node.CATEGORY`] +* The plugin name in `@Plugin::value` or the simple class name of the plugin if no custom name is given must be unique across all available `Appender` plugins. Most appender implementation use *managers*, which model an abstraction owning the resources, such as an `OutputStream` or a socket. -When a reconfiguration occurs, a new appender will be created. +When a reconfiguration occurs a new appender will be created. However, if nothing significant in the previous manager has changed, the new appender will simply reference it instead of creating a new one. This ensures that events are not lost while a reconfiguration is taking place without requiring that logging pause while the reconfiguration takes place. You are strongly advised to study the manager concept in <>, and either use an existing manager, or create your own. -You can check out the following files for examples: +You can check out following files for examples: -* {project-github-url}/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/HttpAppender.java[`HttpAppender.java`] – xref:manual/appenders/network.adoc#HttpAppender[HttpAppender] sends log events over HTTP using `HttpURLConnectionManager` +* {project-github-url}/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/HttpAppender.java[`HttpAppender.java`] – <> sends log events over HTTP using `HttpURLConnectionManager` * {project-github-url}/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java[`ConsoleAppender.java`] – <> writes log events to either `System.out` or `System.err` using `OutputStreamManager` diff --git a/src/site/antora/modules/ROOT/pages/manual/architecture.adoc b/src/site/antora/modules/ROOT/pages/manual/architecture.adoc index c98172be67d..2b7d9374040 100644 --- a/src/site/antora/modules/ROOT/pages/manual/architecture.adoc +++ b/src/site/antora/modules/ROOT/pages/manual/architecture.adoc @@ -16,468 +16,848 @@ //// = Architecture -== Main Components - -Log4j uses the classes shown in the diagram below. - -image:Log4jClasses.jpg[Log4j 2 Class Relationships,title="Log4j 2 Class Relationships"] - -Applications using the Log4j 2 API will request a Logger with a specific -name from the LogManager. The LogManager will locate the appropriate -LoggerContext and then obtain the Logger from it. If the Logger must be -created it will be associated with the LoggerConfig that contains either -a) the same name as the Logger, b) the name of a parent package, or c) -the root LoggerConfig. LoggerConfig objects are created from Logger -declarations in the configuration. The LoggerConfig is associated with -the Appenders that deliver the LogEvents. - -[id=logger-hierarchy] -=== Logger Hierarchy - -The first and foremost advantage of any logging API over plain -`System.out.println()` resides in its ability to disable certain log -statements while allowing others to print unhindered. This capability -assumes that the logging space, that is, the space of all possible -logging statements, is categorized according to some developer-chosen -criteria. - -In Log4j 1.x the Logger Hierarchy was maintained through a relationship -between Loggers. In Log4j 2 this relationship no longer exists. Instead, -the hierarchy is maintained in the relationship between LoggerConfig -objects. - -Loggers and LoggerConfigs are named entities. Logger names are -case-sensitive and they follow the hierarchical naming rule: - -Named Hierarchy:: -A LoggerConfig is said to be an _ancestor_ of another LoggerConfig if -its name followed by a dot is a prefix of the _descendant_ logger -name. A LoggerConfig is said to be a _parent_ of a _child_ -LoggerConfig if there are no ancestors between itself and the -descendant LoggerConfig. - -For example, the LoggerConfig named `"com.foo"` is a parent of the -LoggerConfig named `"com.foo.Bar"`. Similarly, `"java"` is a parent of -`"java.util"` and an ancestor of `"java.util.Vector"`. This naming -scheme should be familiar to most developers. - -The root LoggerConfig resides at the top of the LoggerConfig hierarchy. -It is exceptional in that it always exists and it is part of every -hierarchy. A Logger that is directly linked to the root LoggerConfig can -be obtained as follows: - -[source,java] ----- -Logger logger = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME); ----- - -Alternatively, and more simply: - -[source,java] ----- -Logger logger = LogManager.getRootLogger(); ----- - -All other Loggers can be retrieved using the -{log4j2-url}/javadoc/log4j-api/org/apache/logging/log4j/LogManager.html#getLogger(java.lang.String)[`LogManager.getLogger`] -static method by passing the name of the desired Logger. Further -information on the Logging API can be found in the -xref:manual/api.adoc[Log4j API]. - -=== LoggerContext - -The -link:../javadoc/log4j-core/org/apache/logging/log4j/core/LoggerContext.html[`LoggerContext`] -acts as the anchor point for the Logging system. However, it is possible -to have multiple active LoggerContexts in an application depending on -the circumstances. More details on the LoggerContext are in the -xref:manual/logsep.adoc[Log Separation] section. - -=== Configuration - -Every LoggerContext has an active -link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/Configuration.html[`Configuration`]. -The Configuration contains all the Appenders, context-wide Filters, -LoggerConfigs and contains the reference to the StrSubstitutor. -During reconfiguration, two Configuration objects will exist. Once all Loggers -have been redirected to the new Configuration, the old Configuration -will be stopped and discarded. - -=== Logger - -As stated previously, Loggers are created by calling -{log4j2-url}/javadoc/log4j-api/org/apache/logging/log4j/LogManager.html#getLogger(java.lang.String)[`LogManager.getLogger`]. -The Logger itself performs no direct actions. It simply has a name and -is associated with a LoggerConfig. It extends -{log4j2-url}/javadoc/log4j-api/org/apache/logging/log4j/spi/AbstractLogger.html[`AbstractLogger`] -and implements the required methods. As the configuration is modified -Loggers may become associated with a different LoggerConfig, thus -causing their behavior to be modified. - -Retrieving Loggers - -Calling the `LogManager.getLogger` method with the same name will always -return a reference to the same Logger object. - -For example, in - -[source,java] ----- -Logger x = LogManager.getLogger("wombat"); -Logger y = LogManager.getLogger("wombat"); ----- - -`x` and `y` refer to _exactly_ the same Logger object. - -Configuration of the log4j environment is typically done at application -initialization. The preferred way is by reading a configuration file. -This is discussed in xref:manual/configuration.adoc[Configuration]. - -Log4j makes it easy to name Loggers by _software component_. This can be -accomplished by instantiating a Logger in each class, with the logger -name equal to the fully qualified name of the class. This is a useful -and straightforward method of defining loggers. As the log output bears -the name of the generating Logger, this naming strategy makes it easy to -identify the origin of a log message. However, this is only one -possible, albeit common, strategy for naming loggers. Log4j does not -restrict the possible set of loggers. The developer is free to name the -loggers as desired. - -Since naming Loggers after their owning class is such a common idiom, -the convenience method `LogManager.getLogger()` is provided to -automatically use the calling class's fully qualified class name as the -Logger name. - -Nevertheless, naming loggers after the class where they are located -seems to be the best strategy known so far. - -[#loggerconfig] -=== LoggerConfig - -link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/LoggerConfig.html[`LoggerConfig`] -objects are created when Loggers are declared in the logging -configuration. The LoggerConfig contains a set of Filters that must -allow the LogEvent to pass before it will be passed to any Appenders. It -contains references to the set of Appenders that should be used to -process the event. - -==== Log Levels - -LoggerConfigs will be assigned a Log -{log4j2-url}/javadoc/log4j-api/org/apache/logging/log4j/Level.html[`Level`]. -The set of built-in levels includes ALL, TRACE, DEBUG, INFO, WARN, ERROR, -FATAL, and OFF. Log4j 2 also supports {log4j2-url}/manual/customloglevels.adoc[custom log -levels]. Another mechanism for getting more granularity is to use -{log4j2-url}/manual/markers.adoc[markers] instead. The OFF and ALL -levels are not intended to be used on calls to the logging API. -Specifying OFF in the configuration implies no logging events should -match while specifying ALL would mean all events match, including custom -events. However, OFF can be used on logging API calls in special cases -where the event should always be logged regardless of the configuration. -However, it is generally recommended that a Marker with a corresponding -global Marker Filter be used instead. - -{logging-services-url}/log4j/1.x/manual.html[Log4j 1] and -{logback-url}/manual/architecture.html#effectiveLevel[Logback] -both have the concept of "Level Inheritance". In Log4j 2, Loggers and -LoggerConfigs are two different objects so this concept is implemented -differently. Each Logger references the appropriate LoggerConfig which -in turn can reference its parent, thus achieving the same effect. - -Below are five tables with various assigned level values and the -resulting levels that will be associated with each Logger. Note that in -all these cases if the root LoggerConfig is not configured a default -Level will be assigned to it. - -.Example 1 -[cols=",,,",options="header",] -|==================================================================== -|Logger Name |Assigned LoggerConfig |LoggerConfig Level |Logger Level +Log4j Core is the reference implementation of xref:manual/api.adoc[] and composed of several components. +In this section we will try to explain major pillars its architecture stands on. +An overview these major classes can be depicted as follows: + +[#architecture-diagram] +.An overview of major classes and their relation +[plantuml] +.... +@startuml + +class LoggerContext { + Configuration config + Logger[] loggers + Logger getLogger(String name) +} + +note left of LoggerContext { + Anchor for the logging system +} + +LoggerContext --> "0..*" Logger + +package "Configuration" as c { + + class Configuration { + Appender[] appenders + Filter[] filters + LoggerConfig[] loggerConfigs + LoggerConfig getLoggerConfig(String name) + StrSubstitutor substitutor + } + + note left of Configuration + Encapsulates components compiled + from a user-provided configuration + file (e.g., `log4j2.xml`) + end note + + Configuration --> Filter + + Configuration --> "0..*" Appender + + Configuration --> "0..*" LoggerConfig + + Configuration --> StrSubstitutor + + class Appender { + AbstractManager manager + Layout layout + Filter filter + void append(LogEvent) + } + + Appender --> Layout + + Appender --> Filter + + class Layout { + byte[] encode(LogEvent) + } + + class Filter { + Result filter(LogEvent) + } + + note right of Filter + Note that a `Filter` can + be provided at 4 levels: + 1. `Configuration` + 2. `LoggerConfig` + 3. `AppenderControl` + 4. `Appender` + end note + + class LoggerConfig { + AppenderControl[] appenderControls + Level level + Filter filter + void log(LogEvent) + } + + LoggerConfig -[#green,thickness=6]-> "0..*" AppenderControl + + LoggerConfig --> Filter + + class AppenderControl { + Appender appender + Filter filter + void append(LogEvent) + } + + note right of AppenderControl + Decorates an `Appender` + with a `Filter` + end note + + AppenderControl -[#green,thickness=6]-> Appender + + AppenderControl --> Filter + + class StrSubstitutor { + Interpolator interpolator + String replace(String input) + } + + note right of StrSubstitutor + Responsible for + property substitution + (e.g., `${env:USER}`) + end note + + StrSubstitutor --> Interpolator + + class Interpolator { + StrLookup[] lookups + String lookup(String input) + } + + Interpolator --> "0..*" StrLookup + + class StrLookup { + String lookup(String input) + } +} + +LoggerContext --> Configuration + +class Logger { + void log(Level level, Message message) +} + +note right of Logger + The main API entry point + users interact with +end note + +Logger -[#green,thickness=6]-> LoggerConfig : delegates `log()` + +class AbstractManager { +} + +Appender -[#green,thickness=6]-> AbstractManager + +@enduml +.... + +At a really high level, + +* A <>, the composition anchor, gets created in combination with a <>. +Both can be created either directly (i.e., programmatically) or indirectly at first interaction with Log4j. +* `LoggerContext` creates <>s that users interact with for logging purposes. +* <> delivers a link:../javadoc/log4j-core/org/apache/logging/log4j/core/LogEvent.html[`LogEvent`] to a target (file, socket, database, etc.) and typically uses a <> to encode log events and an <> to handle the lifecycle of the target resource. +* <> encapsulates configuration for a `Logger`, as `AppenderControl` and `AppenderRef` for ``Appender``s. +* <> is equipped with <> to allow property substitution in `String`-typed values. +* A typical `log()` call triggers a chain of invocations through classes `Logger`, `LoggerConfig`, `AppenderControl`, `Appender`, and `AbstractManager` in order – this is depicted using green arrows in xref:architecture-diagram[xrefstyle=short]. + +Following sections examine this interplay in detail. + +[#LoggerContext] +== `LoggerContext` + +The {log4j2-url}/javadoc/log4j-api/org/apache/logging/log4j/spi/LoggerContext.html[`LoggerContext`] acts as the anchor point for the logging system. +It is associated with an active <> and is primarily responsible for instantiating <>s. + +[#LoggerContext-diagram] +.`LoggerContext` and other directly related classes +[plantuml] +.... +@startuml + +class LoggerContext #line.bold { + Configuration config + Logger[] loggers + Logger getLogger(String name) +} + +LoggerContext --> Configuration + +LoggerContext --> "0..*" Logger + +class Configuration { + Appender[] appenders + Filter[] filters + LoggerConfig[] loggerConfigs + LoggerConfig getLoggerConfig(String name) + StrSubstitutor substitutor +} + +class Logger { + void log(Level level, Message message) +} + +@enduml +.... + +In most cases, applications have a single global `LoggerContext`. +Though in certain cases (e.g., Java EE applications), Log4j can be configured to accommodate multiple ``LoggerContext``s. +Refer to xref:manual/logsep.adoc[] for details. + +[#Configuration] +== `Configuration` + +Every <> is associated with an active link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/Configuration.html[`Configuration`]. +It models the configuration of all appenders, layouts, filters, loggers, and contains the reference to <>. + +[#Configuration-diagram] +.`Configuration` and other directly related classes +[plantuml] +.... +@startuml + +class LoggerContext { + Configuration config + Logger[] loggers + Logger getLogger(String name) +} + +LoggerContext --> Configuration + +class Configuration #line.bold { + Appender[] appenders + Filter[] filters + LoggerConfig[] loggerConfigs + LoggerConfig getLoggerConfig(String name) + StrSubstitutor substitutor +} + +Configuration --> "0..*" Filter + +Configuration --> "0..*" Appender + +Configuration --> "0..*" LoggerConfig + +Configuration --> StrSubstitutor + +class Appender { + Layout layout + void append(LogEvent) +} + +class Filter { + Result filter(LogEvent) +} + +class LoggerConfig { + AppenderRef[] appenderRefs + AppenderControl[] appenderControls + Level level + Filter filter + void log(LogEvent) +} + +class StrSubstitutor { + Interpolator interpolator + String replace(String input) +} +@enduml +.... + +Configuration of Log4j Core is typically done at application initialization. +The preferred way is by reading a xref:manual/configuration.adoc[configuration file], but it can also be done xref:manual/customconfig.adoc[programmatically]. +This is further discussed in xref:manual/config-intro.adoc[]. + +[#reconfiguration] +=== Reconfiguration reliability + +The main motivation for the existing architecture is the reliability to configuration changes. +When a reconfiguration event occurs, two `Configuration` instances are active at the same time. +Threads that already started processing a log event will either: + +* continue logging to the old configuration, if execution already reached the `LoggerConfig` class, +* or switch to the new configuration. + +The service that manages the reconfiguration process is called link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/ReliabilityStrategy.html[`ReliabilityStrategy`] and it decides: + +* when should ``Logger``s switch to the new configuration, +* when should the old configuration be stopped. + +.Overview of the reconfiguration process +[plantuml] +.... +@startuml +left to right direction + +package LoggerContext { + object Logger + + package "New Configuration" as c2 { + object "LoggerConfig" as lc2 + object "AppenderControl" as ac2 + object "Appender" as app2 + } + + package "Old Configuration" as c1 { + object "LoggerConfig" as lc1 + object "AppenderControl" as ac1 + object "Appender" as app1 + } +} + +object AbstractManager + +Logger ..> lc1 +lc1 --> ac1 +ac1 --> app1 +app1 --> AbstractManager + +Logger --> lc2 +lc2 --> ac2 +ac2 --> app2 +app2 --> AbstractManager +@enduml +.... + +[#Logger] +== `Logger` + +{log4j2-url}/javadoc/log4j-api/org/apache/logging/log4j/Logger.html[`Logger`]s are the primary user entry point for logging. +They are created by calling one of the `getLogger()` methods of {log4j2-url}/javadoc/log4j-api/org/apache/logging/log4j/LogManager.html[`LogManager`] – this is further documented in xref:manual/api.adoc[]. +The `Logger` itself performs no direct actions. +It simply has a name and is associated with a <>. + +[#Logger-diagram] +.`Logger` and other directly related classes +[plantuml] +.... +@startuml + +class LoggerContext { + Configuration config + Logger[] loggers + Logger getLogger(String name) +} + +LoggerContext --> "0..*" Logger + +class LoggerConfig { + AppenderRef[] appenderRefs + AppenderControl[] appenderControls + Level level + Filter filter + void log(LogEvent) +} + +class Logger #line.bold { + void log(Level level, Message message) +} + +Logger -[#green,thickness=6]-> LoggerConfig : delegates `log()` + +@enduml +.... + +The hierarchy between <>s, implies the very same hierarchy between ``Logger``s too. +You can use `LogManager.getRootLogger()` to get the root logger. +Note that Log4j API has no assumptions on a `Logger` hierarchy – this is a feature implemented by Log4j Core. + +When the <> is modified, ``Logger``s may become associated with a different `LoggerConfig`, thus causing their behavior to be modified. +Refer to xref:manual/configuration.adoc#configuring-loggers[configuring ``Logger``s] for further information. + +[#LoggerConfig] +== `LoggerConfig` + +link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/LoggerConfig.html[`LoggerConfig`] binds <> definitions to their associated components (appenders, filters, etc.) as declared in the active <>. +The details of mapping a `Configuration` to ``LoggerConfig``s is explained xref:manual/configuration.adoc#configuring-loggers[here]. +``Logger``s effectively interact with appenders, filters, etc. through corresponding ``LoggerConfig``s. +A `LoggerConfig` essentially contains + +* A reference to its parent (except if it is the root logger) +* A {log4j2-url}/manual/customloglevels.html[level] denoting the severity of messages that are accepted (defaults to `ERROR`) +* <>s that must allow the `LogEvent` to pass before it will be passed to any <>s +* References to <>s that should be used to process the event + +[#LoggerConfig-diagram] +.`LoggerConfig` and other directly related classes +[plantuml] +.... +@startuml + +class Configuration { + Appender[] appenders + Filter[] filters + LoggerConfig[] loggerConfigs + LoggerConfig getLoggerConfig(String name) + StrSubstitutor substitutor +} + +Configuration --> "0..*" LoggerConfig + +class Filter { + Result filter(LogEvent) +} + +class LoggerConfig #line.bold { + AppenderRef[] appenderRefs + AppenderControl[] appenderControls + Level level + Filter filter + void log(LogEvent) +} + +LoggerConfig --> "0..*" AppenderRef + +LoggerConfig -[#green,thickness=6]-> "0..*" AppenderControl + +LoggerConfig --> Filter + +class AppenderRef { + String appenderName + Level level + Filter filter +} + +class AppenderControl { + Appender appender + Filter filter + void append(LogEvent) +} + +class Logger { + void log(Level level, Message message) +} + +Logger -[#green,thickness=6]-> LoggerConfig : delegates `log()` + +@enduml +.... + +[#logger-hiearchy] +=== Logger hierarchy + +Log4j Core has a *hierarchical* model of ``LoggerConfig``s, and hence ``Logger``s. +A `LoggerConfig` called `child` is said to be parented by `parent`, if `parent` has the _longest prefix match_ on name. +This match is case-sensitive and performed after tokenizing the name by splitting it from `.` (dot) characters. +For a positive name match, tokens must match exhaustively. +See xref:#logger-hiearchy-diagram[xrefstyle=short] for an example. + +[#logger-hiearchy-diagram] +.Example hierarchy of loggers named `X`, `X.Y`, `X.Y.Z`, and `X.YZ` +[plantuml] +.... +@startmindmap +* root +** X +*** X.Y +**** X.Y.Z +*** X.YZ +@endmindmap +.... + +If a `LoggerConfig` is not provided an explicit level, it will be inherited from its parent. +Similarly, if a user programmatically requests a `Logger` with a name that doesn't have a directly corresponding `LoggerConfig` configuration entry with its name, the `LoggerConfig` of the parent will be used. + +.Click for examples on `LoggerConfig` hierarchy +[%collapsible] +==== +Below we demonstrate the `LoggerConfig` hierarchy by means of _level inheritance_. +That is, we will examine the effective level of a `Logger` in various `LoggerConfig` settings. + +.Only the root logger is configured with a level, and it is `DEBUG` +[%header,cols="1m,1m,1m,1m"] +|=== +|Logger name |Assigned `LoggerConfig` name |Configured level |Effective level |root |root |DEBUG |DEBUG -|X |root |DEBUG |DEBUG -|X.Y |root |DEBUG |DEBUG -|X.Y.Z |root |DEBUG |DEBUG -|==================================================================== - -In example 1 above, only the root logger is configured and has a Log -Level. All the other Loggers reference the root LoggerConfig and use its -Level. - -.Example 2 -[cols=",,,",options="header",] -|============================================================= -|Logger Name |Assigned LoggerConfig |LoggerConfig Level |Level +|X |root | |DEBUG +|X.Y |root | |DEBUG +|X.Y.Z |root | |DEBUG +|=== + +.All loggers are configured with a level +[%header,cols="1m,1m,1m,1m"] +|=== +|Logger name |Assigned `LoggerConfig` |Configured level |Effective level |root |root |DEBUG |DEBUG |X |X |ERROR |ERROR |X.Y |X.Y |INFO |INFO |X.Y.Z |X.Y.Z |WARN |WARN -|============================================================= - -In example 2, all loggers have a configured LoggerConfig and obtain -their Level from it. +|=== -.Example 3 -[cols=",,,",options="header",] -|============================================================= -|Logger Name |Assigned LoggerConfig |LoggerConfig Level |Level +.All loggers are configured with a level, except the logger `X.Y` +[%header,cols="1m,1m,1m,1m"] +|=== +|Logger name |Assigned `LoggerConfig` |Configured level |Effective level |root |root |DEBUG |DEBUG |X |X |ERROR |ERROR -|X.Y |X |ERROR |ERROR +|X.Y |X | |ERROR |X.Y.Z |X.Y.Z |WARN |WARN -|============================================================= - -In example 3, the loggers`root`, `X` and `X.Y.Z` each have a configured -LoggerConfig with the same name. The Logger `X.Y` does not have a -configured LoggerConfig with a matching name so uses the configuration -of LoggerConfig `X` since that is the LoggerConfig whose name has the -the longest match to the start of the Logger's name. - -.Example 4 -[cols=",,,",options="header",] -|============================================================= -|Logger Name |Assigned LoggerConfig |LoggerConfig Level |level -|root |root |DEBUG |DEBUG -|X |X |ERROR |ERROR -|X.Y |X |ERROR |ERROR -|X.Y.Z |X |ERROR |ERROR -|============================================================= - -In example 4, the loggers `root` and `X` each have a Configured -LoggerConfig with the same name. The loggers `X.Y` and `X.Y.Z` do not -have configured LoggerConfigs and so get their Level from the -LoggerConfig assigned to them, `X`, since it is the LoggerConfig whose -name has the longest match to the start of the Logger's name. - -.Example 5 -[cols=",,,",options="header",] -|============================================================= -|Logger Name |Assigned LoggerConfig |LoggerConfig Level |level +|=== + +.All loggers are configured with a level, except loggers `X.Y` and `X.Y.Z` +[%header,cols="1m,1m,1m,1m"] +|=== +|Logger name |Assigned `LoggerConfig` |Configured level |Effective level |root |root |DEBUG |DEBUG |X |X |ERROR |ERROR -|X.Y |X.Y |INFO |INFO -|X.YZ |X |ERROR |ERROR -|============================================================= - -In example 5, the loggers `root`.`X`, and `X.Y` each has a configured -LoggerConfig with the same name. The logger `X.YZ` does not have -configured LoggerConfig and so gets its Level from the LoggerConfig -assigned to it, `X`, since it is the LoggerConfig whose name has the -longest match to the start of the Logger's name. It is not associated -with LoggerConfig `X.Y` since tokens after periods must match exactly. - -.Example 6 -[cols=4*,options="header"] +|X.Y |X | |ERROR +|X.Y.Z |X | |ERROR +|=== + +.All loggers are configured with a level, except the logger `X.YZ` +[%header,cols="1m,1m,1m,1m"] |=== -|Logger Name |Assigned LoggerConfig |LoggerConfig Level |Level +|Logger name |Assigned `LoggerConfig` |Configured level |Effective level |root |root |DEBUG |DEBUG |X |X |ERROR |ERROR -|X.Y |X.Y | |ERROR -|X.Y.Z |X.Y | |ERROR +|X.Y |X.Y |INFO |INFO +|X.YZ |X | |ERROR |=== +==== -In example 6, LoggerConfig X.Y has no configured level so it inherits -its level from LoggerConfig X. Logger X.Y.Z uses LoggerConfig X.Y since -it doesn't have a LoggerConfig with a name that exactly matches. It too -inherits its logging level from LoggerConfig X. +For further information on log levels and using them for filtering purposes in a configuration, see {log4j2-url}/manual/customloglevels.html[Levels]. -The table below illustrates how Level filtering works. In the table, -the vertical header shows the Level of the LogEvent, while the horizontal -header shows the Level associated with the appropriate LoggerConfig. The -intersection identifies whether the LogEvent would be allowed to pass -for further processing (Yes) or discarded (No). +[#Filter] +== `Filter` -[cols=8*,options="header"] -|=== -|Event Level -7+|LoggerConfig Level +In addition to <>, Log4j provides link:../javadoc/log4j-core/org/apache/logging/log4j/core/Filter.html[`Filter`]s to evaluate the parameters of a logging call (i.e., context-wide filter) or a log event, and decide if it should be processed further in the pipeline. -|  |`TRACE` |`DEBUG` |`INFO` |`WARN` |`ERROR` |`FATAL` |`OFF` +[#Filter-diagram] +.`Filter` and other directly related classes +[plantuml] +.... +@startuml -|`ALL` |❌ |❌ |❌ |❌ |❌ |❌ |❌ +class Configuration { + Appender[] appenders + Filter[] filters + LoggerConfig[] loggerConfigs + LoggerConfig getLoggerConfig(String name) + StrSubstitutor substitutor +} -|`TRACE` |✅ |❌ |❌ |❌ |❌ |❌ |❌ +Configuration --> "0..*" Filter -|`DEBUG` |✅ |✅ |❌ |❌ |❌ |❌ |❌ +Configuration --> "0..*" LoggerConfig -|`INFO` |✅ |✅ |✅ |❌ |❌ |❌ |❌ +class Filter #line.bold { + Result filter(LogEvent) +} -|`WARN` |✅ |✅ |✅ |✅ |❌ |❌ |❌ +class LoggerConfig { + AppenderRef[] appenderRefs + AppenderControl[] appenderControls + Level level + Filter filter + void log(LogEvent) +} -|`ERROR` |✅ |✅ |✅ |✅ |✅ |❌ |❌ +LoggerConfig --> "0..*" AppenderRef -|`FATAL` |✅ |✅ |✅ |✅ |✅ |✅ |❌ +LoggerConfig -[#green,thickness=6]-> "0..*" AppenderControl -|`OFF` |✅ |✅ |✅ |✅ |✅ |✅ |✅ -|=== +LoggerConfig --> Filter + +class AppenderRef { + String appenderName + Level level + Filter filter +} + +AppenderRef --> Filter + +AppenderControl --> Filter + +@enduml +.... + +Refer to xref:manual/filters.adoc[] for further information. + +[#Appender] +== `Appender` + +link:../javadoc/log4j-core/org/apache/logging/log4j/core/Appender.html[`Appender`]s are responsible for delivering a link:../javadoc/log4j-core/org/apache/logging/log4j/core/LogEvent.html[`LogEvent`] to a certain target; console, file, database, etc. +While doing so, they typically use <>s to encode the log event. +See xref:manual/appenders.adoc[] for the complete guide. + +[#Appender-diagram] +.`Appender` and other directly related classes +[plantuml] +.... +@startuml + +class Configuration { + Appender[] appenders + Filter[] filters + LoggerConfig[] loggerConfigs + LoggerConfig getLoggerConfig(String name) + StrSubstitutor substitutor +} + +Configuration --> "0..*" Filter -=== Filter - -In addition to the automatic log Level filtering that takes place as -described in the previous section, Log4j provides -link:../javadoc/log4j-core/org/apache/logging/log4j/core/Filter.html[`Filter`]s -that can be applied before control is passed to any LoggerConfig, after -control is passed to a LoggerConfig but before calling any Appenders, -after control is passed to a LoggerConfig but before calling a specific -Appender, and on each Appender. In a manner very similar to firewall -filters, each Filter can return one of three results, `Accept`, `Deny` -or `Neutral`. A response of `Accept` means that no other Filters should -be called and the event should progress. A response of `Deny` means the -event should be immediately ignored and control should be returned to -the caller. A response of `Neutral` indicates the event should be passed -to other Filters. If there are no other Filters the event will be -processed. - -Although an event may be accepted by a Filter the event still might not -be logged. This can happen when the event is accepted by the -pre-LoggerConfig Filter but is then denied by a LoggerConfig filter or -is denied by all Appenders. - -=== Appender - -The ability to selectively enable or disable logging requests based on -their logger is only part of the picture. Log4j allows logging requests -to print to multiple destinations. In log4j speak, an output destination -is called an -link:../javadoc/log4j-core/org/apache/logging/log4j/core/Appender.html[`Appender`]. -Currently, appenders exist for the console, files, remote socket -servers, Apache Flume, remote UNIX Syslog daemons, and various -database APIs. See the section on xref:manual/appenders.adoc[Appenders] for -more details on the various types available. More than one Appender can -be attached to a Logger. - -An Appender can be added to a Logger by calling the -link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/Configuration.html#addLoggerAppender(org.apache.logging.log4j.core.Logger,%20org.apache.logging.log4j.core.Appender)[`addLoggerAppender`] -method of the current Configuration. If a LoggerConfig matching the name -of the Logger does not exist, one will be created, and the Appender will be -attached to it and then all Loggers will be notified to update their -LoggerConfig references. - -*Each enabled logging request for a given logger will be forwarded to -all the appenders in that Logger's LoggerConfig as well as the Appenders -of the LoggerConfig's parents.* In other words, Appenders are inherited -additively from the LoggerConfig hierarchy. For example, if a console -appender is added to the root logger, then all enabled logging requests -will at least print on the console. If in addition a file appender is -added to a LoggerConfig, say _C_, then enabled logging requests for _C_ -and _C_'s children will print in a file _and_ on the console. It is -possible to override this default behavior so that Appender accumulation -is no longer additive by setting `additivity="false"` on the Logger -declaration in the configuration file. - -The rules governing appender additivity are summarized below. - -Appender Additivity:: -The output of a log statement of Logger _L_ will go to all the -Appenders in the LoggerConfig associated with _L_ and the ancestors of -that LoggerConfig. This is the meaning of the term "appender -additivity". -+ -However, if an ancestor of the LoggerConfig associated with Logger -_L_, say _P_, has the additivity flag set to `false`, then _L_'s -output will be directed to all the appenders in _L_'s LoggerConfig and -it's ancestors up to and including _P_ but not the Appenders in any of -the ancestors of _P_. -+ -Loggers have their additivity flag set to `true` by default. - -The table below shows an example: +Configuration --> "0..*" Appender +Configuration --> "0..*" LoggerConfig + +class Appender #line.bold { + Layout layout + void append(LogEvent) +} + +Appender -[#green,thickness=6]-> Layout + +class Layout { + byte[] encode(LogEvent) +} + +class Filter { + Result filter(LogEvent) +} + +class LoggerConfig { + AppenderRef[] appenderRefs + AppenderControl[] appenderControls + Level level + Filter filter + void log(LogEvent) +} + +LoggerConfig --> "0..*" AppenderRef + +LoggerConfig -[#green,thickness=6]-> "0..*" AppenderControl + +LoggerConfig --> Filter + +class AppenderRef { + String appenderName + Level level + Filter filter +} + +AppenderRef --> Filter + +class AppenderControl { + Appender appender + Filter filter + void append(LogEvent) +} + +AppenderControl -[#green,thickness=6]-> Appender + +AppenderControl --> Filter + +@enduml +.... + +An `Appender` can be added to a <> by calling the link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/Configuration.html#addLoggerAppender(org.apache.logging.log4j.core.Logger,%20org.apache.logging.log4j.core.Appender)[`addLoggerAppender()`] method of the current <>. +If a <> matching the name of the `Logger` does not exist, one will be created, and the `Appender` will be attached to it, and then all ``Logger``s will be notified to update their `LoggerConfig` references. + +[#appender-additivity] +=== Appender additivity + +Each enabled logging request for a given logger will be forwarded to all the appenders in the corresponding ``Logger``'s `LoggerConfig`, as well as to the ``Appender``s of the ``LoggerConfig``'s parents. +In other words, ``Appender``s are inherited *additively* from the `LoggerConfig` hierarchy. +For example, if a console appender is added to the root logger, then all enabled logging requests will at least print on the console. +If in addition a file appender is added to a `LoggerConfig`, say `LC`, then enabled logging requests for `LC` and ``LC``'s children will print in a file _and_ on the console. +It is possible to override this default behavior so that appender accumulation is no longer additive by setting `additivity` attribute to `false` on xref:manual/configuration.adoc#configuring-loggers[the `Logger` declaration in the configuration file]. + +The output of a log statement of `Logger` `L` will go to all the appenders in the `LoggerConfig` associated with `L` and the ancestors of that `LoggerConfig`. +However, if an ancestor of the `LoggerConfig` associated with `Logger` +`L`, say `P`, has the additivity flag set to `false`, then ``L``'s output will be directed to all the appenders in ``L``'s `LoggerConfig` and it's ancestors up to and including `P` but not the appenders in any of the ancestors of `P`. + +.Click for an example on appender additivity +[%collapsible] +==== +[#appender-additivity-diagram] +.Example hierarchy of logger configurations to demonstrate appender additivity +[plantuml] +.... +@startmindmap +* root +** A +*** A.B1 (additivity=false) +**** A.B1.C +***** A.B1.C.D +*** A.B2.C +**** A.B2.C.D (additivity=false) +@endmindmap +.... + +In xref:#appender-additivity-diagram[xrefstyle=short], the effective appenders for each logger configuration are as follows: + +.Effective appenders of logger configurations in xref:#appender-additivity-diagram[xrefstyle=short] +[cols="1c,1c,1c,1c,1c,1c,1c"] |=== -|Logger Name |Added Appenders |Additivity Flag |Output Targets |Comment - -|root -|A1 -|not applicable -|A1 -|The root logger has no parent so additivity does not apply to it. - -|x -|A-x1, A-x2 -|true -|A1, A-x1, A-x2 -|Appenders of "x" and root. - -|x.y -|none -|true -|A1, A-x1, A-x2 -|Appenders of "x" and root. It would not be typical to configure a Logger with no Appenders. - -|x.y.z -|A-xyz1 -|true -|A1, A-x1, A-x2, A-xyz1 -|Appenders in "x.y.z", "x" and root. - -|security -|A-sec -|false -|A-sec -|No appender accumulation since the additivity flag is set to `false`. - -|security.access -|none -|true -|A-sec -|Only appenders of "security" because the additivity flag in "security" is set to `false`. +.2+^.^h| Appender +6+^.h|Logger configuration + +| `A` +| `A.B1` +| `A.B1.C` +| `A.B1.C.D` +| `A.B2.C` +| `A.B2.C.D` + +| `root` +| ✅ +| ✅ +| ✅ +| ✅ +| ✅ +| ❌ + +| `A` +| ✅ +| ❌ +| ❌ +| ❌ +| ✅ +| ❌ + +| `A.B1` +| - +| ✅ +| ✅ +| ✅ +| - +| - + +| `A.B1.C` +| - +| - +| ✅ +| ✅ +| - +| - + +| `A.B1.C.D` +| - +| - +| - +| ✅ +| - +| - + +| `A.B2.C` +| - +| - +| - +| - +| ✅ +| ❌ + +| `A.B2.C.D` +| - +| - +| - +| - +| - +| ✅ |=== +==== -=== Layout +[#AbstractManager] +=== `AbstractManager` -More often than not, users wish to customize not only the output -destination but also the output format. This is accomplished by -associating a -link:../javadoc/log4j-core/org/apache/logging/log4j/core/Layout.html[`Layout`] -with an Appender. The Layout is responsible for formatting the LogEvent -according to the user's wishes, whereas an appender takes care of -sending the formatted output to its destination. The -link:../javadoc/log4j-core/org/apache/logging/log4j/core/layout/PatternLayout.html[`PatternLayout`], -part of the standard log4j distribution, lets the user specify the -output format according to conversion patterns similar to the C language -`printf()` function. +To multiplex the access to external resources (files, network connections, etc.), most appenders are split into an +link:../javadoc/log4j-core/org/apache/logging/log4j/core/appender/AbstractManager.html[`AbstractManager`] +that handles the low-level access to the external resource and an `Appender` that transforms log events into a format that the manager can handle. -For example, the PatternLayout with the conversion pattern "%r [%t] %-5p -%c - %m%n" will output something akin to: +Managers that share the same resource are shared between appenders regardless of the `Configuration` or `LoggerContext` of the appenders. +For example +xref:manual/appenders.adoc#FileAppender[`FileAppender`]s +with the same `fileName` attribute all share the same +link:../javadoc/log4j-core/org/apache/logging/log4j/core/appender/FileManager.html[`FileManager`]. +[IMPORTANT] +==== +Due to the manager-sharing feature of many Log4j appenders, it is not possible to configure multiple appenders for the same resource that only differ in the way the underlying resource is configured. + +For example, it is not possible to have two file appenders (even in different logger contexts) that use the same file, but a different value of the `append` option. +Since during a <> multiple instances of the same appender exists, it is also not possible to toggle the value of the `append` option through reconfiguration. +==== + +[#Layout] +== `Layout` + +An <> uses a *layout* to encode a link:../javadoc/log4j-core/org/apache/logging/log4j/core/LogEvent.html[`LogEvent`] into a form that meets the needs of whatever will be consuming the log event. + +[#Layout-diagram] +.`Layout` and other directly related classes +[plantuml] .... -176 [main] INFO org.foo.Bar - Located nearest gas station. -.... +@startuml -The first field is the number of milliseconds elapsed since the start of -the program. The second field is the thread making the log request. The -third field is the level of the log statement. The fourth field is the -name of the logger associated with the log request. The text after the -'-' is the message of the statement. +class Appender { + Layout layout + void append(LogEvent) +} -Log4j comes with many different xref:manual/layouts.adoc[Layouts] for various -use cases such as JSON, XML, HTML, and Syslog (including the new RFC -5424 version). Other appenders such as the database connectors fill in -specified fields instead of a particular textual layout. +Appender -[#green,thickness=6]-> Layout -Just as importantly, log4j will render the content of the log message -according to user-specified criteria. For example, if you frequently -need to log `Oranges`, an object type used in your current project, then -you can create an OrangeMessage that accepts an Orange instance and pass -that to Log4j so that the Orange object can be formatted into an -appropriate byte array when required. +class Layout #line.bold { + byte[] encode(LogEvent) +} + +@enduml +.... + +Refer to xref:manual/layouts.adoc[] for details. [#StrSubstitutor] -=== StrSubstitutor and StrLookup - -The -link:../javadoc/log4j-core/org/apache/logging/log4j/core/lookup/StrSubstitutor.html[`StrSubstitutor`] -class and -link:../javadoc/log4j-core/org/apache/logging/log4j/core/lookup/StrLookup.html[`StrLookup`] -interface was borrowed from -https://commons.apache.org/proper/commons-lang/[Apache Commons Lang] and -then modified to support evaluating LogEvents. In addition the -link:../javadoc/log4j-core/org/apache/logging/log4j/core/lookup/Interpolator.html[`Interpolator`] -class was borrowed from Apache Commons Configuration to allow the -StrSubstitutor to evaluate variables from multiple StrLookups. It -too was modified to support evaluating LogEvents. Together these provide -a mechanism to allow the configuration to reference variables coming -from System Properties, the configuration file, the ThreadContext Map, -StructuredData in the LogEvent. The variables can either be resolved -when the configuration is processed or as each event is processed if -the component is capable of handling it. See xref:manual/lookups.adoc[Lookups] -for more information. +== `StrSubstitutor` et al. + +link:../javadoc/log4j-core/org/apache/logging/log4j/core/lookup/StrSubstitutor.html[`StrSubstitutor`] is a `String` interpolation tool that can be used in both configurations and components (e.g., appenders, layouts). +It accepts an link:../javadoc/log4j-core/org/apache/logging/log4j/core/lookup/Interpolator.html[`Interpolator`] to determine if a key maps to a certain value. +`Interpolator` is essentially a facade delegating to multiple link:../javadoc/log4j-core/org/apache/logging/log4j/core/lookup/StrLookup.html[`StrLookup`] (aka. _lookup_) implementations. + +[#StrSubstitutor-diagram] +.`StrSubstitutor` et al. and other directly related classes +[plantuml] +.... +@startuml + +class Configuration { + Appender[] appenders + Filter[] filters + LoggerConfig[] loggerConfigs + LoggerConfig getLoggerConfig(String name) + StrSubstitutor substitutor +} + +Configuration --> StrSubstitutor + +class StrSubstitutor #line.bold { + Interpolator interpolator + String replace(String input) +} + +StrSubstitutor --> Interpolator + +class Interpolator { + StrLookup[] lookups + String lookup(String input) +} + +Interpolator --> "0..*" StrLookup + +class StrLookup { + String lookup(String input) +} + +@enduml +.... + +See xref:manual/configuration.adoc#property-substitution[how property substitution works] and xref:manual/lookups.adoc[the predefined lookups] for further information. diff --git a/src/site/antora/modules/ROOT/pages/manual/config-intro.adoc b/src/site/antora/modules/ROOT/pages/manual/config-intro.adoc index 90bf892d869..10a7f64378f 100644 --- a/src/site/antora/modules/ROOT/pages/manual/config-intro.adoc +++ b/src/site/antora/modules/ROOT/pages/manual/config-intro.adoc @@ -17,17 +17,10 @@ [id=configuration] = Configuration -Logging is a standard method for monitoring the health of an application and diagnosing problems that may arise within it. Even moderately sized applications can contain thousands of logging statements. +To decide which of these statements will be logged and where, users need to configure Log4j Core in one of following ways: -To decide which of these statements will be logged and where, users need to configure Log4j Core in one of two ways: +* Through a xref:manual/configuration.adoc[configuration file] +* Through xref:manual/customconfig.adoc[programmatic configuration] -* through a xref:manual/configuration.adoc[]. -Since version 2.0, the configuration file format has been considered part of the public API and has remained stable across significant version upgrades. - -* through xref:manual/customconfig.adoc[Programmatic Configuration], which provides a larger spectrum of possible customizations but might require code changes during version upgrades. - -[NOTE] -==== -To prevent a chicken-and-egg problem, users can only supply some configuration options (e.g., the configuration file location) through xref:manual/systemproperties.adoc[configuration properties]. -==== \ No newline at end of file +Some meta-configuration options (e.g., the configuration file location) are only available through xref:manual/systemproperties.adoc[system properties]. diff --git a/src/site/antora/modules/ROOT/pages/manual/configuration.adoc b/src/site/antora/modules/ROOT/pages/manual/configuration.adoc index 66f1c0ad8f4..0c800aa16f1 100644 --- a/src/site/antora/modules/ROOT/pages/manual/configuration.adoc +++ b/src/site/antora/modules/ROOT/pages/manual/configuration.adoc @@ -28,7 +28,7 @@ If you are looking for a quick start on using Log4j in your application or libra [id=automatic-configuration] == [[AutomaticConfiguration]] Configuration file location -Upon initialization of a new logger context, Log4j assigns it a context name and scans the following **classpath** locations for a configuration file: +Upon initialization of a new xref:manual/architecture.adoc#LoggerContext[logger context, the anchor of the logging implementation], Log4j Core assigns it a context name and scans the following **classpath** locations for a configuration file in following order: . Files named `log4j2-test.` . Files named `log4j2-test.` @@ -42,23 +42,18 @@ A name derived from the runtime environment: + * For standalone Java SE applications, it is a random identifier. * For web applications, it is an identifier derived from the application descriptor. -See xref:jakarta.adoc#configuration[Log4j Web application configuration] for details. +See {logging-services-url}/log4j/jakarta[Log4j Web application configuration] for details. :: A file extension supported by a `ConfigurationFactory`. The order in which an extension will be searched for first depends on the order of the associated `ConfigurationFactory`. See <> for details. -If no configuration file is found, Log4j Core uses the link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/DefaultConfiguration.html[`DefaultConfiguration`] and the xref:manual/status-logger.adoc[status logger] prints a warning. -The default configuration prints all messages less severe than -xref:manual/systemproperties.adoc#log4j.configuration.level[`log4j.configuration.level`] -to the console. +If no configuration file is found, Log4j Core uses the link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/DefaultConfiguration.html[`DefaultConfiguration`] and the {log4j2-url}/manual/status-logger.html[status logger] prints a warning. +The default configuration prints all messages less specific than xref:manual/systemproperties.adoc#log4j.configuration.level[`log4j.configuration.level`] to the console. -You can override the location of the configuration file -using the xref:manual/systemproperties.adoc#log4j.configuration.location[`log4j.configuration.location` -system property]. -In such a case, Log4j Core will guess the configuration file format from the provided file name, -or use the default configuration factory if the extension is unknown. +You can override the location of the configuration file using the xref:manual/systemproperties.adoc#log4j.configuration.location[the `log4j.configuration.location` system property]. +In such a case, Log4j Core will guess the configuration file format from the provided file name, or use the default configuration factory if the extension is unknown. There are certain *best-practices* we strongly recommend you to adapt in your Log4j configuration: @@ -71,8 +66,7 @@ That is, don't provide both `log4j2.xml` and `log4j2.json` files. === Predefined ``ConfigurationFactory`` plugins Log4j Core uses plugins extending from link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/ConfigurationFactory.html[`ConfigurationFactory`] to determine which configuration file extensions are supported, in which order, and how to read them. -How this works under the hood and how you can introduce your custom implementations is explained in -xref:manual/extending.adoc#ConfigurationFactory[`ConfigurationFactory`]. +How this works under the hood and how you can introduce your custom implementations is explained in <>. .Supported configuration file formats by predefined `ConfigurationFactory` plugins [%header,cols="1,1m,1"] @@ -99,6 +93,13 @@ include::partial$configuration-file-format-deps.adoc[] Starting with Log4j 2, the configuration file syntax has been considered part of the public API and has remained stable across significant version upgrades. ==== +[WARNING] +==== +The syntax of the configuration file changed between Log4j{nbsp}1 and Log4j{nbsp}2. +Files in the Log4j{nbsp}1 syntax are ignored by default. +To enable partial support for old configuration syntax, see xref:manual/migration.adoc#ConfigurationCompatibility[configuration compatibility]. +==== + The Log4j runtime is composed of xref:manual/plugins.adoc[plugins], which are like beans in the Spring Framework and Java EE. Appenders, layouts, filters, configuration loaders, and similar components are all accessed as plugins. @@ -412,10 +413,9 @@ Between the two operations log events might be lost. Overrides the logging level of {log4j2-url}/manual/status-logger.adoc[Status Logger]. -[WARNING] -==== -Since version `2.24.0`, this attribute is deprecated and should be replaced with the xref:manual/status-logger.adoc#log4j2.statusLoggerLevel[log4j2.statusLoggerLevel] configuration property instead. -==== +WARNING: Since 2.24.0 this attribute is deprecated and should be replaced with the +{log4j2-url}/manual/systemproperties.html#log4j.sta.statusLoggerLevel[`log4j2.statusLoggerLevel`] +configuration property. [id=configuring-loggers] == [[Loggers]] Loggers @@ -444,7 +444,7 @@ Other logger configurations are optional. Every {log4j2-url}/javadoc/log4j-api/org/apache/logging/log4j/Logger.html[`Logger`] in your application is assigned to one of these logger configurations (see -xref:manual/architecture.adoc#loggerconfig[architecture]), which determines the events that will be logged and those that won't. +xref:manual/architecture.adoc#LoggerConfig[architecture]), which determines the events that will be logged and those that won't. Let's start with an example of logger configuration: @@ -1100,40 +1100,17 @@ include::example$manual/configuration/arbiters-select.properties[tag=select] <2> Otherwise, a JSON Template Layout will be used. [#CompositeConfiguration] -== Composite Configuration - -Log4j allows multiple configuration files to be used at the same time by specifying them as a list of comma-separated file paths or URLs in the -xref:manual/systemproperties.adoc#log4j.configuration.location[`log4j.configuration.location`] -configuration property. - -These configuration files are merged into a single configuration file using -link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/composite/MergeStrategy.html[`MergeStrategy`] -service that can be customized using the -xref:manual/systemproperties.adoc#log4j.configuration.mergeStrategy[`log4j.configuration.mergeStrategy`] -configuration property. - -The default merge strategy will merge the files using the following rules: - -. <> in later configurations replace those in previous configurations. -+ -The exception is the `monitorInterval` attribute: the lowest positive value from all the configuration files will be used. - -. <> from all configurations are aggregated. -Duplicate properties replace those in previous configurations. - -. xref:manual/filters.adoc[Filters] are aggregated under -xref:manual/filters.adoc#CompositeFilter[CompositeFilter], if more than one filter is defined. +== Composite configuration -. xref:manual/scripts.adoc[] are aggregated. -Duplicate definitions replace those in previous configurations. +include::partial$manual/composite-configuration.adoc[tag=intro] -. xref:manual/appenders.adoc[Appenders] are aggregated. -Appenders with the same name are **replaced** by those in later configurations, including all their elements. +You can provide a list of comma-separated file paths or URLs in xref:manual/systemproperties.adoc#log4j.configuration.location[the `log4j.configuration.location` configuration property], where each resource will get read into a `Configuration`, and then eventually combined into a single one using link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/composite/CompositeConfiguration.html[`CompositeConfiguration`]. -. <> are all aggregated. -Logger attributes are individually merged, and those in later configurations replace duplicates. -Appender references on a logger are aggregated, and those in later configurations replace duplicates. -The strategy merges filters on loggers using the rule above. +.How does `CompositeConfiguration` work? +[%collapsible] +==== +include::partial$manual/composite-configuration.adoc[tag=how] +==== [id=format-specific-notes] == Format specific notes @@ -1200,3 +1177,39 @@ include::example$manual/configuration/xinclude-appenders.xml[lines=1;18..-1] include::example$manual/configuration/xinclude-loggers.xml[lines=1;18..-1] ---- + +[#extending] +== Extending + +Log4j Core uses xref:manual/plugins.adoc[plugins] to inject necessary components while reading a configuration file. +In this section, we will explore extension points users can hook into to customize the way Log4j Core reads configuration files. + +[#extending-plugins] +=== Plugin preliminaries + +include::partial$manual/plugin-preliminaries.adoc[] + +[#ConfigurationFactory] +=== Extending `ConfigurationFactory` plugins + +Under the hood, Log4j Core uses plugins extending from link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/ConfigurationFactory.html[`ConfigurationFactory`] to load configuration files. +This procedure can be summarized as follows: + +. Load plugins which extend from link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/ConfigurationFactory.html[`ConfigurationFactory`] and whose plugin `@Namespace` is set to link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/ConfigurationFactory.html#NAMESPACE[`ConfigurationFactory.NAMESPACE`] +. Sort them by link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/Ordered.html[`@Ordered`] annotation (in natural integer order), if present +. Feed <> to `ConfigurationFactory` instances in order, if the file extension is contained by `String[]` returned from link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/ConfigurationFactory.html#getSupportedTypes()[`ConfigurationFactory#getSupportedTypes()`] + +If xref:manual/systemproperties.adoc#log4j.configuration.factory[the `log4j.configuration.factory` system property] is defined, it will be used before any other factory implementations. + +For an example, see {project-github-url}/log4j-core/src/main/java/org/apache/logging/log4j/core/config/json/JsonConfigurationFactory.java[`JsonConfigurationFactory.java`] on how Log4j Core implements JSON-formatted configuration file read. + +[TIP] +==== +Next to introducing new configuration file formats, `ConfigurationFactory` can be used for xref:manual/customconfig.adoc[programmatic configuration] too. +==== + +[#extending-config-file-plugins] +=== Plugins represented in a configuration file + +As explained in <>, a configuration file gets parsed into a tree of plugins. +If your plugin needs to be represented in a configuration file element, some xref:manual/plugins.adoc#core[extra plugin configuration] needs to be administered. diff --git a/src/site/antora/modules/ROOT/pages/manual/customconfig.adoc b/src/site/antora/modules/ROOT/pages/manual/customconfig.adoc index 0662519d88f..0abf361f5b5 100644 --- a/src/site/antora/modules/ROOT/pages/manual/customconfig.adoc +++ b/src/site/antora/modules/ROOT/pages/manual/customconfig.adoc @@ -14,372 +14,236 @@ See the License for the specific language governing permissions and limitations under the License. //// -= Programmatic Configuration += Programmatic configuration -Log4j 2 provides a few ways for applications to create their own -programmatic configuration: +Next to xref:manual/configuration.adoc[configuration files], Log4j Core can be configured programmatically too. +In this page, we will explore utilities helping with programmatic configuration and demonstrate how they can be leveraged for certain use cases. -* Specify a custom `ConfigurationFactory` to start Log4j with a -programmatic configuration -* Use the `Configurator` to replace the configuration after Log4j started -* Initialize Log4j with a combination of a configuration file and -programmatic configuration -* Modify the current `Configuration` after initialization +[#prelim] +== Preliminaries + +To begin with, we strongly encourage you to check out the xref:manual/architecture.adoc[] page first. +Let's repeat some basic definitions of particular interest: + +xref:manual/architecture.adoc#LoggerContext[`LoggerContext`]:: +It is the anchor of the logging system. +Generally there is one, statically-accessible, global `LoggerContext` for most applications. +But there can be multiple ``LoggerContext``s, for instance, to use in tests, in Java EE web applications, etc. + +xref:manual/architecture.adoc#Configuration[`Configuration`]:: +It encapsulates a Log4j Core configuration (properties, appenders, loggers, etc.) and is associated with a `LoggerContext`. + +[#tooling] +== Tooling + +For programmatic configuration, Log4j Core essentially provides the following tooling: + +<>:: for declaratively creating a `Configuration` + +<>:: for associating a `Configuration` with a `LoggerContext` + +<>:: for registering a `Configuration` factory to xref:manual/configuration.adoc[the configuration file mechanism] + +In short, we will create ``Configuration``s using `ConfigurationBuilder`, and activate them using `Configurator`. [#ConfigurationBuilder] -== The ConfigurationBuilder API - -Starting with release 2.4, Log4j provides a `ConfigurationBuilder` and a -set of component builders that allow a `Configuration` to be created -fairly easily. Actual configuration objects like `LoggerConfig` or -`Appender` can be unwieldy; they require a lot of knowledge about Log4j -internals which makes them difficult to work with if all you want is to -create a `Configuration`. - -The new `ConfigurationBuilder` API (in the -`org.apache.logging.log4j.core.config.builder.api` package) allows users -to create Configurations in code by constructing component -_definitions_. There is no need to work directly with actual -configuration objects. Component definitions are added to the -`ConfigurationBuilder`, and once all the definitions have been collected -all the actual configuration objects (like Loggers and Appenders) are -constructed. - -`ConfigurationBuilder` has convenience methods for the base components -that can be configured such as Loggers, Appenders, Filter, Properties, -etc. However, Log4j 2's plugin mechanism means that users can create any -number of custom components. As a trade-off, the `ConfigurationBuilder` -API provides only a limited number of "strongly typed" convenience -methods like `newLogger()`, `newLayout()` etc. The generic -`builder.newComponent()` method can be used if no convenience method -exists for the component you want to configure. - -For example, the builder does not know what sub-components can be -configured on specific components such as the RollingFileAppender vs. -the RoutingAppender. To specify a triggering policy on a -RollingFileAppender you would use builder.newComponent(). - -Examples of using the `ConfigurationBuilder` API are in the sections that -follow. +=== `ConfigurationBuilder` -[#ConfigurationFactory] -== Understanding ConfigurationFactory - -During initialization, Log4j 2 will search for available -xref:manual/extending.adoc#ConfigurationFactory[ConfigurationFactories] and -then select the one to use. The selected `ConfigurationFactory` creates -the `Configuration` that Log4j will use. Here is how Log4j finds the -available ConfigurationFactories: - -1. A system property named `log4j2.configurationFactory` can be set -with the name of the ConfigurationFactory to be used. -2. `ConfigurationFactory.setConfigurationFactory(ConfigurationFactory)` -can be called with the instance of the `ConfigurationFactory` to be used. -This must be called before any other calls to Log4j. -3. A `ConfigurationFactory` implementation can be added to the classpath -and configured as a plugin in the "ConfigurationFactory" category. The -`@Order` annotation can be used to specify the relative priority when -multiple applicable ConfigurationFactories are found. - -ConfigurationFactories have the concept of "supported types", which -basically maps to the file extension of the configuration file that the -ConfigurationFactory can handle. If a configuration file location is -specified, ConfigurationFactories whose supported type does not include -"*" or the matching file extension will not be used. - -[#Example] -== Initialize Log4j Using ConfigurationBuilder with a Custom ConfigurationFactory - -One way to programmatically configure Log4j 2 is to create a custom -`ConfigurationFactory` that uses the -<> to create a -Configuration. The below example overrides the `getConfiguration()` -method to return a `Configuration` created by the `ConfigurationBuilder`. -This will cause the `Configuration` to automatically be hooked into Log4j -when the `LoggerContext` is created. In the example below, because it -specifies a supported type of "*" it will override any configuration -files provided. +link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/builder/api/ConfigurationBuilder.html[`ConfigurationBuilder`] interface models a fluent API to programmatically create link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/Configuration.html[`Configuration`]s. +If you have ever created a xref:manual/configuration.adoc[Log4j Core configuration file], consider `ConfigurationBuilder` as a convenience utility to model the very same declarative configuration structure programmatically. + +Let's show `ConfigurationBuilder` usage with an example. +Consider the following Log4j Core configuration file: + +[tabs] +==== +XML:: ++ +.Snippet from an example {antora-examples-url}/manual/customconfig/ConfigurationBuilder/log4j2.xml[`log4j2.xml`] +[source,xml] +---- +include::example$manual/customconfig/ConfigurationBuilder/log4j2.xml[lines=24..34,indent=0] +---- + +JSON:: ++ +.Snippet from an example {antora-examples-url}/manual/customconfig/ConfigurationBuilder/log4j2.json[`log4j2.json`] +[source,json] +---- +include::example$manual/customconfig/ConfigurationBuilder/log4j2.json[lines=3..16,indent=0] +---- + +YAML:: ++ +.Snippet from an example {antora-examples-url}/manual/customconfig/ConfigurationBuilder/log4j2.yaml[`log4j2.yaml`] +[source,yaml] +---- +include::example$manual/customconfig/ConfigurationBuilder/log4j2.yaml[lines=19..-1,indent=0] +---- +Properties:: ++ +.Snippet from an example {antora-examples-url}/manual/customconfig/ConfigurationBuilder/log4j2.properties[`log4j2.properties`] +[source,properties] +---- +include::example$manual/customconfig/ConfigurationBuilder/log4j2.properties[lines=17..-1] +---- +==== + +Above Log4j Core configuration can be programmatically built using `ConfigurationBuilder` as follows: + +.Snippet from an example {antora-examples-url}/manual/customconfig/Usage.java[`Usage.java`] [source,java] ---- -@Namespace(ConfigurationFactory.NAMESPACE) -@Plugin -@Order(50) -public class CustomConfigurationFactory extends ConfigurationFactory { - - static Configuration createConfiguration(final String name, ConfigurationBuilder builder) { - builder.setConfigurationName(name); - builder.setStatusLevel(Level.ERROR); - builder.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.NEUTRAL). - addAttribute("level", Level.DEBUG)); - AppenderComponentBuilder appenderBuilder = builder.newAppender("Stdout", "CONSOLE"). - addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT); - appenderBuilder.add(builder.newLayout("PatternLayout"). - addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable")); - appenderBuilder.add(builder.newFilter("MarkerFilter", Filter.Result.DENY, - Filter.Result.NEUTRAL).addAttribute("marker", "FLOW")); - builder.add(appenderBuilder); - builder.add(builder.newLogger("org.apache.logging.log4j", Level.DEBUG). - add(builder.newAppenderRef("Stdout")). - addAttribute("additivity", false)); - builder.add(builder.newRootLogger(Level.ERROR).add(builder.newAppenderRef("Stdout"))); - return builder.build(); - } - - @Override - public Configuration getConfiguration(final LoggerContext loggerContext, final ConfigurationSource source) { - return getConfiguration(loggerContext, source.toString(), null); - } - - @Override - public Configuration getConfiguration(final LoggerContext loggerContext, final String name, final URI configLocation) { - ConfigurationBuilder builder = newConfigurationBuilder(); - return createConfiguration(name, builder); - } - - @Override - protected String[] getSupportedTypes() { - return new String[] {"*"}; - } -} +include::example$manual/customconfig/Usage.java[tag=createConfiguration,indent=0] ---- +<1> The default `ConfigurationBuilder` instance is obtained using link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/builder/api/ConfigurationBuilderFactory.html#newConfigurationBuilder()[`ConfigurationBuilderFactory.newConfigurationBuilder()`] static method +<2> Add the appender along with the layout +<3> Add the root logger along with a level and appender reference +<4> Create the configuration, but *don't initialize* it ++ +[TIP] +==== +It is a good practice to not initialize ``Configuration``s when they are constructed. +This task should ideally be delegated to <>. +==== + +`ConfigurationBuilder` has convenience methods for the base components that can be configured such as loggers, appenders, filters, properties, etc. +Though there are cases where the provided convenience methods fall short of: -As of version 2.7, the `ConfigurationFactory.getConfiguration()` methods -take an additional `LoggerContext` parameter. +* Custom xref:manual/plugins.adoc#core[plugins that are declared to be represented in a configuration] +* Custom subcomponents (e.g., a xref:manual/appenders.adoc#TriggeringPolicies[triggering policy] for xref:manual/appenders.adoc#RollingFileAppender[`RollingFileAppender`]) + +For those, you can use the generic link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/builder/api/ConfigurationBuilder.html#newComponent()[`ConfigurationBuilder#newComponent()`] method. + +See {project-github-url}/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/Configurator1Test.java[`Configurator1Test.java`] for examples on `ConfigurationBuilder`, `newComponent()`, etc. usage. [#Configurator] -== Reconfigure Log4j Using ConfigurationBuilder with the Configurator +=== `Configurator` + +link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/Configurator.html[`Configurator`] is a programmatic interface to associate a ``Configuration`` with either new, or an existing `LoggerContext`. -An alternative to a custom `ConfigurationFactory` is to configure with the -`Configurator`. Once a `Configuration` object has been constructed, it can -be passed to one of the `Configurator.initialize` methods to set up the -Log4j configuration. +[#Configurator-initialize] +==== Obtaining a `LoggerContext` -Using the `Configurator` in this manner allows the application control -over when Log4j is initialized. However, should any logging be attempted -before `Configurator.initialize()` is called then the default -configuration will be used for those log events. +You can use `Configurator` to obtain a `LoggerContext`: +.Snippet from an example {antora-examples-url}/manual/customconfig/Usage.java[`Usage.java`] [source,java] ---- -ConfigurationBuilder builder = ConfigurationBuilderFactory.newConfigurationBuilder(); -builder.setStatusLevel(Level.ERROR); -builder.setConfigurationName("BuilderTest"); -builder.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.NEUTRAL) - .addAttribute("level", Level.DEBUG)); -AppenderComponentBuilder appenderBuilder = builder.newAppender("Stdout", "CONSOLE").addAttribute("target", - ConsoleAppender.Target.SYSTEM_OUT); -appenderBuilder.add(builder.newLayout("PatternLayout") - .addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable")); -appenderBuilder.add(builder.newFilter("MarkerFilter", Filter.Result.DENY, Filter.Result.NEUTRAL) - .addAttribute("marker", "FLOW")); -builder.add(appenderBuilder); -builder.add(builder.newLogger("org.apache.logging.log4j", Level.DEBUG) - .add(builder.newAppenderRef("Stdout")).addAttribute("additivity", false)); -builder.add(builder.newRootLogger(Level.ERROR).add(builder.newAppenderRef("Stdout"))); -ctx = Configurator.initialize(builder.build()); +include::example$manual/customconfig/Usage.java[tag=useConfiguration,indent=0] ---- -This example shows how to create a configuration that includes a -RollingFileAppender. +`initialize()` will either return the `LoggerContext` currently associated with the caller, or create a new one. +This is a convenient way to create isolated ``LoggerContext``s for tests, etc. + +[#Configurator-reconfigure] +==== Reconfiguring the active `LoggerContext` + +You can use `Configurator` to reconfigure the active `LoggerContext` as follows: +.Snippet from an example {antora-examples-url}/manual/customconfig/Usage.java[`Usage.java`] [source,java] ---- -ConfigurationBuilder builder = ConfigurationBuilderFactory.newConfigurationBuilder(); - -builder.setStatusLevel(Level.ERROR); -builder.setConfigurationName("RollingBuilder"); -// create a console appender -AppenderComponentBuilder appenderBuilder = builder.newAppender("Stdout", "CONSOLE").addAttribute("target", - ConsoleAppender.Target.SYSTEM_OUT); -appenderBuilder.add(builder.newLayout("PatternLayout") - .addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable")); -builder.add(appenderBuilder); -// create a rolling file appender -LayoutComponentBuilder layoutBuilder = builder.newLayout("PatternLayout") - .addAttribute("pattern", "%d [%t] %-5level: %msg%n"); -ComponentBuilder triggeringPolicy = builder.newComponent("Policies") - .addComponent(builder.newComponent("CronTriggeringPolicy").addAttribute("schedule", "0 0 0 * * ?")) - .addComponent(builder.newComponent("SizeBasedTriggeringPolicy").addAttribute("size", "100M")); -appenderBuilder = builder.newAppender("rolling", "RollingFile") - .addAttribute("fileName", "target/rolling.log") - .addAttribute("filePattern", "target/archive/rolling-%d{MM-dd-yy}.log.gz") - .add(layoutBuilder) - .addComponent(triggeringPolicy); -builder.add(appenderBuilder); - -// create the new logger -builder.add(builder.newLogger("TestLogger", Level.DEBUG) - .add(builder.newAppenderRef("rolling")) - .addAttribute("additivity", false)); - -builder.add(builder.newRootLogger(Level.DEBUG) - .add(builder.newAppenderRef("rolling"))); -LoggerContext ctx = Configurator.initialize(builder.build()); +include::example$manual/customconfig/Usage.java[tag=reconfigureActiveLoggerContext,indent=0] ---- -[#Hybrid] -== Initialize Log4j by Combining Configuration File with Programmatic Configuration +Using the `Configurator` in this manner allows the application control over when Log4j is initialized. +However, should any logging be attempted before `Configurator.initialize()` is called then the default configuration will be used for those log events. + +[#ConfigurationFactory] +=== [[Example]] `ConfigurationFactory` -Sometimes you want to configure with a configuration file but do some -additional programmatic configuration. A possible use case might be that -you want to allow for a flexible configuration using XML but at the same -time make sure there are a few configuration elements that are always -present that can't be removed. +link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/ConfigurationFactory.html[`ConfigurationFactory`] interface, which is mainly used by xref:manual/configuration.adoc#automatic-configuration[the configuration file mechanism] to load a link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/Configuration.html[`Configuration`], can be leveraged to inject a custom `Configuration`. +You need to -The easiest way to achieve this is to extend one of the standard -`Configuration` classes (`XMLConfiguration`, `JSONConfiguration`) and then -create a new `ConfigurationFactory` for the extended class. After the -standard configuration completes the custom configuration can be added -to it. +* xref:manual/configuration.adoc#ConfigurationFactory[Create a custom `ConfigurationFactory` plugin] +* Assign it a higher priority (i.e., higher `@Ordered` value) +* Support all configuration file types (i.e. return `*` from `getSupportedTypes()`) -The example below shows how to extend `XMLConfiguration` to manually add -an `Appender` and a `LoggerConfig` to the configuration. +Consider the example below: +.Snippet from an example {antora-examples-url}/manual/customconfig/ExampleConfigurationFactory.java[`ExampleConfigurationFactory.java`] [source,java] ---- -@Namespace("ConfigurationFactory") -@Plugin("MyXMLConfigurationFactory") -@Order(10) -public class MyXMLConfigurationFactory extends ConfigurationFactory { - - /** - * Valid file extensions for XML files. - */ - public static final String[] SUFFIXES = new String[] {".xml", "*"}; - - /** - * Return the Configuration. - * @param source The InputSource. - * @return The Configuration. - */ - public Configuration getConfiguration(InputSource source) { - return new MyXMLConfiguration(source, configFile); - } - - /** - * Returns the file suffixes for XML files. - * @return An array of File extensions. - */ - public String[] getSupportedTypes() { - return SUFFIXES; - } -} - -public class MyXMLConfiguration extends XMLConfiguration { - public MyXMLConfiguration(final ConfigurationFactory.ConfigurationSource configSource) { - super(configSource); - } - - @Override - protected void doConfigure() { - super.doConfigure(); - final LoggerContext ctx = (LoggerContext) LogManager.getContext(false); - final Layout layout = PatternLayout.createDefaultLayout(config); - final Appender appender = FileAppender.createAppender("target/test.log", "false", "false", "File", "true", - "false", "false", "4000", layout, null, "false", null, config); - appender.start(); - addAppender(appender); - LoggerConfig loggerConfig = LoggerConfig.createLogger("false", "info", "org.apache.logging.log4j", - "true", refs, null, config, null ); - loggerConfig.addAppender(appender, null, null); - addLogger("org.apache.logging.log4j", loggerConfig); - } -} +include::example$manual/customconfig/ExampleConfigurationFactory.java[tag=class] ---- +<1> `getConfiguration(LoggerContext, ConfigurationSource)` is only called if `ConfigurationSource` is not null. +This is possible if the `Configuration` is provided programmatically. +Hence, you are encouraged to implement `getConfiguration(LoggerContext, String, URI)` overload too. -[#AddingToCurrent] -== Programmatically Modifying the Current Configuration after Initialization +[#guides] +== How-to guides -Applications sometimes have the need to customize logging separate from -the actual configuration. Log4j allows this although it suffers from a -few limitations: +In this section we will share guides on programmatically configuring Log4j Core for certain use cases. -1. If the configuration file is changed the configuration will be -reloaded and the manual changes will be lost. -2. Modification to the running configuration requires that all the -methods being called (addAppender and addLogger) be synchronized. +[#load-config-file] +=== Loading a configuration file -As such, the recommended approach for customizing a configuration is to -extend one of the standard Configuration classes, override the setup -method to first do super.setup() and then add the custom Appenders, -Filters and LoggerConfigs to the configuration before it is registered -for use. +<> provides the link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/ConfigurationFactory.html#getInstance()[`getInstance()`] method returning a meta-`ConfigurationFactory` that combines the behaviour of all available ``ConfigurationFactory`` implementations, including xref:manual/configuration.adoc#configuration-factories[the predefined ones]; `XmlConfigurationFactory`, `JsonConfigurationFactory`, etc. +You can use this `getInstance()` method to load a configuration file programmatically, granted that the input file format is supported by at least one of the available `ConfigurationFactory` plugins: -The following example adds an Appender and a new LoggerConfig using that -Appender to the current configuration. - -//TODO: update code example below with new plugin API +.Snippet from an example {antora-examples-url}/manual/customconfig/Usage.java[`Usage.java`] [source,java] ---- - final LoggerContext ctx = (LoggerContext) LogManager.getContext(false); - final Configuration config = ctx.getConfiguration(); - Layout layout = PatternLayout.createDefaultLayout(config); - Appender appender = FileAppender.createAppender("target/test.log", "false", "false", "File", "true", - "false", "false", "4000", layout, null, "false", null, config); - appender.start(); - config.addAppender(appender); - AppenderRef ref = AppenderRef.createAppenderRef("File", null, null); - AppenderRef[] refs = new AppenderRef[] {ref}; - LoggerConfig loggerConfig = LoggerConfig.createLogger("false", "info", "org.apache.logging.log4j", - "true", refs, null, config, null ); - loggerConfig.addAppender(appender, null, null); - config.addLogger("org.apache.logging.log4j", loggerConfig); - ctx.updateLoggers(); -} +include::example$manual/customconfig/Usage.java[tag=loadConfigurationFile,indent=0] ---- +<1> Passing the `LoggerContext` argument as null, since this is the first time we are instantiating this `Configuration`, and it is not associated with a `LoggerContext` yet +<2> Passing the configuration name argument as null, since it is not used when the configuration source location is provided +<3> URI pointing to the configuration file; `file://path/to/log4j2.xml`, `classpath:log4j2.xml`, etc. -[#AppendingToWritersAndOutputStreams] -== Appending Log Events to Writers and OutputStreams Programmatically +[#CompositeConfiguration] +=== Combining multiple configurations -Log4j 2.5 provides facilities to append log events to Writers and -OutputStreams. For example, this provides simple integration for JDBC -Driver implementors that use Log4j internally and still want to support -the JDBC APIs `CommonDataSource.setLogWriter(PrintWriter)`, -`java.sql.DriverManager.setLogWriter(PrintWriter)`, and -`java.sql.DriverManager.setLogStream(PrintStream)`. +include::partial$manual/composite-configuration.adoc[tag=intro] -Given any `Writer`, like a `PrintWriter`, you tell Log4j to append -events to that writer by creating a `WriterAppender` and updating the -Log4j configuration: +You can programmatically combine multiple configurations into a single one using link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/composite/CompositeConfiguration.html[`CompositeConfiguration`]: +.Snippet from an example {antora-examples-url}/manual/customconfig/Usage.java[`Usage.java`] [source,java] ---- -void addAppender(final Writer writer, final String writerName) { - final LoggerContext context = LoggerContext.getContext(false); - final Configuration config = context.getConfiguration(); - final PatternLayout layout = PatternLayout.createDefaultLayout(config); - final Appender appender = WriterAppender.createAppender(layout, null, writer, writerName, false, true); - appender.start(); - config.addAppender(appender); - updateLoggers(appender, config); -} - -private void updateLoggers(final Appender appender, final Configuration config) { - final Level level = null; - final Filter filter = null; - for (final LoggerConfig loggerConfig : config.getLoggers().values()) { - loggerConfig.addAppender(appender, level, filter); - } - config.getRootLogger().addAppender(appender, level, filter); -} +include::example$manual/customconfig/Usage.java[tag=combineConfigurations,indent=0] ---- +<1> Loading a common, and an application-specific configuration from file +<2> Casting them to `AbstractConfiguration`, the type required by `CompositeConfiguration` +<3> Programmatically creating an uninitialized configuration. +Note that no casting is needed. +<4> Creating a `CompositeConfiguration` using all three configurations created. +Note that passed configuration order matters! + +.How does `CompositeConfiguration` work? +[%collapsible] +==== +include::partial$manual/composite-configuration.adoc[tag=how] +==== -You can achieve the same effect with an `OutputStream`, like a -`PrintStream`: +[#Hybrid] +=== [[AddingToCurrent]] [[AppendingToWritersAndOutputStreams]] Modifying configuration components + +[WARNING] +==== +*We strongly advise against programmatically modifying components of a configuration!* +This section will explain what it is, and why you should avoid it. +==== + +It is unfortunately common that users modify components (appenders, filters, etc.) of a configuration programmatically as follows: [source,java] ---- -void addAppender(final OutputStream outputStream, final String outputStreamName) { - final LoggerContext context = LoggerContext.getContext(false); - final Configuration config = context.getConfiguration(); - final PatternLayout layout = PatternLayout.createDefaultLayout(config); - final Appender appender = OutputStreamAppender.createAppender(layout, null, outputStream, outputStreamName, false, true); - appender.start(); - config.addAppender(appender); - updateLoggers(appender, config); -} +LoggerContext context = LoggerContext.getContext(false); +Configuration config = context.getConfiguration(); +PatternLayout layout = PatternLayout.createDefaultLayout(config); +Appender appender = createCustomAppender(); +appender.start(); +config.addAppender(appender); +updateLoggers(appender, config); ---- -The difference is the use of `OutputStreamAppender` instead of -`WriterAppender`. +This approach is prone several problems: + +* Your code relies on Log4j Core internals which don't have any backward compatibility guarantees. +You not only risk breaking your build at a minor Log4j Core version upgrade, but also make the life of Log4j maintainers trying to evolve the project extremely difficult. +* You move out from the safety zone, where Log4j Core takes care of components' life cycle (initialization, reconfiguration, etc.), and step into a minefield seriously undermining the reliability of your logging setup. + +If you happen to have code programmatically modifying components of a configuration, we advise you to migrate to other declarative approaches shared in this page. +In case of need, feel free to ask for help in {logging-services-url}/support.html#discussions-user[user support channels]. diff --git a/src/site/antora/modules/ROOT/pages/manual/dependencyinjection.adoc b/src/site/antora/modules/ROOT/pages/manual/dependencyinjection.adoc index e6686c541a6..ee1f5b782e0 100644 --- a/src/site/antora/modules/ROOT/pages/manual/dependencyinjection.adoc +++ b/src/site/antora/modules/ROOT/pages/manual/dependencyinjection.adoc @@ -24,19 +24,19 @@ Instance factories may be customized through post-processor service classes whic == Overview -The `org.apache.logging.log4j.plugins.di.ConfigurableInstanceFactory` runtime keeps a registry of bindings between `Key` and `Supplier`, where `org.apache.logging.log4j.plugins.di.Key` describes an instance type `T`, optional qualifier annotation type, and optional name plus namespace, and `java.util.function.Supplier` defines a factory for obtaining instances of `T` matching the corresponding `Key`. -To obtain a factory for a given key, if a binding is not already registered for said key, then the raw class of the key (i.e., the `Class` instance from `Key`) is checked for a single constructor annotated with `@org.apache.logging.log4j.plugins.Inject` or a no-arg constructor if no `@Inject` constructor is present. +The link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/di/ConfigurableInstanceFactory.html[`ConfigurableInstanceFactory`] runtime keeps a registry of bindings between link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/di/Key.html[`Key`] and `Supplier`, where `Key` describes an instance type `T`, optional qualifier annotation type, and optional name plus namespace, and `java.util.function.Supplier` defines a factory for obtaining instances of `T` matching the corresponding `Key`. +To obtain a factory for a given key, if a binding is not already registered for said key, then the raw class of the key (i.e., the `Class` instance from `Key`) is checked for a single constructor annotated with link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/Inject.html[`@Inject`] or a no-arg constructor if no `@Inject` constructor is present. The injectable constructor is invoked with arguments which are obtained by looking up factories matching the `Key` of each constructor parameter. -Then, fields that are annotated with `@Inject` or annotated with an annotation that is itself annotated with `@QualifierType` (i.e., a _qualifier annotation_) are injected from factories matching the `Key` of the field. +Then, fields that are annotated with `@Inject` or annotated with an annotation that is itself annotated with link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/QualifierType.html[`@QualifierType`] (i.e., a _qualifier annotation_) are injected from factories matching the `Key` of the field. Next, methods that are annotated with `@Inject` or have a parameter annotated with a qualifier annotation are invoked using factories matching the `Key` of each parameter. Lastly, no-arg methods annotated with `@Inject` are invoked which can be useful for post-injection initialization logic. Additional strategies for resolving factories for unbound keys may be registered which are consulted first before falling back to this `@Inject` reflection logic. -Bindings may be registered using `ConfigurableInstanceFactory::registerBinding` or `ConfigurableInstanceFactory::registerBindingIfAbsent` using explicit `Binding` instances, or they may be registered using `ConfigurableInstanceFactory::registerBundle` as _bundles_ which are instances or injectable `Class` instances that contain one or more annotated factory methods. -Annotated factory methods are non-abstract methods annotated with an annotation that is itself annotated with `@org.apache.logging.log4j.plugins.FactoryType`. -Built-in factory annotations include `@org.apache.logging.log4j.plugins.Factory` and `@org.apache.logging.log4j.plugins.PluginFactory`. +Bindings may be registered using `ConfigurableInstanceFactory::registerBinding` or `ConfigurableInstanceFactory::registerBindingIfAbsent` using explicit `Key` and `Supplier` pairs, or they may be registered using `ConfigurableInstanceFactory::registerBundle` as _bundles_ which are instances or injectable `Class` instances that contain one or more annotated factory methods. +Annotated factory methods are non-abstract methods annotated with an annotation that is itself annotated with link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/FactoryType.html[`@FactoryType`]. +Built-in factory annotations include link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/Factory.html[`@Factory`] and link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/PluginFactory.html[`@PluginFactory`]. -`ConfigurableInstanceFactory` can create `@Configurable` namespace plugins from a tree of `org.apache.logging.log4j.plugins.Node` instances using `org.apache.logging.log4j.core.config.ConfigurationProcessor`. +`ConfigurableInstanceFactory` can create link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/Configurable[`@Configurable`] namespace plugins from a tree of link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/Node.html[`Node`] instances using link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/ConfigurationProcessor.html[`ConfigurationProcessor`]. This allows for node attributes and child nodes to be injected into a plugin class along with any other registered bindings. To configure a `Node`, its plugin class is checked for a static method annotated with a factory annotation (such as `@PluginFactory` or `@Factory`) first before falling back to checking for an `@Inject` constructor or a no-args constructor. This static factory method or constructor has its parameters injected. @@ -53,14 +53,16 @@ Injection points are injectable fields or parameters where a dependency should b _Injectable fields_ are fields annotated with `@Inject` or a qualifier annotation. _Injectable methods_ are methods annotated with `@Inject` or are not annotated with a factory annotation and have at least one parameter annotated with a qualifier annotation. _Injectable constructors_ are constructors annotated with `@Inject`; only one such constructor should exist per class. -When a field or parameter is annotated with a name-providing annotation (i.e., an annotation annotated with `@org.apache.logging.log4j.plugins.name.NameProvider`), then the provided name or name of the field or parameter are included in the `Key` for the injection point. -When these elements are annotated with a `@Namespace` annotation or meta-annotation, then that namespace name is included in the `Key` for the injection point. +When a field or parameter is annotated with a name-providing annotation (i.e., an annotation annotated with link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/name/NameProvider.html[`@NameProvider`]), then the provided name or name of the field or parameter are included in the `Key` for the injection point. +When these elements are annotated with a link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/Namespace.html[`@Namespace`] annotation or meta-annotation, then that namespace name is included in the `Key` for the injection point. Similarly, when a field or parameter is annotated with a qualifier annotation, then that qualifier annotation type is included in the `Key` for the injection point. An example of each injection point with a no-arg `@Inject` method to show the post-injected state: [source,java] ---- +import org.apache.logging.log4j.plugins.Inject; + class ExampleBean { @Override public String toString() { @@ -109,40 +111,43 @@ class MethodInjection { === Names and Qualifiers -Qualifiers are annotations that are annotated with `@org.apache.logging.log4j.plugins.QualifierType`. +Qualifiers are annotations that are annotated with link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/QualifierType.html[`@QualifierType`]. Qualifiers provide a way to match dependencies and factories based on more than just their type. -For example, the `@org.apache.logging.log4j.plugins.Named` qualifier allows for creating different bindings of the same type with different names (along with support for aliases). +For example, the link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/Named.html[`@Named`] qualifier allows for creating different bindings of the same type with different names (along with support for aliases). Qualifiers on an injection point request a binding with that qualifier type and name. Qualifiers on a factory method register a binding with that qualifier type and name. -The name for a qualifier is provided via an `org.apache.logging.log4j.plugins.name.AnnotatedElementNameProvider` strategy class given in the `@NameProvider` annotation declared on the qualifier annotation. -Aliases are likewise provided via an `org.apache.logging.log4j.plugins.name.AnnotatedElementAliasesProvider` strategy class given in the `@AliasesProvider` annotated declared on the qualifier annotation. +The name for a qualifier is provided via an link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/name/AnnotatedElementNameProvider.html[`AnnotatedElementNameProvider`] strategy class given in the `@NameProvider` annotation declared on the qualifier annotation. +Aliases are likewise provided via an link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/name/AnnotatedElementAliasesProvider.html[`AnnotatedElementAliasesProvider`] strategy class given in the `@AliasesProvider` annotated declared on the qualifier annotation. === Scopes Scopes control the lifecycle of instances returned from a factory. -Scopes correspond to an annotation that is annotated with `@org.apache.logging.log4j.plugins.ScopeType`. -By default, `@org.apache.logging.log4j.plugins.Singleton` and the default scope are supported. +Scopes correspond to an annotation that is annotated with link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/ScopeType.html[`@ScopeType`]. +By default, link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/Singleton.html[`@Singleton`] and the default scope are supported. The `@Singleton` scope ensures that only a single instance is returned from factories bound in that scope. The default scope returns a new instance every time. Additional scopes may be registered via `ConfigurableInstanceFactory::registerScope`. == Injector Callbacks -An `ConfigurableInstanceFactory` may be initialized with `org.apache.logging.log4j.plugins.di.spi.ConfigurableInstanceFactoryPostProcessor` service classes. +An `ConfigurableInstanceFactory` may be initialized with link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/di/spi/ConfigurableInstanceFactoryPostProcessor.html[`ConfigurableInstanceFactoryPostProcessor`] service classes. These service classes must be declared in their respective `module-info.java` files containing `provides org.apache.logging.log4j.plugins.di.spi.ConfigurableInstanceFactoryPostProcessor with my.fully.qualified.ClassName;` and should also be declared in a file named `META-INF/services/org.apache.logging.log4j.plugins.di.spi.ConfigurableInstanceFactoryPostProcessor` containing the line `my.fully.qualified.ClassName` for traditional classpath usage. -Post-processor services are invoked in the order defined by the `@Order` annotation on the class. +Post-processor services are invoked in the order defined by the link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/Ordered.html[`@Ordered`] annotation on the class. Each post-processor is given the `ConfigurableInstanceFactory` being initialized where it can be introspected and modified. === Configurable Bindings -The default callback sets up bindings for the following keys if none have been registered. -Some of these bindings were previously configured through various system properties which are supported via the default callback and its default bindings, though they can be directly registered via custom callbacks with a negative order value. +Log4j sets up {project-github-url}/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/CoreDefaultBundle.java[`CoreDefaultBundle`] containing default bindings for the following types if none are already registered. +More details can be found in the xref:manual/extending.adoc[extending Log4j manual]. -* `org.apache.logging.log4j.core.ContextDataInjector` +* `org.apache.logging.log4j.core.async.AsyncQueueFullPolicy` * `org.apache.logging.log4j.core.config.ConfigurationFactory` +* `org.apache.logging.log4j.core.config.URIConfigurationFactory` * `org.apache.logging.log4j.core.config.composite.MergeStrategy` * `org.apache.logging.log4j.core.impl.LogEventFactory` +* `org.apache.logging.log4j.core.lookup.ConfigurationStrSubstitutor` * `org.apache.logging.log4j.core.lookup.InterpolatorFactory` +* `org.apache.logging.log4j.core.lookup.RuntimeStrSubstitutor` * `org.apache.logging.log4j.core.lookup.StrSubstitutor` * `org.apache.logging.log4j.core.selector.ContextSelector` * `org.apache.logging.log4j.core.time.Clock` @@ -150,3 +155,8 @@ Some of these bindings were previously configured through various system propert * `org.apache.logging.log4j.core.util.ShutdownCallbackRegistry` * `org.apache.logging.log4j.core.util.WatchManager` * `org.apache.logging.log4j.core.config.ConfigurationScheduler` +* `org.apache.logging.log4j.kit.recycler.RecyclerFactory` +* `org.apache.logging.log4j.message.FlowMessageFactory` +* `org.apache.logging.log4j.message.MessageFactory` +* `org.apache.logging.log4j.spi.LoggerContextFactory` +* `org.apache.logging.log4j.spi.Provider` diff --git a/src/site/antora/modules/ROOT/pages/manual/extending.adoc b/src/site/antora/modules/ROOT/pages/manual/extending.adoc index 6bdc61e738b..8ac60d0d690 100644 --- a/src/site/antora/modules/ROOT/pages/manual/extending.adoc +++ b/src/site/antora/modules/ROOT/pages/manual/extending.adoc @@ -14,490 +14,151 @@ See the License for the specific language governing permissions and limitations under the License. //// -= Extending Log4j -Log4j provides numerous ways that it can be manipulated and extended. -This section includes an overview of the various ways that are directly -supported by the Log4j 3 implementation. += Extending + +Log4j provides numerous extension points to adapt it for custom needs. +Several of such extension points are covered in the page of the associated component: + +* Log4j API +** {log4j2-url}/manual/customloglevels.html[Extending levels] +** {log4j2-url}/manual/markers.html[Extending markers] +** {log4j2-url}/manual/messages.html#extending[Extending messages] +** {log4j2-url}/manual/thread-context.html#extending[Extending thread context] +* Log4j Core +** xref:manual/appenders.adoc#extending[Extending appenders] +** xref:manual/filters.adoc#extending[Extending filters] +** xref:manual/layouts.adoc#extending[Extending layouts] +*** xref:manual/json-template-layout.adoc#extending[Extending JSON Template Layout] +*** xref:manual/pattern-layout.adoc#extending[Extending Pattern Layout] +** xref:manual/lookups.adoc#extending[Extending lookups] + +This section guides you on the rest of the Log4j extension points. + +[#mechanisms] +== Extension mechanisms + +Log4j allows extensions primarily using following mechanisms: + +[#Custom_Plugins] +=== Plugins + +include::partial$manual/plugin-preliminaries.adoc[] + +[#bindings] +=== Bindings + +The Log4j plugin system was enhanced in 3.0 to support arbitrary bindings for xref:manual/dependencyinjection.adoc[dependency injection]. +Many shared components in Log4j could be configured via system properties or similar to include a fully qualified class name to use. +Using custom bindings, however, these custom classes can be configured as code. +Default bindings are configured in {project-github-url}/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/CoreDefaultBundle.java[`CoreDefaultBundle`]. +Custom bindings can be installed by defining a link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/di/spi/ConfigurableInstanceFactoryPostProcessor.html[`ConfigurableInstanceFactoryPostProcessor`] service class which invokes `ConfigurableInstanceFactory::registerBundle` to register the bundle class containing the bindings. +This approach is more portable than the legacy approach of using system properties to define the classes as it removes ambiguity of `ClassLoader` ownership and other details of modules and similar runtimes. + +[#service-loader] +=== ``ServiceLoader``s + +https://docs.oracle.com/javase/{java-target-version}/docs/api/java/util/ServiceLoader.html[`ServiceLoader`] is a simple service-provider loading facility baked into the Java platform itself. +Log4j uses ``ServiceLoader``s for extending places where + +* The service needs to be implementation agnostic. +As a result, <> cannot be used, since it is provided by the logging implementation, i.e., Log4j Core. +For instance, this is why {log4j2-url}/manual/thread-context.html#extending[extending Thread Context], which is a Log4j API component, works using ``ServiceLoader``s. + +* The service needs to be loaded before <>. +For instance, this is why <> works using ``ServiceLoader``s. + +Refer to https://docs.oracle.com/javase/{java-target-version}/docs/api/java/util/ServiceLoader.html[the `ServiceLoader` documentation] for details. + +[#system-properties] +=== System properties + +Log4j uses system properties to determine the fully-qualified class name (FQCN) to load for extending a certain functionality. +For instance, <> works using system properties. + +[WARNING] +==== +Loading a class using _only_ its FQCN can result in unexpected behaviour when there are multiple class loaders. +==== + +[#points] +== Extension points + +In this section we will guide you on certain Log4j extension points that are not covered elsewhere. + +[#Provider] +=== `Provider` + +link:../javadoc/log4j-api/org/apache/logging/log4j/spi/Provider.html[`Provider`] is the anchor contract binding Log4j API to an implementation. +For instance, it has been implemented by Log4j Core, Log4j-to-JUL bridge, and Log4j-to-SLF4J bridge modules. + +Under the hood, link:../javadoc/log4j-api/org/apache/logging/log4j/LogManager.html[`LogManager`] locates a `Provider` implementation using <>, and delegates invocations to it. +Hence, you can extend it by providing a `org.apache.logging.log4j.spi.Provider` implementation in the form of a `ServiceLoader`. + +Having multiple ``Provider``s in the classpath is strongly discouraged. +A specific provider can be <> using a custom bundle class if Log4j Core is also available. +Alternatively, you can use xref:manual/systemproperties.adoc#log4j.provider[the `log4j.provider` property] to explicitly select one. [#LoggerContextFactory] -== LoggerContextFactory - -The `LoggerContextFactory` binds the Log4j API to its implementation. -The Log4j `LogManager` locates a `LoggerContextFactory` by using -`java.util.ServiceLoader` to locate all instances of -`org.apache.logging.log4j.spi.Provider`. Each implementation must -provide a class that extends `org.apache.logging.log4j.spi.Provider` and -should have a no-arg constructor that delegates to Provider's -constructor passing the Priority, the API versions it is compatible -with, and the class that implements -`org.apache.logging.log4j.spi.LoggerContextFactory`. Log4j will compare -the current API version and if it is compatible the implementation -will be added to the list of providers. The API version in -`org.apache.logging.log4j.LogManager` is only changed when a feature is -added to the API that implementations need to be aware of. If more than -one valid implementation is located the value for the Priority will be -used to identify the factory with the highest priority. Finally, the -class that implements -`org.apache.logging.log4j.spi.LoggerContextFactory` will be instantiated -and bound to the LogManager. In Log4j 2 this is provided by -`Log4jContextFactory`. - -Applications may change the LoggerContextFactory that will be used by - -1. Create a binding to the logging implementation. -.. Implement a new link:../javadoc/log4j-core/org/apache/logging/log4j/core/impl/Log4jContextFactory.html[`LoggerContextFactory`]. -.. Implement a class that extends -{log4j2-url}/javadoc/log4j-api/org/apache/logging/spi/Provider.html[`org.apache.logging.spi.Provider`] -with a no-arg constructor that calls super-class's constructor with the -Priority, the API version(s), `LoggerContextFactory` class, and -optionally, a -{log4j2-url}/javadoc/log4j-api/org/apache/logging/log4j/spi/ThreadContextMap.html[`ThreadContextMap`] -implementation class. -.. Create a `META-INF/services/org.apache.logging.spi.Provider` file -that contains the name of the class that implements -`org.apache.logging.spi.Provider`. -2. Setting the system property "log4j2.loggerContextFactory" to the name -of the `LoggerContextFactory` class to use. -3. Setting the property "log4j2.loggerContextFactory" in a properties -file named "log4j2.LogManager.properties" to the name of the -LoggerContextFactory class to use. The properties file must be on the -classpath. - -[#InjectorCallback] -== InjectorCallback -InjectorCallback services are called by an link:../log4j-plugins/apidocs/org/apache/logging/log4j/plugins/di/Injector.html[`Injector`] when its `init()` method is invoked (see link:./dependencyinjection.html[Dependency Injection] for further information about `Injector`). -These callback services are invoked in order using `InjectorCallback::getOrder` and the natural integer comparator. -Callbacks may examine the current state of the invoking `Injector` as well as make changes to bindings or provide default bindings. -Backwards compatibility with system property based methods for configuring various extensions are handled through a default callback with order 0 which allows for making customizations before or after the defaults are set up. -Callback classes must have a no-args constructor and need to be defined in two places: - -1. Add the fully qualified class name of the callback class to a file named `META-INF/services/org.apache.logging.log4j.plugins.di.InjectorCallback`. -2. For compatibility with Java modules, add a line to `module-info.java` containing `provides org.apache.logging.log4j.plugins.di.InjectorCallback with my.fully.qualified.ClassName;`. +=== `LoggerContextFactory` + +link:../javadoc/log4j-api/org/apache/logging/log4j/spi/LoggerContextFactory.html[`LoggerContextFactory`] is the factory class used by Log4j API implementations to create xref:manual/architecture.adoc#LoggerContext[`LoggerContext`]s. +If you are using Log4j Core, you can use <>s to influence the way its `LoggerContextFactory` implementation works. +If you are creating a new Log4j API implementation, you should <> to introduce your custom `LoggerContextFactory` implementation. [#ContextSelector] -== ContextSelector - -ContextSelectors are called by the -link:../javadoc/log4j-core/org/apache/logging/log4j/core/impl/Log4jContextFactory.html[Log4j `LoggerContext` factory]. They perform the actual work of locating or -creating a LoggerContext, which is the anchor for Loggers and their -configuration. ContextSelectors are free to implement any mechanism they -desire to manage LoggerContexts. The default Log4jContextFactory checks -for the presence of an `Injector` binding for `ContextSelector`. -If none are defined, the System Property named "Log4jContextSelector" is checked. -If found, the property is expected to contain the name of the Class that implements the ContextSelector to be used. -This class is then used for creating `ContextSelector` instances. - -Log4j provides five ContextSelectors: - -link:../javadoc/log4j-core/org/apache/logging/log4j/core/selector/BasicContextSelector.html[`BasicContextSelector`]:: - Uses either a LoggerContext that has been stored in a ThreadLocal or a - common LoggerContext. -link:../javadoc/log4j-core/org/apache/logging/log4j/core/selector/ClassLoaderContextSelector.html[`ClassLoaderContextSelector`]:: - Associates LoggerContexts with the ClassLoader that created the caller - of the getLogger(...) call. This is the default ContextSelector. -link:../javadoc/log4j-core/org/apache/logging/log4j/core/selector/JndiContextSelector.html[`JndiContextSelector`]:: - Locates the LoggerContext by querying JNDI. -link:../javadoc/log4j-core/org/apache/logging/log4j/core/async/AsyncLoggerContextSelector.html[`AsyncLoggerContextSelector`]:: - Creates a LoggerContext that ensures that all loggers are - AsyncLoggers. -link:../javadoc/log4j-core/org/apache/logging/log4j/core/osgi/BundleContextSelector.html[`BundleContextSelector`]:: - Associates LoggerContexts with the ClassLoader of the bundle that - created the caller of the getLogger call. This is enabled by default - in OSGi environments. +=== `ContextSelector` + +link:../javadoc/log4j-core/org/apache/logging/log4j/core/impl/Log4jContextFactory.html[`Log4jContextFactory`], the Log4j Core implementation of <>, delegates the actual work to a link:../javadoc/log4j-core/org/apache/logging/log4j/core/selector/ContextSelector.html[`ContextSelector`]. +This should be configured as a `ContextSelector` binding in a <>. +Alternatively, it can be configured using xref:manual/systemproperties.adoc#log4j.loggerContext.selector[the `log4j.loggerContext.selector` property]. [#ConfigurationFactory] -== ConfigurationFactory - -Modifying the way in which logging can be configured is usually one of -the areas with the most interest. The primary method for doing that is -by implementing or extending a -link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/ConfigurationFactory.html[`ConfigurationFactory`]. -Log4j provides two ways of adding new ConfigurationFactories. The first -is by defining the system property named "log4j.configurationFactory" to -the name of the class that should be searched first for a configuration. -The second method is by defining the `ConfigurationFactory` as a `Plugin`. - -All the ConfigurationFactories are then processed in order. Each factory -is called on its `getSupportedTypes()` method to determine the file -extensions it supports. If a configuration file is located with one of -the specified file extensions then control is passed to that -`ConfigurationFactory` to load the configuration and create the link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/Configuration.html[`Configuration`] object. - -Most `Configuration` extend the link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/AbstractConfiguration.html[`AbstractConfiguration`] class. This class expects that the subclass will process the configuration file and create -a hierarchy of `Node` objects. Each `Node` is fairly simple in that it -consists of the name of the node, the name/value pairs associated with -the node, The `PluginType` of the node and a List of all of its child -Nodes. `Configuration` will then be passed the `Node` tree and -instantiate the configuration objects from that. - -[source,java] ----- -@Namespace("ConfigurationFactory") -@Plugin("XMLConfigurationFactory") -@Order(5) -public class XMLConfigurationFactory extends ConfigurationFactory { - - /** - * Valid file extensions for XML files. - */ - public static final String[] SUFFIXES = new String[] {".xml", "*"}; - - /** - * Returns the Configuration. - * @param loggerContext The logger context. - * @param source The InputSource. - * @return The Configuration. - */ - @Override - public Configuration getConfiguration(final LoggerContext loggerContext, final ConfigurationSource source) { - return new XmlConfiguration(loggerContext, source); - } - - /** - * Returns the file suffixes for XML files. - * @return An array of File extensions. - */ - public String[] getSupportedTypes() { - return SUFFIXES; - } -} ----- +=== `ConfigurationFactory` + +link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/ConfigurationFactory.html[`ConfigurationFactory`] is the factory class used by Log4j Core to create link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/Configuration.html[`Configuration`] instances given a xref:manual/architecture.adoc#LoggerContext[`LoggerContext`] and a link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/ConfigurationSource.html[`ConfigurationSource`]. + +You can provide a custom `ConfigurationFactory` in the form of a <>. +For example, see {project-github-url}/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfigurationFactory.java[`XmlConfigurationFactory.java`] and {project-github-url}/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java[`XmlConfiguration.java`] of Log4j Core. + +A specific configuration factory can be bound in a <> which can take priority over the default configuration factories. +You can also use xref:manual/systemproperties.adoc#log4j.configuration.factory[the `log4j.configuration.factory` property] to explicitly set a `ConfigurationFactory` to be used before any other factory implementation. [#LoggerConfig] -== LoggerConfig - -`LoggerConfig` objects are where Loggers created by applications tie into -the configuration. The Log4j implementation requires that all -LoggerConfigs are based on the LoggerConfig class, so applications -wishing to make changes must do so by extending the `LoggerConfig` class. -To declare the new `LoggerConfig`, declare it as a Plugin of type "Core" -and providing the name that applications should specify as the element -name in the configuration. The `LoggerConfig` should also define a -PluginFactory that will create an instance of the `LoggerConfig`. - -The following example shows how the root `LoggerConfig` simply extends a -generic `LoggerConfig`. - -[source,java] ----- -@Configurable(printObject = true) -@Plugin("root") -public static class RootLogger extends LoggerConfig { - - @PluginFactory - public static LoggerConfig createLogger(@PluginAttribute(defaultBooleanValue = true) boolean additivity, - @PluginAttribute(defaultStringValue = "ERROR") Level level, - @PluginElement AppenderRef[] refs, - @PluginElement Filter filter) { - List appenderRefs = Arrays.asList(refs); - return new LoggerConfig(LogManager.ROOT_LOGGER_NAME, appenderRefs, filter, level, additivity); - } -} ----- +=== `LoggerConfig` + +link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/LoggerConfig.html[`LoggerConfig`] denotes the `Logger` configurations in a `Configuration`. +A custom `LoggerConfig` needs to satisfy the following conditions: + +* It needs to extend from `LoggerConfig` class +* It needs to be declared as a <> +* It needs to include a `@Configurable` annotation on the class + +For example, see `RootLogger` definition in {project-github-url}/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java[`LoggerConfig.java`]. [#LogEventFactory] -== LogEventFactory +=== `LogEventFactory` -A LogEventFactory is used to generate LogEvents. Applications may replace the standard LogEventFactory by setting the value of the system property Log4jLogEventFactory to the name of the custom LogEventFactory class. +Log4j Core uses link:../javadoc/log4j-core/org/apache/logging/log4j/core/impl/LogEventFactory.html[`LogEventFactory`] to create link:../javadoc/log4j-core/org/apache/logging/log4j/core/LogEvent.html[`LogEvent`]s. +You can replace the default `LogEventFactory` implementation with a custom one of yours by defining a <> for `LogEventFactory` or by using xref:manual/systemproperties.adoc#log4j.logEvent.factory[the `log4j.logEvent.factory` property]. -Note: When log4j is configured to have xref:manual/async.adoc#AllAsync[all -loggers asynchronous], log events are pre-allocated in a ring buffer and -the `LogEventFactory` is not used. +[NOTE] +==== +xref:manual/async.adoc[] discard `LogEventFactory` and any configuration related with it. +==== [#MessageFactory] -== MessageFactory - -A `MessageFactory` is used to generate `Message` objects. Applications may -replace the standard `ReusableMessageFactory` by setting the value of the -system property `log4j2.messageFactory` to the name of the custom -`MessageFactory` class. - -Flow messages for the `Logger.entry()` and `Logger.exit()` methods have -a separate `FlowMessageFactory`. Applications may replace the -`DefaultFlowMessageFactory` by setting the value of the system property -`log4j2.flowMessageFactory` to the name of the custom `FlowMessageFactory` -class. - -[#Lookups] -== Lookups - -Lookups are the means in which parameter substitution is performed. -During Configuration initialization an "Interpolator" is created that -locates all the Lookups and registers them for use when a variable needs -to be resolved. The interpolator matches the "prefix" portion of the -variable name to a registered Lookup and passes control to it to resolve -the variable. - -A Lookup must be declared using a `@Plugin @Lookup` annotation. The `value` specified on the `@Plugin` annotation will be used to -match the prefix. The example below shows a Lookup that will return -the value of a System Property. - -The provided Lookups are documented here: xref:manual/lookups.adoc[Lookups] - -[source,java] ----- -@Lookup -@Plugin("sys") -public class SystemPropertiesLookup implements StrLookup { - - /** - * Lookup the value for the key. - * @param key the key to be looked up, may be null - * @return The value for the key. - */ - public String lookup(String key) { - return System.getProperty(key); - } - - /** - * Lookup the value for the key using the data in the LogEvent. - * @param event The current LogEvent. - * @param key the key to be looked up, may be null - * @return The value associated with the key. - */ - public String lookup(LogEvent event, String key) { - return System.getProperty(key); - } -} ----- - -[#Filters] -== Filters - -As might be expected, Filters are used to reject or accept log -events as they pass through the logging system. A Filter is declared -using a `@Configurable` annotation with an `elementType` of "filter". -The `value` attribute on the `@Plugin` annotation is used to specify the name -of the element users should use to enable the Filter. Specifying the -`printObject` attribute with a value of "true" indicates that a call to -`toString` will format the arguments to the filter as the configuration is -being processed. The Filter must also specify a `@PluginFactory` method -or `@PluginFactoryBuilder` builder class and method -that will be called to create the Filter. - -The example below shows a Filter used to reject LogEvents based upon -their logging level. Notice the typical pattern where all the filter -methods resolve to a single filter method. - -[source,java] ----- -@Configurable(elementType = Filter.ELEMENT_TYPE, printObject = true) -@Plugin -public final class ThresholdFilter extends AbstractFilter { - - private final Level level; - - private ThresholdFilter(Level level, Result onMatch, Result onMismatch) { - super(onMatch, onMismatch); - this.level = level; - } - - public Result filter(Logger logger, Level level, Marker marker, String msg, Object[] params) { - return filter(level); - } - - public Result filter(Logger logger, Level level, Marker marker, Object msg, Throwable t) { - return filter(level); - } - - public Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t) { - return filter(level); - } - - @Override - public Result filter(LogEvent event) { - return filter(event.getLevel()); - } - - private Result filter(Level level) { - return level.isAtLeastAsSpecificAs(this.level) ? onMatch : onMismatch; - } - - @Override - public String toString() { - return level.toString(); - } - - /** - * Create a ThresholdFilter. - * @param level The log Level. - * @param onMatch The action to take on a match. - * @param onMismatch The action to take on a mismatch. - * @return The created ThresholdFilter. - */ - @PluginFactory - public static ThresholdFilter createFilter(@PluginAttribute(defaultStringValue = "ERROR") Level level, - @PluginAttribute(defaultStringValue = "NEUTRAL") Result onMatch, - @PluginAttribute(defaultStringValue = "DENY") Result onMismatch) { - return new ThresholdFilter(level, onMatch, onMismatch); - } -} ----- - -[#Appenders] -== Appenders - -Appenders are passed an event, (usually) invoke a Layout to format the -event, and then "publish" the event in whatever manner is desired. -Appenders are declared as `@Configurable` with an -`elementType` of "appender". The `value` attribute on the `@Plugin` annotation -specifies the name of the element users must provide in their -configuration to use the Appender. Appenders should specify `printObject` -as "true" if the toString method renders the values of the attributes -passed to the Appender. - -Appenders must also declare a `@PluginFactory` method that returns an instance -of the appender or a builder class used to create the appender. The example below shows -an Appender named "Stub" that can be used as an initial template. - -Most Appenders use Managers. A manager actually "owns" the resources, -such as an `OutputStream` or socket. When a reconfiguration occurs a new -Appender will be created. However, if nothing significant in the -previous Manager has changed, the new Appender will simply reference it -instead of creating a new one. This insures that events are not lost -while a reconfiguration is taking place without requiring that logging -pause while the reconfiguration takes place. - -[source,java] ----- -@Configurable(elementType = Appender.ELEMENT_TYPE, printObject = true) -@Plugin("Stub") -public final class StubAppender extends AbstractOutputStreamAppender { - - private StubAppender(String name, - Layout layout, - Filter filter, - boolean ignoreExceptions, - StubManager manager) { - super(name, layout, filter, ignoreExceptions, true, manager); - } - - @PluginFactory - public static StubAppender createAppender(@PluginAttribute @Required(message = "No name provided for StubAppender") String name, - @PluginAttribute boolean ignoreExceptions, - @PluginElement Layout layout, - @PluginElement Filter filter) { - - StubManager manager = StubManager.getStubManager(name); - if (manager == null) { - return null; - } - if (layout == null) { - layout = PatternLayout.createDefaultLayout(); - } - return new StubAppender(name, layout, filter, ignoreExceptions, manager); - } -} ----- - -[#Plugin_Builders] -== Plugin Builders - -Some plugins take a lot of optional configuration options. When a plugin -takes many options, it is more maintainable to use a builder class -rather than a factory method (see _Item 2: Consider a builder when faced -with many constructor parameters_ in _Effective Java_ by Joshua Bloch). -There are some other advantages to using an annotated builder class over -an annotated factory method: - -* Attribute names don't need to be specified if they match the field name or the parameter name. -* Default values can be specified in code rather than through an -annotation (also allowing a runtime-calculated default value which isn't -allowed in annotations). -* Adding new optional parameters doesn't require existing programmatic -configuration to be refactored. -* Easier to write unit tests using builders rather than factory methods -with optional parameters. -* Default values are specified via code rather than relying on -reflection and injection, so they work programmatically as well as in a -configuration file. - -Here is an example of a plugin factory from `ListAppender`: - -[source,java] ----- -@PluginFactory -public static ListAppender createAppender( - @PluginAttribute @Required(message = "No name provided for ListAppender") final String name, - @PluginAttribute final boolean entryPerNewLine, - @PluginAttribute final boolean raw, - @PluginElement final Layout layout, - @PluginElement final Filter filter) { - return new ListAppender(name, filter, layout, newLine, raw); -} ----- - -Here is that same factory using a builder pattern instead: - -[source,java] ----- -@PluginFactory -public static Builder newBuilder() { - return new Builder(); -} - -public static class Builder implements org.apache.logging.log4j.plugins.util.Builder { - - private String name; - private boolean entryPerNewLine; - private boolean raw; - private Layout layout; - private Filter filter; - - - public Builder setName( - @PluginAttribute - @Required(message = "No name provided for ListAppender") - final String name) { - this.name = name; - return this; - } - - public Builder setEntryPerNewLine(@PluginAttribute final boolean entryPerNewLine) { - this.entryPerNewLine = entryPerNewLine; - return this; - } - - public Builder setRaw(@PluginAttribute final boolean raw) { - this.raw = raw; - return this; - } - - public Builder setLayout(@PluginElement final Layout layout) { - this.layout = layout; - return this; - } - - public Builder setFilter(@PluginElement final Filter filter) { - this.filter = filter; - return this; - } - - @Override - public ListAppender build() { - return new ListAppender(name, filter, layout, entryPerNewLine, raw); - } -} ----- - -When plugins are being constructed after a configuration has been -parsed, a plugin builder will be used if available, otherwise a plugin -factory method will be used as a fallback. If a plugin contains neither -factory, then it cannot be used from a configuration file (it can still -be used programmatically of course). - -Here is an example of using a plugin factory versus a plugin builder -programmatically: - -[source,java] ----- -ListAppender list1 = ListAppender.createAppender("List1", true, false, null, null); -ListAppender list2 = ListAppender.newBuilder().setName("List1").setEntryPerNewLine(true).build(); ----- +=== `MessageFactory2` -[#Custom_Plugins] -== Custom Plugins +Log4j Core uses link:../javadoc/log4j-api/org/apache/logging/log4j/message/MessageFactory2.html[`MessageFactory2`] to create link:../javadoc/log4j-api/org/apache/logging/log4j/message/Message.html[`Message`]s. +You can replace the default `MessageFactory2` implementation with a custom one of yours by using xref:manual/systemproperties.adoc#log4j.message.factory[the `log4j.message.factory` property]. + +[IMPORTANT] +==== +Message factory implementations are expected to interpret formatting patterns containing placeholders denoted with `{}`. +For instance, the default message factory chooses between a {log4j2-url}/manual/messages.html#SimpleMessage[`SimpleMessage`] and a {log4j2-url}/manual/messages.html#ParameterizedMessage[`ParameterizedMessage`] depending on the presence of placeholders in the formatting pattern. -// TODO -See the xref:manual/plugins.adoc[Plugins] section of the manual. +If you want to change the placeholder style (e.g., switching from `{}` to `%s`), you should *not* replace the default message factory. +Because this will break the existing Log4j API calls using the standard placeholder style. +Instead, you can use link:../javadoc/log4j-api/org/apache/logging/log4j/LogManager.html[`LogManager`] methods accepting a message factory to create ``Logger``s with your custom message factory implementations. +==== diff --git a/src/site/antora/modules/ROOT/pages/manual/filters.adoc b/src/site/antora/modules/ROOT/pages/manual/filters.adoc index e2101a48d79..f1b9468d7b6 100644 --- a/src/site/antora/modules/ROOT/pages/manual/filters.adoc +++ b/src/site/antora/modules/ROOT/pages/manual/filters.adoc @@ -960,10 +960,699 @@ xref:manual/configuration.adoc#configuration-attribute-monitorInterval[automatic to modify the ``KeyValuePair``s without restarting your application. ==== -xref:plugin-reference.adoc#org-apache-logging-log4j_log4j-core_org-apache-logging-log4j-core-filter-MapFilter[📖 Plugin reference for `MapFilter`] +[#collection] +== Collection + +Log4j bundles several predefined filters to assist in several common deployment use cases. +Following sections explain all these in detail. + +[#BurstFilter] +=== BurstFilter + +The BurstFilter provides a mechanism to control the rate at which LogEvents are processed by silently discarding events after the maximum limit has been reached. + +.Burst Filter Parameters +[cols="1m,1,4"] +|=== +|Parameter Name |Type |Description + +|level +|String +|Level of messages to be filtered. Anything at or below +this level will be filtered out if `maxBurst` has been exceeded. The +default is WARN meaning any messages that are higher than warn will be +logged regardless of the size of a burst. + +|rate +|float +|The average number of events per second to allow. + +|maxBurst +|integer +|The maximum number of events that can occur before +events are filtered for exceeding the average rate. The default is 10 +times the rate. + +|onMatch +|String +|Action to take when the filter matches. Can be ACCEPT, +DENY or NEUTRAL. The default value is NEUTRAL. + +|onMismatch +|String +|Action to take when the filter does not match. Can +be ACCEPT, DENY or NEUTRAL. The default value is DENY. +|=== + +A configuration containing the BurstFilter might look like: + +[source,xml] +---- + + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + +---- + +[#CompositeFilter] +=== CompositeFilter + +The CompositeFilter provides a way to specify more than one filter. +It is added to the configuration as a filter element and contains other filters to be evaluated. +The filter element accepts no parameters. + +A configuration containing the CompositeFilter might look like: + +[source,xml] +---- + + + + + + + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + + + + +---- + +[#DynamicThresholdFilter] +=== DynamicThresholdFilter + +The DynamicThresholdFilter allows filtering by log level based on specific attributes. +For example, if the user's loginId is being captured in the ThreadContext Map then it is possible to enable debug logging for only that user. +If the log event does not contain the specified ThreadContext item NEUTRAL will be returned. + +.Dynamic Threshold Filter Parameters +[cols="1m,1,4"] +|=== +|Parameter Name |Type |Description + +|key +|String +|The name of the item in the ThreadContext Map to compare. + +|defaultThreshold +|String +|Level of messages to be filtered. The default +threshold only applies if the log event contains the specified +ThreadContext Map item and its value do not match any key in the +key/value pairs. + +|keyValuePair +|KeyValuePair[] +|One or more KeyValuePair elements that +define the matching value for the key and the Level to evaluate when the +key matches. + +|onMatch +|String +|Action to take when the filter matches. Can be ACCEPT, +DENY or NEUTRAL. The default value is NEUTRAL. + +|onMismatch +|String +|Action to take when the filter does not match. Can +be ACCEPT, DENY or NEUTRAL. The default value is DENY. +|=== + +Here is a sample configuration containing the DynamicThresholdFilter: + +[source,xml] +---- + + + + + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + +---- + +[#LevelRangeFilter] +=== LevelRangeFilter + +`LevelRangeFilter` allows filtering against a level range, where levels get compared by their associated integral values; `OFF` has an integral value of 0, `FATAL` 100, `ERROR` 200, and so on. + +.`LevelRangeFilter` parameters +[cols="1m,1m,4"] +|=== +|Parameter Name |Type |Description + +|minLevel +|Level +|the minimum level threshold (defaults to `OFF`, which has an integral value of 0) + +|maxLevel +|Level +|the maximum level threshold (defaults to `ALL`, which has an integral value of `Integer.MAX_VALUE`) + +|onMatch +|Filter.Result +|the result to return on a match, where allowed values are `ACCEPT`, `DENY`, or `NEUTRAL` (default) + +|onMismatch +|Filter.Result +|the result to return on a mismatch, where allowed values are `ACCEPT`, `DENY` (default), or `NEUTRAL` +|=== + +In the following example configuration, a `LevelRangeFilter` is configured with `maxLevel` set to `INFO`. +The filter will return `onMismatch` result (i.e., `DENY`, the default) for log events of level with higher integral values than `INFO`; i.e., `DEBUG`, `TRACE`, etc. + +.Example configuration using `LevelRangeFilter` +[source,xml] +---- + + + + + + + + + + + + + + +---- + +[#MapFilter] +=== MapFilter + +The MapFilter allows filtering against data elements that are in a MapMessage. + +.Map Filter Parameters +[cols="1m,1,4"] +|=== +|Parameter Name |Type |Description + +|keyValuePair +|KeyValuePair[] +|One or more KeyValuePair elements that +define the key in the map and the value to match. If the same key is +specified more than once then the check for that key will automatically +be an "or" since a Map can only contain a single value. + +|operator +|String +|If the operator is "or" then a match by any one of +the key/value pairs will be considered to be a match, otherwise all the +key/value pairs must match. + +|onMatch +|String +|Action to take when the filter matches. Can be ACCEPT, +DENY or NEUTRAL. The default value is NEUTRAL. + +|onMismatch +|String +|Action to take when the filter does not match. Can +be ACCEPT, DENY or NEUTRAL. The default value is DENY. +|=== + +As in this configuration, the MapFilter can be used to log particular events: + +[source,xml] +---- + + + + + + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + +---- + +This sample configuration will exhibit the same behavior as the preceding example since the only logger configured is the root. + +[source,xml] +---- + + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + + + + + + +---- + +This third sample configuration will exhibit the same behavior as the preceding examples since the only logger configured is the root and the root is only configured with a single appender reference. + +[source,xml] +---- + + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + + + + + + +---- + +[#MarkerFilter] +=== MarkerFilter + +The MarkerFilter compares the configured Marker value against the Marker that is included in the LogEvent. +A match occurs when the Marker name matches either the Log Event's Marker or one of its parents. + +.Marker Filter Parameters +[cols="1m,1,4"] +|=== +|Parameter Name |Type |Description + +|marker +|String +|The name of the Marker to compare. + +|onMatch +|String +|Action to take when the filter matches. Can be ACCEPT, +DENY or NEUTRAL. The default value is NEUTRAL. + +|onMismatch +|String +|Action to take when the filter does not match. Can +be ACCEPT, DENY or NEUTRAL. The default value is DENY. +|=== + +A sample configuration that only allows the event to be written by the appender if the Marker matches: + +[source,xml] +---- + + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + +---- + +[#MutableThreadContextMapFilter] +=== MutableThreadContextMapFilter + +The MutableThreadContextMapFilter or MutableContextMapFilter allows filtering against data elements that are in the current context. +By default, this is the ThreadContext Map. +The values to compare are defined externally and can be periodically polled for changes. + +.Mutable Context Map Filter Parameters +[cols="1m,1,4"] +|=== +|Parameter Name |Type |Description + +|configLocation +|String +|A file path or URI that points to the configuration. See below for a sample configuration. + +|operator +|String +|If the operator is "or" then a match by any one of +the key/value pairs will be considered to be a match, otherwise all the +key/value pairs must match. + +|pollInterval +|int +|The number of seconds to wait before checking to see if the configuration has been modified. When using HTTP or HTTPS the server must support the If-Modified-Since header and return a Last-Modified header containing the date and time the file was last modified. Note that by default only the https, file, and jar protocols are allowed. Support for other protocols can be enabled by specifying them in the `log4j2.Configuration.allowedProtocols` system property + +|onMatch +|String +|Action to take when the filter matches. Can be ACCEPT, +DENY or NEUTRAL. The default value is NEUTRAL. + +|onMismatch +|String +|Action to take when the filter does not match. Can +be ACCEPT, DENY or NEUTRAL. The default value is DENY. +|=== + +A sample configuration that only allows the event to be written by the appender if the Marker matches: + +[source,xml] +---- + + + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + +---- + +The configuration file supplied to the filter should look similar to: + +[source,json] +---- +{ + "configs": { + "loginId": ["rgoers@apache.org", "logging@apache.org"], + "accountNumber": ["30510263"] + } +} +---- + +[#NoMarkerFilter] +=== NoMarkerFilter + +The NoMarkerFilter checks that there is no marker included in the LogEvent. +A match occurs when there is no marker in the Log Event. + +.No Marker Filter Parameters +[cols="1m,1,3"] +|=== +|Parameter Name |Type |Description + +|onMatch +|String +|Action to take when the filter matches. Can be ACCEPT, +DENY or NEUTRAL. The default value is NEUTRAL. + +|onMismatch +|String +|Action to take when the filter does not match. Can +be ACCEPT, DENY or NEUTRAL. The default value is DENY. +|=== + +A sample configuration that only allows the event to be written by the appender if no marker is there: + +[source,xml] +---- + + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + +---- + +[#RegexFilter] +=== RegexFilter + +The RegexFilter allows the formatted or unformatted message to be compared against a regular expression. + +.Regex Filter Parameters +[cols="1m,1,4"] +|=== +|Parameter Name |Type |Description + +|regex +|String +|The regular expression. + +|useRawMsg +|boolean +|If true the unformatted message will be used, +otherwise, the formatted message will be used. The default value is +false. + +|onMatch +|String +|Action to take when the filter matches. Can be ACCEPT, +DENY or NEUTRAL. The default value is NEUTRAL. + +|onMismatch +|String +|Action to take when the filter does not match. Can +be ACCEPT, DENY or NEUTRAL. The default value is DENY. +|=== + +A sample configuration that only allows the event to be written by the appender if it contains the word "test": + +[source,xml] +---- + + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + +---- + +[[Script]] +The ScriptFilter executes a script that returns true or false. + +.Script Filter Parameters +[cols="1m,1,4"] +|=== +|Parameter Name |Type |Description + +|script +|Script, ScriptFile or ScriptRef +|The Script element that specifies the logic to be executed. + +|onMatch +|String +|Action to take when the script returns true. Can be +ACCEPT, DENY or NEUTRAL. The default value is NEUTRAL. + +|onMismatch +|String +|Action to take when the filter returns false. Can +be ACCEPT, DENY or NEUTRAL. The default value is DENY. +|=== + +.Script Parameters +[cols="1m,1,4"] +|=== +|Parameter Name |Type |Description + +|configuration +|Configuration +|The Configuration that owns this +ScriptFilter. + +|level +|Level +|The logging Level associated with the event. Only present +when configured as a global filter. + +|loggerName +|String +|The name of the logger. Only present when +configured as a global filter. + +|logEvent +|LogEvent +|The LogEvent being processed. Not present when +configured as a global filter. + +|marker +|Marker +|The Marker passed on the logging call, if any. Only +present when configured as a global filter. + +|message +|Message +|The Message associated with the logging call. Only +present when configured as a global filter. + +|parameters +|Object[] +|The parameters passed to the logging call. Only +present when configured as a global filter. Some Messages include the +parameters as part of the Message. + +|throwable +|Throwable +|The Throwable passed to the logging call, if any. +Only present when configured as a global filter. Som Messages include +Throwable as part of the Message. + +|substitutor +|StrSubstitutor +|The StrSubstitutor is used to replace lookup variables. +|=== + +The sample below shows how to declare script fields and then reference them in specific components. +See +xref:manual/appenders.adoc#ScriptCondition[ScriptCondition] for an example of how the `ScriptPlugin` element can be used to embed script code directly in the configuration. + +[source,xml] +---- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +---- [#StructuredDataFilter] -==== `StructuredDataFilter` +=== StructuredDataFilter The `StructuredDataFilter` is a variant of <> that only matches {log4j2-url}/manual/messages.html#StructuredDataMessage[`StructureDataMessage`]s. @@ -1083,7 +1772,7 @@ to modify the ``KeyValuePair``s without restarting your application. xref:plugin-reference.adoc#org-apache-logging-log4j_log4j-core_org-apache-logging-log4j-core-filter-StructuredDataFilter[📖 Plugin reference for `StructuredDataFilter`] [#ThreadContextMapFilter] -==== `ContextMapFilter` +=== ThreadContextMapFilter The `ContextMapFilter` works in the same way as the <> above, except it checks the @@ -1146,13 +1835,8 @@ JSON:: include::example$manual/filters/ContextMapFilter.json[tag=filter] ---- -YAML:: -+ -.Snippet from an example {antora-examples-url}/manual/filters/ContextMapFilter.yaml[`log4j2.yaml`] -[source,yaml,indent=0] ----- -include::example$manual/filters/ContextMapFilter.yaml[tag=filter] ----- +[#ThresholdFilter] +=== ThresholdFilter Properties:: + @@ -1356,7 +2040,34 @@ Some logging calls include the `Throwable` as part of `message`. For the remaining filters, only these bindings are available: -.Script Bindings -- internal filter +[source,xml] +---- + + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + +---- + +[#TimeFilter] +=== TimeFilter + +The time filter can be used to restrict the filter to only a certain portion of the day. + +.Time Filter Parameters [cols="1m,1,4"] |=== | Binding name | Type | Description @@ -1383,90 +2094,6 @@ you can use a simple Groovy script: include::example$manual/filters/local.groovy[lines=17..-1] ---- -You can then integrate the script in a Log4j configuration: - -[tabs] -==== -XML:: -+ -.Snippet from an example {antora-examples-url}/manual/filters/ScriptFilter.xml[`log4j2.xml`] -[source,xml,indent=0] ----- -include::example$manual/filters/ScriptFilter.xml[tag=local] ----- - -JSON:: -+ -.Snippet from an example {antora-examples-url}/manual/filters/ScriptFilter.json[`log4j2.json`] -[source,json,indent=0] ----- -include::example$manual/filters/ScriptFilter.json[tag=local] ----- - -YAML:: -+ -.Snippet from an example {antora-examples-url}/manual/filters/ScriptFilter.yaml[`log4j2.yaml`] -[source,yaml,indent=0] ----- -include::example$manual/filters/ScriptFilter.yaml[tag=local] ----- - -Properties:: -+ -.Snippet from an example {antora-examples-url}/manual/filters/ScriptFilter.yaml[`log4j2.properties`] -[source,properties,indent=0] ----- -include::example$manual/filters/ScriptFilter.properties[tag=local] ----- -==== - -Writing an equivalent **global** script is a little bit more complex, -since you need to take into account all the places where a throwable can be passed as a parameter. -The script becomes: - -.`scripts/global.groovy` -[source,groovy] ----- -include::example$manual/filters/global.groovy[lines=17..-1] ----- - -You can use it as a global filter: - -[tabs] -==== -XML:: -+ -.Snippet from an example {antora-examples-url}/manual/filters/ScriptFilter.xml[`log4j2.xml`] -[source,xml,indent=0] ----- -include::example$manual/filters/ScriptFilter.xml[tag=global] ----- - -JSON:: -+ -.Snippet from an example {antora-examples-url}/manual/filters/ScriptFilter.json[`log4j2.json`] -[source,json,indent=0] ----- -include::example$manual/filters/ScriptFilter.json[tag=global] ----- - -YAML:: -+ -.Snippet from an example {antora-examples-url}/manual/filters/ScriptFilter.yaml[`log4j2.yaml`] -[source,yaml,indent=0] ----- -include::example$manual/filters/ScriptFilter.yaml[tag=global] ----- - -Properties:: -+ -.Snippet from an example {antora-examples-url}/manual/filters/ScriptFilter.yaml[`log4j2.properties`] -[source,properties,indent=0] ----- -include::example$manual/filters/ScriptFilter.properties[tag=global] ----- -==== - [#extending] == Extending @@ -1487,18 +2114,13 @@ include::partial$manual/plugin-preliminaries.adoc[] [#extending-filters] === Extending filters -Filters are xref:manual/plugins.adoc[plugins] -implementing link:../javadoc/log4j-core/org/apache/logging/log4j/core/Filter.html[the `Filter` -interface]. -We recommend users -to extend from link:../javadoc/log4j-core/org/apache/logging/log4j/core/filter/AbstractFilter.html[`AbstractFilter`], -which provides implementation convenience. -While annotating your filter with `@Plugin`, you need to make sure that +Filter are xref:manual/plugins.adoc[plugins] implementing link:../javadoc/log4j-core/org/apache/logging/log4j/core/Filter.html[the `Filter` interface]. +We recommend users to extend from link:../javadoc/log4j-core/org/apache/logging/log4j/core/filter/AbstractFilter.html[`AbstractFilter`], which provides implementation convenience. +While annotating your filter with `@Plugin` and `@Configurable`, you need to make sure that -* It has a unique `name` attribute across all available `Filter` plugins -* The `category` attribute is set to link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/Node.html#CATEGORY[`Node.CATEGORY`] +* The plugin name in `@Plugin::value` or the simple class name of the plugin if no custom name is given must be unique across all available `Filter` plugins. -You can check out the following files for examples: +You can check out following files for examples: * {project-github-url}/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MarkerFilter.java[`MarkerFilter.java`] – <> matching on markers associated with the effective `LogEvent` in the context * {project-github-url}/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java[`RegexFilter.java`] – <> matching on the message associated with the effective `LogEvent` in the context diff --git a/src/site/antora/modules/ROOT/pages/manual/garbagefree.adoc b/src/site/antora/modules/ROOT/pages/manual/garbagefree.adoc index 2a513be60a4..4d48eeb6fdb 100644 --- a/src/site/antora/modules/ROOT/pages/manual/garbagefree.adoc +++ b/src/site/antora/modules/ROOT/pages/manual/garbagefree.adoc @@ -57,7 +57,7 @@ If not for yours, keep on reading. In order to have a garbage-free Log4j Core, you need to * <>, -* and employ garbage-free <>, <>, and <>. +* and employ garbage-free <>, <>, and <>. [#core-properties] === Properties diff --git a/src/site/antora/modules/ROOT/pages/manual/layouts.adoc b/src/site/antora/modules/ROOT/pages/manual/layouts.adoc index 81ca4e3fb7b..2c43b44dd27 100644 --- a/src/site/antora/modules/ROOT/pages/manual/layouts.adoc +++ b/src/site/antora/modules/ROOT/pages/manual/layouts.adoc @@ -18,6 +18,8 @@ = Layouts An xref:manual/appenders.adoc[appender] uses a *layout* to encode a link:../javadoc/log4j-core/org/apache/logging/log4j/core/LogEvent.html[`LogEvent`] into a form that meets the needs of whatever will be consuming the log event. +Layouts can encode this data into a `String`, a `byte[]`, or to a `ByteBufferDestination`. +Layouts used to support encoding data into an arbitrary `java.io.Serializable` classes in Log4j 2.x, but due to security concerns, this is no longer directly supported by layouts in Log4j 3.0. This page will try to answer following questions: * <> @@ -554,7 +556,11 @@ include::partial$manual/plugin-preliminaries.adoc[] === Extending layouts Layouts are xref:manual/plugins.adoc[plugins] implementing link:../javadoc/log4j-core/org/apache/logging/log4j/core/Layout.html[the `Layout` interface]. -If your layout is a `String`-based one, we recommend you to extend your plugin class from link:../javadoc/log4j-core/org/apache/logging/log4j/core/layout/AbstractStringLayout.html[`AbstractStringLayout`], which contains convenience for some of the boilerplate code shared by `String`-based layouts. +It is recommended you extend from link:../javadoc/log4j-core/org/apache/logging/log4j/core/layout/AbstractStringLayout.html[`AbstractStringLayout`]. +While annotating your layout with `@Plugin` and `@Configurable`, you need to make sure that + +* The plugin name in `@Plugin::value` or the simple class name of the plugin if no custom name is given must be unique across all available `Layout` plugins. + You can check out following files for examples: * {project-github-url}/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/SyslogLayout.java[`SyslogLayout.java`] – simple, single-file, extending from `AbstractStringLayout` diff --git a/src/site/antora/modules/ROOT/pages/manual/lookups.adoc b/src/site/antora/modules/ROOT/pages/manual/lookups.adoc index 889ff6c1e3b..f1f828984cc 100644 --- a/src/site/antora/modules/ROOT/pages/manual/lookups.adoc +++ b/src/site/antora/modules/ROOT/pages/manual/lookups.adoc @@ -275,6 +275,12 @@ Do you want to use the values in Spring Boot's `application.properties` file? Use <> instead. ==== +[#collection] +== Collection + +Log4j bundles several predefined lookups to assist in several common deployment use cases. +Following sections explain all these in detail. + [#ContextMapLookup] === Context Map Lookup @@ -388,9 +394,8 @@ include::partial$components/log4j-docker.adoc[] [#EnvironmentLookup] === Environment Lookup -[cols="1h,4"] -|=== -| Context | _global_ +[id=environment-lookup] +=== [[EnvironmentLookup]] Environment Lookup | Syntax | `env:` @@ -402,6 +407,15 @@ The Environment Lookup retrieves the value of the https://docs.oracle.com/en/java/javase/{java-target-version}/docs/api/java.base/java/lang/System.html#getenv(java.lang.String)[OS environment variable] associated with the key. +[source,xml] +---- + + + %d %p %c{1.} [%t] $${env:USER:-jdoe} %m%n + + +---- + [#EventLookup] === Event Lookup @@ -537,10 +551,8 @@ As an example, to retrieve the value of `java:comp/env/app_name` you can use: $${jndi:app_name} ---- -[NOTE] -==== -Android does not support JNDI. -==== +[#JavaLookup] +=== Java Lookup Additional runtime dependencies are required for using JNDI Lookup: @@ -573,10 +585,140 @@ The Configuration Location Lookup supports two keys: |Returns the location of the folder containing the configuration file as an absolute file path or URI. |=== +For example: + +[source,xml] +---- + + + %d %m%n + + +---- + +[#JndiLookup] +=== JNDI Lookup + +As of Log4j 2.15.1 JNDI operations require that `log4j2.enableJndi=true` be set as a system property or the +corresponding environment variable for this lookup to function. See the +xref:manual/systemproperties.adoc#log4j.jndi.enableLookup[`log4j.jndi.enableLookup`] +system property. + +The JndiLookup allows variables to be retrieved via JNDI. By default the +key will be prefixed with java:comp/env/, however if the key contains a +":" no prefix will be added. + +By default the JNDI Lookup only supports the java, ldap, and ldaps protocols or no protocol. Additional +protocols may be supported by specifying them on the ``log4j2.allowedJndiProtocols`` property. +When using LDAP Java classes that implement the Referenceable interface are not supported for security +reasons. Only the Java primative classes are supported by default as well as any classes specified by the +``log4j2.allowedLdapClasses`` property. When using LDAP only references to the local host name +or ip address are supported along with any hosts or ip addresses listed in the +``log4j2.allowedLdapHosts`` property. + +[source,xml] +---- + + + %d %p %c{1.} [%t] $${jndi:logging/context-name} %m%n + + +---- + +*Java's JNDI module is not available on Android.* + +[#JmxRuntimeInputArgumentsLookup] +=== JVM Input Arguments Lookup (JMX) + +Maps JVM input arguments -- but not _main_ arguments -- using JMX to +acquire the JVM arguments. + +Use the prefix `jvmrunargs` to access JVM arguments. + +See the Javadocs for +https://docs.oracle.com/javase/8/docs/api/java/lang/management/RuntimeMXBean.html#getInputArguments--[`java.lang.management.RuntimeMXBean.getInputArguments()`]. + +*Java's JMX module is not available on Android or on Google App Engine.* + +[#KubernetesLookup] +=== Kubernetes Lookup + +For retrieving attributes using Fabric8's Kubernetes Client, see their https://github.com/fabric8io/kubernetes-client/blob/main/doc/KubernetesLog4j.md[Kubernetes Log4j Lookup]. + +[#Log4jConfigLookup] +== Log4j Configuration Location Lookup + +Log4j configuration properties. The expressions +`${log4j:configLocation}` and `${log4j:configParentLocation}` +respectively provide the absolute path to the log4j configuration file +and its parent folder. + +The example below uses this lookup to place log files in a directory +relative to the log4j configuration file. + +[source,xml] +---- + + + %d %p %c{1.} [%t] %m%n + + +---- + [#LowerLookup] === Lower Lookup -[cols="1h,4"] +The LowerLookup converts the passed in argument to lower case. Presumably the value will be the +result of a nested lookup. + +[source,xml] +---- + + + %d %p %c{1.} [%t] $${lower:${spring:spring.application.name}} %m%n + + +---- + +[#AppMainArgsLookup] +=== Main Arguments Lookup (Application) + +This lookup requires that you manually provide the main arguments of the +application to Log4j: + +[source,java] +---- +import org.apache.logging.log4j.core.lookup.MainMapLookup; +public class Main { + public static void main(String[] args) { + MainMapLookup.setMainArguments(args); + // ... + } +} +---- + +If the main arguments have been set, this lookup allows applications to +retrieve these main argument values from within the logging +configuration. The key that follows the `main:` prefix can either be a +0-based index into the argument list, or a string, where +`${main:myString}` is substituted with the value that follows `myString` +in the main argument list. + +Note: Many applications use leading dashes to identify command arguments. Specifying +`${main:--file}` would result in the lookup failing because it would look for a variable +named "main" with a default value of "-file". To avoid this the ":" separating the Lookup name from the +key must be followed by a backslash as an escape character as in `${main:\--file}`. + +For example, suppose the static void main String[] arguments are: + +[source,text] +---- +--file foo.txt --verbose -x bar +---- + +Then the following substitutions are possible: + +[cols="m,m"] |=== | Context | _global_ @@ -656,15 +798,43 @@ XML:: include::example$manual/lookups/mainArgs.xml[lines=1;18..-1] ---- -JSON:: -+ -[source,json] +[#MapLookup] +=== Map Lookup + +The MapLookup serves several purposes. + +1. Provide the base for Properties declared in the configuration file. +2. Retrieve values from MapMessages in LogEvents. +3. Retrieve values set with +link:../javadoc/log4j-core/org/apache/logging/log4j/core/lookup/MapLookup.html#setMainArguments%28java.lang.String%5B%5D%29[`MapLookup.setMainArguments(String[])`] + +The first item simply means that the MapLookup is used to substitute +properties that are defined in the configuration file. These variables +are specified without a prefix - e.g. `$\{name}`. The second usage allows +a value from the current +{log4j2-url}/javadoc/log4j-api/org/apache/logging/log4j/message/MapMessage.html[`MapMessage`], +if one is part of the current log event, to be substituted. In the +example below the RoutingAppender will use a different +RollingFileAppender for each unique value of the key named "type" in the +MapMessage. Note that when used this way a value for "type" should be +declared in the properties declaration to provide a default value in +case the message is not a MapMessage or the MapMessage does not contain +the key. See the xref:manual/configuration.adoc#property-substitution[Property +Substitution] section of the xref:manual/configuration.adoc[Configuration] +page for information on how to set the default values. + +[source,xml] ---- include::example$manual/lookups/mainArgs.json[] ---- -YAML:: -+ +[#marker-lookup] +=== Marker Lookup + +The marker lookup allows you to use markers in interesting +configurations like a routing appender. Consider the following YAML +configuration and code that logs to different files based on markers: + [source,yaml] ---- include::example$manual/lookups/mainArgs.yaml[lines=17..-1] @@ -752,8 +922,8 @@ See <> for more information. | Syntax | `sd:` -where `` is either one of the <> or any `String` -|=== +[id=system-properties-lookup] +=== [[SystemPropertiesLookup]] System Properties Lookup The Structured Data Lookup is very similar to <> and retrieves the value assigned to the given key in a {log4j2-url}/manual/messages.html#StructuredDataMessage[`StructuredDataMessage`]. @@ -938,63 +1108,6 @@ Using the Web Lookup, you can, for example, place the log file in the applicatio ---- -Additional runtime dependencies are required for using web lookup: - -include::partial$features/servlet-support.adoc[] - -[#third-party] -== Third-party lookups - -[IMPORTANT] -==== -These lookups are provided by **third-party** vendors and are not maintained by the -link:{logging-services-url}[Apache Logging Services] -(Log4j, Log4cxx, Log4net) project. -==== - -[#KubernetesLookup] -=== Kubernetes Lookup - -[cols="1h,4"] -|=== -| Syntax | `k8s:` -| Dependency | {log4j-kubernetes-url}[Log4j Kubernetes of Fabric8] -|=== - -Kubernetes Lookup queries https://kubernetes.io/docs/concepts/overview/kubernetes-api/[the Kubernetes API] to retrieve certain information about the current container and its environment. -Kubernetes Lookup is distributed as a part of Fabric8's Kubernetes Client, refer to {log4j-kubernetes-url}[its website] for details. - -[#SpringBootLookup3] -=== Spring Boot 3 Lookup - -[cols="1h,4"] -|=== -| Syntax | `spring:` -| Dependency | _integrated in Spring Boot 3_ -|=== - -Starting with Spring Boot 3 a `$+{spring:...}+` lookup is available out-of-the-box. -https://docs.spring.io/spring-boot/reference/features/logging.html#features.logging.log4j2-extensions.environment-properties-lookup[Spring Boot documentation] -for more details. - -[#TomcatLookup] -=== Tomcat Lookup - -[cols="1h,4"] -|=== -| Syntax -| -`tomcat:` - -where `key` is one of the -https://oss.copernik.eu/tomcat/3.x/components/log4j-tomcat#TomcatLookup-keys[supported Tomcat Lookup keys] -| Dependency | https://oss.copernik.eu/tomcat/3.x/components/log4j-tomcat#installation[`eu.copernik:log4j-tomcat`] -|=== - -The Tomcat Lookup allows retrieving the names of the currently active Tomcat engine, host and application context. -See -https://oss.copernik.eu/tomcat/3.x/components/log4j-tomcat#TomcatLookup[Copernik.eu Tomcat Lookup documentation] for more details. - [#extending] == Extending @@ -1016,12 +1129,11 @@ include::partial$manual/plugin-preliminaries.adoc[] === Extending lookups Lookups are xref:manual/plugins.adoc[plugins] implementing link:../javadoc/log4j-core/org/apache/logging/log4j/core/lookup/StrLookup.html[the `StrLookup` interface]. -While annotating your lookup with `@Plugin`, you need to make sure that +While annotating your lookup with `@Plugin` and `@Lookup`, you need to make sure that -* It has a unique `name` attribute across all available `StrLookup` plugins -* The `category` attribute is set to link:../javadoc/log4j-core/org/apache/logging/log4j/core/lookup/StrLookup.html#CATEGORY[`StrLookup.CATEGORY`] +* The plugin name in `@Plugin::value` or the simple class name of the plugin if no custom name is given must be unique across all available `StrLookup` plugins. -You can check out the following files for examples: +You can check out following files for examples: * {project-github-url}/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/DateLookup.java[`LowerLookup.java`] – <> lower-cases its input * {project-github-url}/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/EventLookup.java[`EventLookup.java`] – <> extracts specified fields from the effective `LogEvent` in the context diff --git a/src/site/antora/modules/ROOT/pages/manual/pattern-layout.adoc b/src/site/antora/modules/ROOT/pages/manual/pattern-layout.adoc index ee9115a2ed7..79700b1ea17 100644 --- a/src/site/antora/modules/ROOT/pages/manual/pattern-layout.adoc +++ b/src/site/antora/modules/ROOT/pages/manual/pattern-layout.adoc @@ -432,8 +432,7 @@ You can also define custom date formats, see following examples: `%d\{UNIX}` outputs the epoch time in seconds, i.e., the difference in seconds between the current time and 1970-01-01 00:00:00 (UTC). `%d\{UNIX_MILLIS}` outputs the epoch time in milliseconds. -Note that the granularity of the sub-second formatters depends on the platform. -Users may revert to a millisecond-precision clock when running on Java 9 by setting xref:manual/systemproperties.adoc#log4j2.clock[the `log4j2.clock` system property] to `SystemMillisClock`. +Users may revert to a millisecond-precision clock when running on Java 9 by setting xref:manual/systemproperties.adoc#log4j.configuration.clock[the `log4j.configuration.clock` system property] to `SystemMillisClock`. [WARNING] ==== @@ -1545,8 +1544,9 @@ If your terminal supports 24-bit colors, you can specify: [#ansi-windows] ==== ANSI styling on Windows -ANSI escape sequences are supported natively on many platforms, but is disabled by default in `cmd.exe` on Windows. -To enable ANSI escape sequences, create a registry key of name `HKEY_CURRENT_USER\Console\VirtualTerminalLevel` of type `DWORD` and set its value to `0x1`. +ANSI escape sequences are supported natively on many platforms, but not by default on Windows. +To enable ANSI support add the http://jansi.fusesource.org/[Jansi] dependency to your application, and set xref:manual/systemproperties.adoc#log4j.console.jansiEnabled[the `log4j.console.jansiEnabled` system property] to `false`. +This allows Log4j to use Jansi to add ANSI escape codes when writing to the console. See https://devblogs.microsoft.com/commandline/understanding-windows-console-host-settings/[Understanding Windows Console Host Settings] @@ -1565,35 +1565,33 @@ Format modifiers to control such things as field width, padding, left, and right |Pattern |Comment -|xref:#converter-logger[%c\{precision} + -%logger\{precision}] +|<> | -|xref:#converter-date[%d + -%date] -| -The numeric formats (`UNIX` and `UNIX_MILLIS`) are garbage-free. -The remaining formats are low-garbage and only generate temporary objects once per minute. +|<> +|Only the predefined date formats (`DEFAULT`, `ISO8601`, `UNIX`, `UNIX_MILLIS`, etc.) are garbage-free -|xref:#converter-encode[%enc\{pattern} + -%encode\{pattern}] +|<> | -|xref:#converter-equals[%equals\{pattern}\{test}\{substitution} + -%equalsIgnoreCase\{pattern}\{test}\{substitution}] +|<> | |<> |Granted nested pattern is garbage-free -|xref:#converter-map[%K\{key} + +|<> | -|xref:#converter-message[%m + +|<> | |<> @@ -1602,54 +1600,54 @@ The remaining formats are low-garbage and only generate temporary objects once p |<> | -|xref:#converter-max-len[%maxLen + -%maxLength] +|<> | |%n | -|xref:#converter-nano[%N + -%nano] +|<> | -|xref:#converter-not-empty[%notEmpty\{pattern} + +|<> | -|xref:#converter-level[%p + -%level] +|<> | -|xref:#converter-relative[%r + -%relative] +|<> | -|xref:#converter-seq[%sn + -%sequenceNumber] +|<> | |<> | -|xref:#converter-thread-id[%T + +|<> | -|xref:#converter-thread-name[%t + +|<> | |<> | -|<>} + +|<> | |literal text @@ -1735,7 +1733,7 @@ Furthermore, the converter must also specify the `@ConverterKeys` annotation to ==== Unlike most other plugins, **pattern converters do not use a `@PluginFactory`**. Instead, each converter is required to provide a static `newInstance(String[])` factory method. -The `String[]` argument denots the the values that are specified within the curly braces that following the conversion specifier. +The `String[]` argument denotes the values that are specified within the curly braces that following the conversion specifier. ==== Refer to following sources for simple examples: diff --git a/src/site/antora/modules/ROOT/pages/manual/plugins.adoc b/src/site/antora/modules/ROOT/pages/manual/plugins.adoc index 1b9b6768978..dceb09fa9a8 100644 --- a/src/site/antora/modules/ROOT/pages/manual/plugins.adoc +++ b/src/site/antora/modules/ROOT/pages/manual/plugins.adoc @@ -14,78 +14,233 @@ See the License for the specific language governing permissions and limitations under the License. //// + = Plugins -Log4j 1.x allowed for extension by requiring class attributes on most of -the configuration declarations. In the case of some elements, notably -the PatternLayout, the only way to add new pattern converters was to -extend the PatternLayout class and add them via code. One goal of Log4j -2 is to make extending it extremely easy through the use of plugins. - -In Log4j 3.x, a plugin is declared by adding a `@Plugin` and `@Namespace` annotation to the class declaration. -During initialization the -link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/Configuration.html[`Configuration`] -will invoke the `PluginRegistry` -to load the built-in Log4j plugins as well as any custom plugins. The -`Injector` locates plugins by looking in the following places: - -1. Plugin collection classes on the classpath that are loaded by java.util.ServiceLoader. -These classes are generated automatically during the build (more details below). -2. (OSGi only) Serialized plugin listing files in each active OSGi -bundle. A `BundleListener` is added on activation to continue checking -new bundles after `log4j-plugins` has started. Bundles must register their plugin collection -class as an OSGi service. -3. Serialized plugin listing files on the classpath. These files were generated by -the plugin annotation processor in Log4j 2 2.x. These are processed to allow -compatibility. - -When multiple plugins use the same case-insensitive `name` within the same plugin category, then which one is selected is determined first by the presence of `@PluginOrder` annotations and then by the previously described plugin loading order. -For example, to override the `File` plugin which is provided by the built-in `FileAppender` class, you would need to place your plugin in a JAR file in the CLASSPATH ahead of`log4j-core.jar`. -This is not recommended; plugin name collisions will cause a warning to be emitted. -Note that in an OSGi environment, the order that bundles are scanned for plugins generally follows the same order that bundles were installed into the framework. -See https://www.osgi.org/javadoc/r5/core/org/osgi/framework/BundleContext.html#getBundles()[`getBundles()`] and https://www.osgi.org/javadoc/r5/core/org/osgi/framework/SynchronousBundleListener.html[`SynchronousBundleListener`]. -In short, name collisions are even more unpredictable in an OSGi environment without additional `@PluginOrder` usage. - -Plugin collection classes are generated by an annotation processor contained -in the log4j-plugins artifact which will automatically scan your code for -Log4j 2 plugins and generate a Java source file that references all the -located plugins. It will also generate a -META-INF/services/org.apache.logging.log4j.plugins.model.PluginService -file in compliance with java.util.ServiceLoader. -There is nothing extra that needs to be done to enable this; -the Java compiler will automatically pick up the annotation processor on -the class path unless you explicitly disable it. - -If annotation processing is disabled plugins may still be registered by either -[loweralpha] -.. manually providing a class that extends `org.apache.logging.log4j.plugins.model.PluginService` -and identifies all the plugins and also declaring a -`META-INF/services/org.apache.logging.log4j.plugins.model.PluginService` file -that provides the fully qualified name of the implemented class or -.. adding another compiler pass to the build process that -only handles annotation processing using the Log4j 2 annotation -processor class, -`org.apache.logging.log4j.plugin.processor.PluginProcessor`. -To do this using Apache Maven, add the following execution to your -_maven-compiler-plugin_ (version 2.2 or higher) build plugin: - -[source,xml] +Log4j plugin system is the de facto extension mechanism embraced by various Log4j Core components. +Plugins make it possible for extensible components to _receive_ feature implementations without any explicit links in between. +It is analogous to a https://en.wikipedia.org/wiki/Dependency_injection[dependency injection] framework, but curated for xref:manual/dependencyinjection.adoc[Log4j-specific needs]. + +[NOTE] +==== +Log4j plugin system is implemented by Log4j Core, the logging implementation. +It is deliberately not a part of the Log4j API to keep the logging API footprint small. +==== + +[TIP] +==== +Did you know about *xref:plugin-reference.adoc[], the documentation extracted from the source code* of all predefined Log4j plugins? +Like Javadoc, but specialized for plugins! +==== + +In this section we will give an overview of the Log4j plugin system by answering certain questions: + +. <<#declare-plugin,How can you declare a plugin?>> +. <<#core,How can you declare a plugin that needs to be represented in a Log4j configuration file?>> +. <<#plugin-registry,How can you register your plugin to Log4j?>> +. <<#plugin-discovery,How does Log4j discover plugins?>> +. <<#plugin-load,How can you load other plugins in a plugin?>> + +[#declare-plugin] +== Declaring plugins + +A class can be declared as a plugin by adding a link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/Plugin.html[`@Plugin`] annotation and a link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/Configurable.html[`@Configurable`] annotation. + +`@Plugin::value`:: +Name of the plugin. +If left unspecified, this defaults to the simple class name of the annotated class. +This name should be unique within all plugins sharing the same `@Namepsace` (in this case, the `@Configurable` annotation uses the `Core` namespace). +The plugin name is matched using case-insensitive equality. + +`@Namespace::value`:: +Plugins are grouped together in namespaces where they can be identified by name. +Namespaces are case-sensitive. +Typical plugins use the `Core` namespace which is handled by the `@Configurable` annotation. + +`@Configurable::elementType` (deprecated):: +We don't recommend the usage of `elementType` anymore. +Existing usages are kept for backward compatibility reasons with the legacy configuration syntax: `> will determine the effective plugin. +For example, to override the `File` plugin which is provided by the built-in xref:manual/appenders.adoc#FileAppender[File Appender], you would need to place your plugin in a JAR file in the classpath ahead of Log4j Core JAR. +In an OSGi environment, the order that bundles are scanned for plugins generally follows the same order that bundles were installed into the framework; see https://www.osgi.org/javadoc/r5/core/org/osgi/framework/BundleContext.html#getBundles()[`getBundles()`] and https://www.osgi.org/javadoc/r5/core/org/osgi/framework/SynchronousBundleListener.html[`SynchronousBundleListener`]. +In short, name collisions are even more unpredictable in an OSGi environment. +==== + +[#core] +== Declaring plugins represented in a configuration file + +If your plugin needs to be represented by an element in a configuration file (such as an xref:manual/appenders.adoc[appender], xref:manual/layouts.adoc[layout], xref:manual/api.adoc#loggers[logger], or xref:manual/filters.adoc[filter]), following requirements must be met: + +* The `@Namespace` annotation of the `@Plugin`-annotated class must be set to link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/Node.html#CORE_NAMESPACE[`Node.CORE_NAMESPACE`] (`Core`) or it must use the link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/Configurable.html[`@Configurable`] annotation +* It must have a xref:declare-plugin-factory[plugin factory] + +See {project-github-url}/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayout.java[`JsonTemplateLayout.java`] for an example and notice these details: + +* There are two plugin declarations: `JsonTemplateLayout` and `JsonTemplateLayout.EventTemplateAdditionalField` +* Both plugin declarations +** Use a `@Configurable` and `@Plugin` annotation +** Provide a `@Factory`-annotated static method + +[#declare-plugin-factory] +=== Declaring plugin factories + +A *plugin factory* is responsible for + +* Creating an instance of the plugin +* Receiving values (`Configuration` instance, configuration attributes, etc.) available in the context + +Plugin factories are comparable to more general dependency injection frameworks and consist of strategies for binding configuration data to a plugin class instance. +A plugin factory typically consists of a static method in the plugin class annotated with a `@FactoryType`-annotated annotation such as link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/Factory.html[`@Factory`] or `@PluginFactory`. +Alternatively, a plugin can include a link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/Inject.html[`@Inject`]-annotated constructor (along with optional `@Inject`-annotated methods or fields). +This plugin factory executable (constructor or method) may include parameters for binding configuration data or injecting other shared instances as described below. + +If a static method returns an instance that implements `java.util.function.Supplier` (which includes both link:../javadoc.adoc/log4j-plugins/org/apache/logging/log4j/plugins/util/Builder.html[`Builder`] and link:../javadoc/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Builder.java[`Builder`]), then this instance is further processed for dependency injection. +This makes it possible to create a builder class with link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/Inject.html[`@Inject`]-annotated methods whose parameters can be bound to injected data in the same fashion as parameters of the static factory method. + +If a plugin class implements `Collection` or `Map`, then no factory method is used. +Instead, the class is instantiated using the default constructor, and all child configuration nodes are added to the `Collection` or `Map`. + +[#attribute-types] +==== Plugin factory attribute types + +To allow the current `Configuration` to populate the correct arguments for the `@Factory`-annotated method or `@Inject`-annotated constructor or method, every argument to the executable must be annotated using one of the following attribute types. + +link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/PluginAliases.html[`@PluginAliases`]:: +Identifies a list of aliases for a `@Plugin`, `@PluginAttribute`, or `@PluginBuilderAttribute`. +Aliases allow a plugin to be referenced by multiple names in configuration files. +For example, a plugin with `@PluginAliases({"MyApp", "MyApplication"})` can be referred to by any of those names. +Aliases are also supported for plugin attributes, allowing configuration elements to use alternative attribute names. + +link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/PluginAttribute.html[`@PluginAttribute`]:: +Denotes a configuration element attribute. +The parameter must be convertible from a `String` using a `TypeConverter`. +Most built-in types are already supported, but custom `TypeConverter` plugins may also be provided for more type support. +Note that `PluginBuilderAttribute` can be used in builder class fields as an easier way to provide default values. + +link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/plugins/PluginConfiguration.html[`@PluginConfiguration` (optional)]:: +The current `Configuration` object will be passed to the plugin as a parameter. +Note that this annotation is _optional_ as long as the type of the parameter or field is `Configuration`. + +[[PluginElement]] link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/PluginElement.html[`@PluginElement`]:: +The parameter may represent a complex object that itself has parameters that can be configured. +This also supports injecting an array of elements. + +link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/PluginNode.html[`@PluginNode`]:: +The current `Node` being parsed will be passed to the plugin as a parameter. + +link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/PluginValue.html[`@PluginValue`]:: +The value of the current `Node` or its attribute named `value`. +If `@PluginValue::value` is overridden, then the value from the annotation is used as the attribute name to look up a value for. + +Each attribute or element annotation must include the name that must be present in the configuration in order to match the configuration item to its respective parameter if the parameter name (or field name) does not match the expected name. + +[#type-converters] +==== Plugin factory attribute type converters + +link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/convert/TypeConverter.html[`TypeConverter`]s are a certain group of plugins for converting ``String``s read from configuration file elements into the types used in plugin factory attributes. +Other plugins can already be injected via <>; now, any type supported by ``TypeConverter``s can be used in a `@PluginAttribute`-annotated factory attribute. + +Conversion of enum types are supported on demand and do not require custom ``TypeConverter``s. +A large number of built-in Java classes (`int`, `long`, `BigDecimal`, etc.) are already supported; see link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/plugins/convert/CoreTypeConverters.html[`CoreTypeConverters`] for a more exhaustive listing. +Note that type converters for primitive types and their respective boxed types are handled by anonymous type converters in {project-github-url}/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverterFactory.java[`TypeConverterFactory`]. + +You can create custom ``TypeConverter``s as follows: + +* Extend from link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/convert/TypeConverter.html[the `TypeConverter` interface] + +* Add a link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/Plugin.html[`@Plugin`] and link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/convert/TypeConverters.html[`@TypeConverters`] annotation to the class (which is an alias for the `TypeConverter` namespace). + +* Have a default constructor + +* Optionally, extend from `Comparable>`, which will be used for determining the order in case of multiple `TypeConverter` candidates for a certain type + +See {project-github-url}/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/CoreTypeConverters.java[`CoreTypeConverters.java`] for example implementations. + +[#constraint-validators] +==== Plugin factory attribute validators + +Plugin factory fields and parameters can be automatically validated at runtime using constraint validators inspired by https://beanvalidation.org[Bean Validation]. +The following annotations are bundled in Log4j, but custom ``ConstraintValidator`` can be created as well. + +link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/validation/constraints/Required.html[`@Required`]:: +This annotation validates that a value is non-empty. +This covers a check for null as well as several other scenarios: empty `CharSequence` objects, empty arrays, empty `Collection` instances, and empty `Map` instances. + +link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/validation/constraints/RequiredClass.html[`@RequiredClass`]:: +This annotation validates that a class can be loaded by name. +This can be used on a plugin class to avoid loading the plugin unless the required class is present. + +link:../javadoc/log4j-core/org/apache/logging/log4j/plugins/validation/constraints/ValidHost.html[`@ValidHost`]:: +This annotation validates that a value corresponds to a valid host name. +This uses the same validation as https://docs.oracle.com/javase/{java-target-version}/docs/api/java/net/InetAddress.html#getByName-java.lang.String-[`InetAddress.getByName(String)`]. + +link:../javadoc/log4j-core/org/apache/logging/log4j/plugins/validation/constraints/ValidPort.html[`@ValidPort`]:: +This annotation validates that a value corresponds to a valid port number between 0 and 65535. + +[#conditional-annotations] +==== Plugin factory conditional annotations + +Conditional annotations allow plugins to be registered only when certain conditions are met. +They are typically used on bundle classes or factory methods to control whether bindings should be created based on the runtime environment. + +The following built-in conditional annotations are available: + +link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/condition/ConditionalOnMissingBinding.html[`@ConditionalOnMissingBinding`]:: +Checks if a binding exists for the return type of the annotated factory method. +When no binding exists for that key, the method will be considered for binding. +This is commonly used to provide default implementations that can be overridden by user-defined plugins. + +link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/condition/ConditionalOnPresentBindings.html[`@ConditionalOnPresentBindings`]:: +Only creates a binding if all the requested dependencies exist. +The required dependencies are specified via the `bindings` attribute. +This is useful for plugins that require optional dependencies to be present on the classpath. + +Custom conditions can be created by implementing the `Condition` interface and annotating a custom annotation with `@Conditional`. + +[#plugin-registry] +== Registering plugins + +Registering plugins are done by placing a *Log4j plugin class* (i.e., a generated `Log4jPlugins.java` extending link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/model/PluginService.html[`PluginService`]) into the classpath. +This class is generated using the link:../javadoc/log4j-plugin-processor/org/apache/logging/log4j/plugin/processor/PluginProcessor.html[`PluginProcessor`] annotation processor at compile-time. +You need to configure your build tool as follows to employ `PluginProcessor` by the Java compiler: + +[tabs] +==== +Maven:: ++ +[source,xml,subs="+attributes"] ---- org.apache.maven.plugins maven-compiler-plugin - 3.1 + ${maven-compiler-plugin.version} - log4j-plugin-processor + generate-log4j-plugin-descriptor compile process-classes only + + + + org.apache.logging.log4j + log4j-plugin-processor + {log4j-core-version} + + - org.apache.logging.log4j.plugin.processor.PluginProcessor + + org.apache.logging.log4j.plugin.processor.PluginProcessor @@ -93,166 +248,33 @@ _maven-compiler-plugin_ (version 2.2 or higher) build plugin: ---- -As the configuration is processed the appropriate plugins will be -automatically configured and initialized. - -Log4j 3 utilizes a few different namespaces of plugins which are described in the following sections. - -[#Core] -== Core - -Core plugins are those that are directly represented by an element in a -configuration file and correspond to `@Configurable` namespaced `@Plugin` classes such as an `Appender`, `Layout`, `Logger` or `Filter`. -Custom plugins that conform to the rules laid out in the next paragraph may simply be referenced in the configuration. - -Core plugins support a few different dependency injection rules for binding configuration node data and other injectable classes into a plugin instance. -Each plugin must declare a static method annotated with `@Factory` or `@PluginFactory` or contain an `@Inject`-annotated constructor or no-args constructor. -These static factory method or `@Inject` constructor parameters are used for initial dependency injection. -When a static factory method returns a type that implements `java.util.function.Supplier` such as through `Builder`, then that supplier instance first has its members injected before invoking `Supplier::get` to obtain the resulting plugin instance. -See xref:manual/dependencyinjection.adoc[Dependency Injection] for further details on how dependency injection works. -Plugins are configured using additional plugin qualifier annotations such as `@PluginAttribute`, `@PluginBuilderAttribute`, `@PluginElement`, `@PluginValue`, etc., as described below. - -There are dozens of plugins in Log4j Core that can be -used as examples for more complex scenarios including hierarchical -builder classes (e.g., see `FileAppender`). See -link:extending.html#Plugin_Builders[Extending Log4j with Plugin -Builders] for more details. - -=== Attribute Types - -`PluginAttribute`:: - The parameter must be convertible from a String using a - link:#TypeConverters[TypeConverter]. Most built-in types are already - supported, but custom `TypeConverter` plugins may also be provided for - more type support. Note that `PluginBuilderAttribute` can be used in - builder class fields as an easier way to provide default values. -`PluginElement`:: - The parameter may represent a complex object that itself has - parameters that can be configured. This also supports injecting an - array of elements. -link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/plugins/PluginConfiguration.html[`PluginConfiguration`]:: - The current `Configuration` object will be passed to the plugin as a - parameter. -`PluginNode`:: - The current `Node` being parsed will be passed to the plugin as a - parameter. -`PluginValue`:: - The value of the current `Node` or its attribute named `value`. - -=== Constraint Validators - -Plugin factory fields, methods, and parameters can be automatically validated at -runtime using constraint validators inspired by the -http://beanvalidation.org/[Bean Validation spec]. The following -annotations are bundled in Log4j, but custom -`ConstraintValidators` -can be created as well. - -`Required`:: - This annotation validates that a value is non-empty. This covers a - check for `null` as well as several other scenarios: empty - `CharSequence` objects, empty arrays, empty `Collection` instances, - and empty `Map` instances. -`RequiredClass`:: - This annotation validates that a class name can be loaded. This is useful for plugins that should only be loaded when an optional class is present. -`ValidHost`:: - This annotation validates that a value corresponds to a valid - hostname. This uses the same validation as - https://docs.oracle.com/en/java/javase/{java-target-version}/docs/api/java.base/java/net/InetAddress.html#getByName(java.lang.String)[`InetAddress::getByName`]. -`ValidPort`:: - This annotation validates that a value corresponds to a valid port - number between 0 and 65535. - -[#Converters] -== Converters - -Converters are used by xref:manual/layouts.adoc#PatternLayout[`PatternLayout`] -to render the elements identified by the conversion pattern. Every -converter must specify its category as "Converter" on the `@Plugin` -annotation, have a static `newInstance` method that accepts an array of -`String` as its only parameter and returns an instance of the -Converter, and must have a `@ConverterKeys` annotation present that -contains the array of converter patterns that will cause the Converter -to be selected. Converters that are meant to handle `LogEvent` must -extend the -link:../javadoc/log4j-core/org/apache/logging/log4j/core/layout/LogEventPatternConverter.html[`LogEventPatternConverter`] -class and must implement a format method that accepts a `LogEvent` and a -`StringBuilder` as arguments. The Converter should append the result of -its operation to the `StringBuilder`. - -A second type of Converter is the FileConverter - which must have -"FileConverter" specified in the category attribute of the `@Plugin` -annotation. While similar to a `LogEventPatternConverter`, instead of a -single format method these Converters will have two variations; one that -takes an `Object` and one that takes an array of `Object` instead of -the `LogEvent`. Both append to the provided `StringBuilder` in the same -fashion as a `LogEventPatternConverter`. These Converters are typically -used by the `RollingFileAppender` to construct the name of the file to -log to. - -If multiple Converters specify the same `ConverterKeys`, then the load -order above determines which one will be used. For example, to override -the `%date` converter which is provided by the built-in -`DatePatternConverter` class, you would need to place your plugin in a -JAR file in the CLASSPATH ahead of `log4j-core.jar`. This is not -recommended; pattern ConverterKeys collisions will cause a warning to be -emitted. Try to use unique ConverterKeys for your custom pattern -converters. - -[#KeyProviders] -== KeyProviders - -Some components within Log4j may provide the ability to perform data -encryption. These components require a secret key to perform the -encryption. Applications may provide the key by creating a class that -implements the -link:../javadoc/log4j-core/org/apache/logging/log4j/core/util/SecretKeyProvider.html[`SecretKeyProvider`] -interface. - -[#Lookups] -== Lookups - -Lookups are perhaps the simplest plugins of all. They must declare their -type as "Lookup" on the plugin annotation and must implement the -link:../javadoc/log4j-core/org/apache/logging/log4j/core/lookup/StrLookup.html[`StrLookup`] -interface. They will have two methods; a `lookup` method that accepts a -`String` key and returns a `String` value and a second `lookup` method that -accepts both a `LogEvent` and a `String` key and returns a `String`. Lookups -may be referenced by specifying $\{name:key} where name is the name -specified in the Plugin annotation and key is the name of the item to -locate. - -[#TypeConverters] -== TypeConverters - -``TypeConverter``s -are a sort of meta-plugin used for converting strings into other types -in a plugin factory method parameter. Other plugins can already be -injected via the `@PluginElement` annotation; now, any type supported by -the type conversion system can be used in a `@PluginAttribute` -parameter. Conversion of enum types are supported on demand and do not -require custom `TypeConverter` classes. A large number of built-in Java -classes are already supported; see -`TypeConverters` -and -link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/plugins/convert/CoreConverters.html[`CoreConverters`] -for a more exhaustive listing. - -Unlike other plugins, the plugin name of a `TypeConverter` is purely -cosmetic. Appropriate type converters are looked up via the `Type` -interface rather than via `Class` objects only. Do note that -`TypeConverter` plugins must have a default constructor. - -When multiple converters match for a type, the first will be returned. -If any extends from `Comparable>`, it will be used for determining the order. - -[#DeveloperNotes] -== Developer Notes - -If a plugin class implements -https://docs.oracle.com/en/java/javase/{java-target-version}/docs/api/java.base/java/util/Collection.html[`Collection`] -or -https://docs.oracle.com/en/java/javase/{java-target-version}/docs/api/java.base/java/util/Map.html[`Map`], -then no factory method is used. Instead, the class is instantiated using -the default constructor, and all child configuration nodes are added to -the `Collection` or `Map`. +Gradle:: ++ +[source,groovy,subs="+attributes"] +---- +dependencies { + // Process sources using `log4j-plugin-processor` providing `org.apache.logging.log4j.plugin.processor.PluginProcessor` that generates `Log4jPlugins.java` --> + annotationProcessor('org.apache.logging.log4j:log4j-plugin-processor:{log4j-core-version}') +} +---- +==== + +[#plugin-discovery] +== Discovering plugins + +link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/model/PluginRegistry.html[`PluginRegistry`] is responsible for discovering plugins and loading their descriptions. + +* When using a module path, these plugin services must be included in the `module-info.java` file via a `provides org.apache.logging.log4j.plugins.model.PluginService with org.example.plugins.Log4jPlugins` line. + +* When using a classpath, these plugin services must be included in a `META-INF/services/org.apache.logging.log4j.plugins.model.PluginService` file (which is automatically generated by the plugin annotation processor). + +See <> for details. + +[#plugin-load] +== Loading plugins + +It is pretty common that a plugin uses other plugins; appenders accept layouts, some layouts accept key-value pairs, etc. +You can do this as follows: + +* If your plugin has a <<#declare-plugin-factory,plugin factory>> (i.e., it is represented by a configuration file element), you can use <<#PluginElement, the `@PluginElement` annotation>> to receive other plugins. +See `@PluginElement("EventTemplateAdditionalField")` usage in {project-github-url}/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayout.java[`JsonTemplateLayout.java`] for an example. diff --git a/src/site/antora/modules/ROOT/pages/migrate-from-logback.adoc b/src/site/antora/modules/ROOT/pages/migrate-from-logback.adoc index 15ad73eff0d..757008f4a09 100644 --- a/src/site/antora/modules/ROOT/pages/migrate-from-logback.adoc +++ b/src/site/antora/modules/ROOT/pages/migrate-from-logback.adoc @@ -164,7 +164,5 @@ java.lang.RuntimeException: Message As a temporary solution, the SLF4J-to-Log4j API bridges contain a special {log4j2-url}/manual/api.html#logger-message-factories[`MessageFactory`] that classifies trailing `Throwable` arguments in the same way Logback does. -To use it, you need to set the -{log4j2-url}/manual/systemproperties.html#log4j2.messageFactory[`log4j2.messageFactory`] -configuration property to `org.apache.logging.slf4j.message.ThrowableConsumingMessageFactory`. +To use it, you need to set the xref:manual/systemproperties.adoc#log4j.message.factory[`log4j.message.factory`] configuration property to `org.apache.logging.slf4j.message.ThrowableConsumingMessageFactory`. ==== diff --git a/src/site/antora/modules/ROOT/pages/thanks.adoc b/src/site/antora/modules/ROOT/pages/thanks.adoc deleted file mode 100644 index d4d59566397..00000000000 --- a/src/site/antora/modules/ROOT/pages/thanks.adoc +++ /dev/null @@ -1,52 +0,0 @@ -//// - Licensed to the Apache Software Foundation (ASF) under one or more - contributor license agreements. See the NOTICE file distributed with - this work for additional information regarding copyright ownership. - The ASF licenses this file to You under the Apache License, Version 2.0 - (the "License"); you may not use this file except in compliance with - the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -//// -= Project Thanks - -Log4j 2 is a successful project because of the large and diverse -community that contributes to it. - -There are a handful of tools that developers in the community use; some -are open-source and some are commercial. We'd like to extend a special -thanks to these communities/companies: - -|=== -|Who |What - -|image:YourKitLogo.png["YourKit", link="https://www.yourkit.com/features/"] -|YourKit supports the Log4j 2 project with its full-featured Java Profiler. -YourKit, LLC is the creator of innovative and intelligent tools for profiling Java and .NET applications. -See https://www.yourkit.com/features/[YourKit's leading software products]. - -|image:IntelliJ-IDEA-logo.png["IntelliJ IDEA", link="https://www.jetbrains.com/idea/"] -|JetBrains supports the Log4j 2 project with https://www.jetbrains.com/idea/[IntelliJ IDEA]. - -|image:https://www.jclarity.com/wp-content/uploads/2015/02/JClarity_logo_tagline3.png["jClarity", link="https://www.jclarity.com/"] -|jClarity supports the Log4j 2 project with its https://www.jclarity.com/censum/[Censum] GC log parsing tool. - -|image:https://www.apache.org/images/feather-small.gif["Apache Feather Logo", link="https://www.apache.org/foundation/thanks.html"] -|All of the Platinum/Gold/Silver/Bronze sponsors of the ASF. -|=== - -== Individual Donations to the Apache Software Foundation - -The Apache Software Foundation receives many smaller donations from -individuals via our PayPal and Amazon Payments services (details -https://www.apache.org/foundation/contributing.html[here]). - -We would like to thank all of our individual donors for their support of -our work, and for their willingness to contribute with only this as -recognition for their generosity. diff --git a/src/site/antora/modules/ROOT/partials/configuration-file-format-deps.adoc b/src/site/antora/modules/ROOT/partials/configuration-file-format-deps.adoc index 35fc63b20a5..94406933432 100644 --- a/src/site/antora/modules/ROOT/partials/configuration-file-format-deps.adoc +++ b/src/site/antora/modules/ROOT/partials/configuration-file-format-deps.adoc @@ -18,28 +18,67 @@ [tabs] ===== -log4j2.xml:: +XML:: + -- include::partial$features/config-xml.adoc[] -- -log4j2.json:: +JSON:: + -- include::partial$features/config-json.adoc[] -- -log4j2.yaml:: +YAML:: + -- include::partial$features/config-yaml.adoc[] -- -log4j2.properties:: +Properties:: + -- include::partial$features/config-properties.adoc[] -- ===== + +Gradle:: ++ +[tabs] +===== + +XML:: ++ +JPMS users need to add: ++ +[source,java] +---- +module foo.bar { + requires java.xml; +} +---- ++ +to their `module-info.java` descriptor. + +JSON:: ++ +No dependency required. + +YAML:: ++ +[source,groovy] +---- +runtimeOnly 'org.apache.logging.log4j:log4j-config-yaml' +---- + +Properties:: ++ +[source,groovy] +---- +runtimeOnly 'org.apache.logging.log4j:log4j-config-properties' +---- + +===== +==== diff --git a/src/site/antora/modules/ROOT/partials/manual/composite-configuration.adoc b/src/site/antora/modules/ROOT/partials/manual/composite-configuration.adoc new file mode 100644 index 00000000000..39392abd951 --- /dev/null +++ b/src/site/antora/modules/ROOT/partials/manual/composite-configuration.adoc @@ -0,0 +1,50 @@ +//// + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +//// + +// tag::intro[] +There are occasions where multiple configurations might need to be combined. +For instance, + +* You have a common Log4j Core configuration that should always be present, and an environment-specific one that extends the common one depending on the environment (test, production, etc.) the application is running on. +* You develop a framework, and it contains a predefined Log4j Core configuration. +Yet you want to allow users to extend it whenever necessary. +* You collect Log4j Core configurations from multiple sources. +// end::intro[] + +// tag::how[] +`CompositeConfiguration` merges multiple configurations into a single one using a link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/composite/MergeStrategy.html[`MergeStrategy`], which can be customized using xref:manual/systemproperties.adoc#log4j.configuration.mergeStrategy[the `log4j.configuration.mergeStrategy` configuration property]. +The default merge strategy works as follows: + +* xref:manual/configuration.adoc#global-configuration-attributes[Global configuration attributes] in later configurations replace those in previous configurations. +The only exception is the `monitorInterval` attribute: the lowest positive value from all the configuration files will be used. + +* xref:manual/configuration.adoc#property-substitution[Properties] are aggregated. +Duplicate properties override those in previous configurations. + +* xref:manual/filters.adoc[Filters] are aggregated under xref:manual/filters.adoc#CompositeFilter[`CompositeFilter`], if more than one filter is defined. + +* xref:manual/scripts.adoc[] are aggregated. +Duplicate definitions override those in previous configurations. + +* xref:manual/appenders.adoc[Appenders] are aggregated. +Appenders with the same name are **overridden** by those in later configurations, including all their elements. + +* xref:manual/configuration.adoc#configuring-loggers[Loggers] are aggregated. +Logger attributes are individually merged, and those in later configurations replace duplicates. +Appender references on a logger are aggregated, and those in later configurations replace duplicates. +The strategy merges filters on loggers using the rule above. +// end::how[] diff --git a/src/site/antora/modules/ROOT/partials/manual/plugin-preliminaries.adoc b/src/site/antora/modules/ROOT/partials/manual/plugin-preliminaries.adoc index ce00948b590..a4b99344e09 100644 --- a/src/site/antora/modules/ROOT/partials/manual/plugin-preliminaries.adoc +++ b/src/site/antora/modules/ROOT/partials/manual/plugin-preliminaries.adoc @@ -16,10 +16,10 @@ //// Log4j plugin system is the de facto extension mechanism embraced by various Log4j components. -Plugins make it possible for extensible components to _receive_ feature implementations without any explicit links in between. +Plugins provide extension points to components, that can be used to implement new features, without modifying the original component. It is analogous to a https://en.wikipedia.org/wiki/Dependency_injection[dependency injection] framework, but curated for Log4j-specific needs. -In a nutshell, you annotate your classes with link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/plugins/Plugin.html[`@Plugin`] and their (`static`) factory methods with link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/plugins/PluginFactory.html[`@PluginFactory`]. +In a nutshell, you annotate your classes with link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/Plugin.html[`@Plugin`] and their (`static`) factory methods with link:../javadoc/log4j-plugins/org/apache/logging/log4j/plugins/Factory.html[`@Factory`]. Last, you inform the Log4j plugin system to discover these custom classes. -This is done using running the link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessor.html[`PluginProcessor`] annotation processor while building your project. +This is done using running the link:../javadoc/log4j-plugin-processor/org/apache/logging/log4j/plugin/processor/PluginProcessor.html[`PluginProcessor`] annotation processor while building your project. Refer to xref:manual/plugins.adoc[] for details.