ppkarwasz commented on code in PR #2604: URL: https://github.com/apache/logging-log4j2/pull/2604#discussion_r1610040517
########## src/site/antora/modules/ROOT/partials/manual/api-intro.adoc: ########## @@ -0,0 +1,72 @@ +//// + 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. +//// + +To write logs, you need a `Logger` instance which you will retrieve from the `LogManager`. +You can use the `Logger` instance to write logs by using methods like `info()`, `warn()`, `error()`, etc. +These methods are named after the _log levels_ they represent, a way to categorize log events by severity. +The log message can also contain placeholders written as `{}` that will be replaced by the arguments passed to the method. Review Comment: Maybe: > The **log message** can also be specified by providing a format string containing `{}` placeholders and an array of arguments. Users use **log message** and **log event** interchangeably. It would be nice to explain at the beginning that: * a "log message" is something the user provides explicitly, * a "log event" is the message enriched with all sorts of meta-data. ########## src/site/antora/modules/ROOT/partials/manual/api-intro.adoc: ########## @@ -0,0 +1,72 @@ +//// + 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. +//// + +To write logs, you need a `Logger` instance which you will retrieve from the `LogManager`. Review Comment: I would expect a link to the Javadoc on the first `Logger` and `LogManager` occurrence. ########## src/site/antora/modules/ROOT/partials/manual/api-best-practice-dont-use-toString.adoc: ########## @@ -0,0 +1,30 @@ +//// + 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. +//// + +* [ ] Don't use `Object#toString()` in arguments, it is redundant! Review Comment: ```suggestion * [ ] Don't use `Object.toString()` in arguments, it is redundant! ``` I think you made this correction in one of my PRs, so we need to be coherent. ########## src/site/antora/modules/ROOT/partials/manual/api-best-practice-exception-as-last-argument.adoc: ########## @@ -0,0 +1,30 @@ +//// + 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. +//// + +* [ ] Don't use `Object#toString()` in arguments, it is redundant! ++ +[source,java] +---- +/* BAD! */ LOGGER.info("userId: {}", userId.toString()); +---- + +* [x] Underlying message type and layout will deal with arguments: ++ +[source,java] +---- +/* GOOD */ LOGGER.info("userId: {}", userId); +---- Review Comment: This is a copy/paste of `api-best-practice-dont-use-toString.adoc` ########## src/site/antora/modules/ROOT/pages/manual/api.adoc: ########## @@ -14,187 +14,323 @@ See the License for the specific language governing permissions and limitations under the License. //// + +:jboss-logging-link: https://github.com/jboss-logging/jboss-logging[JBoss Logging] +:jcl-link: https://commons.apache.org/proper/commons-logging/[JCL (Apache Commons Logging)] +:jpl-link: https://openjdk.org/jeps/264[JPL (Java Platform Logging)] +:jul-link: https://docs.oracle.com/en/java/javase/{java-target-version}/core/java-logging-overview.html[JUL (Java Logging)] +:logback-link: https://logback.qos.ch/[Logback] +:slf4j-link: https://www.slf4j.org/[SLF4J] + = Log4j API -== Overview +Log4j is essentially composed of a logging API called *Log4j API*, and its reference implementation called *Log4j Core*. -The Log4j 2 API provides the interface that applications should code to -and provides the adapter components required for implementers to create -a logging implementation. Although Log4j 2 is broken up between an API -and an implementation, the primary purpose of doing so was not to allow -multiple implementations, although that is certainly possible, but to -clearly define what classes and methods are safe to use in "normal" -application code. +.What is a logging API and a logging implementation? +[%collapsible] +==== +Logging APIs:: +A logging API is an interface your code or your dependencies directly logs against. +It is implementation agnostic. +Log4j API, {slf4j-link}, {jul-link}, {jcl-link}, {jpl-link} and {jboss-logging-link} are major logging APIs. -=== Hello World! +Logging implementation:: +A logging implementation is only required at runtime and can be changed without the need to recompile your software. +Log4j Core, {jul-link}, {logback-link} are the most well-known logging implementations. +==== -No introduction would be complete without the customary Hello, World -example. Here is ours. First, a Logger with the name "HelloWorld" is -obtained from the -link:../javadoc/log4j-api/org/apache/logging/log4j/LogManager.html[`LogManager`]. -Next, the logger is used to write the "Hello, World!" message, however -the message will be written only if the Logger is configured to allow -informational messages. +[TIP] +==== +Are you looking for a crash course on how to use Log4j in your application or library? +See xref:5min.adoc[]. +You can also check out xref:manual/installation.adoc[] for the complete installation instructions. +==== -[source,java] ----- -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +Log4j API provides -public class HelloWorld { - private static final Logger logger = LogManager.getLogger("HelloWorld"); - public static void main(String[] args) { - logger.info("Hello, World!"); - } -} ----- +* A logging API that libraries and applications can code to +* Adapter components to create a logging implementation -The output from the call to `logger.info()` will vary significantly -depending on the configuration used. See the -xref:manual/configuration.adoc[Configuration] section for more details. +This page tries to cover the most prominent Log4j API features that libraries and applications can code to. -=== Substituting Parameters +== Introduction -Frequently the purpose of logging is to provide information about what -is happening in the system, which requires including information about -the objects being manipulated. In Log4j 1.x this could be accomplished -by doing: +include::partial$manual/api-intro.adoc[leveloffset=+1] -[source,java] ----- -if (logger.isDebugEnabled()) { - logger.debug("Logging in user " + user.getName() + " with birthday " + user.getBirthdayCalendar()); -} ----- +[#best-practice] +== Best practices + +There are several widespread bad practices while using Log4j API. +Let's try to walk through the most common ones and see how to fix them. + +[#best-practice-toString] +=== Don't use `toString()` + +include::partial$manual/api-best-practice-dont-use-toString.adoc[] + +[#best-practice-exception] +=== Pass exception as the last extra argument + +include::partial$manual/api-best-practice-exception-as-last-argument.adoc[] + +[#best-practice-concat] +=== Don't use string concatenation + +include::partial$manual/api-best-practice-dont-use-string-concat.adoc[] + +[#best-practice-supplier] +=== Use ``Supplier``s to pass computationally expensive arguments + +include::partial$manual/api-best-practice-use-supplier.adoc[] + +[#loggers] +== Loggers -Doing this repeatedly has the effect of making the code feel like it is -more about logging than the actual task at hand. In addition, it results -in the logging level being checked twice; once on the call to -isDebugEnabled and once on the debug method. A better alternative would -be: +link:../javadoc/log4j-api/org/apache/logging/log4j/Logger.html[`Logger`]s obtained using link:../javadoc/log4j-api/org/apache/logging/log4j/LogManager.html[`LogManager`] is the primary entry point for logging. +In this section we will introduce you to further details about ``Logger``s. + +[#logger-names] +=== Logger names + +Most logging implementations use a hierarchical scheme for matching logger names with logging configuration. +In this scheme, the logger name hierarchy is represented by `.` (dot) characters in the logger name, in a fashion very similar to the hierarchy used for Java package names. +For example, `org.apache.logging.appender` and `org.apache.logging.filter` both have `org.apache.logging` as their parent. + +In most cases, applications name their loggers by passing the current class's name to `LogManager.getLogger(...)`. +Because this usage is so common, Log4j provides that as the default when the logger name parameter is either omitted or is null. +For example, all `Logger`-typed variables below will have a name of `com.mycompany.LoggerNameTest`: [source,java] ---- -logger.debug("Logging in user {} with birthday {}", user.getName(), user.getBirthdayCalendar()); +package com.mycompany; + +public class LoggerNameTest { + + Logger logger1 = LogManager.getLogger(LoggerNameTest.class); + + Logger logger2 = LogManager.getLogger(LoggerNameTest.class.getName()); + + Logger logger3 = LogManager.getLogger(); + +} ---- -With the code above the logging level will only be checked once and the -String construction will only occur when debug logging is enabled. +**We suggest you to use `LogManager.getLogger()` without any arguments** since it delivers the same functionality with less characters and is not prone to copy-paste errors. -=== Formatting Parameters +[#formatter-logger] +=== Formatter logger Review Comment: I think we should mention all three methods to personalize a logger ordered by usefulness: 1. `Logger.printf()`, 2. `LogManager.getFormatterLogger()`, 3. `LogManager.getLogger(String, MessageFactory)`. ########## src/site/antora/modules/ROOT/partials/manual/api-best-practice-use-supplier.adoc: ########## @@ -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. +//// + +If one or more arguments of the log statement are computationally expensive, it is not wise to evaluate them knowing that their results can be discarded. +Consider the following example: + +[source,java] +---- +/* BAD! */ LOGGER.info("failed for user ID `{}` and role `{}`", userId, db.findUserRoleById(userId)); +---- + +The database query (i.e., `db.findUserNameById(userId)`) can be a significant bottleneck if the created the log event will be discarded anyway – maybe the `INFO` level is not accepted for this logger, or due to some other filtering. + +* [ ] The old-school way of solving this problem is to level-guard the log statement: ++ +[source,java] +---- +/* OKAY */ if (LOGGER.isInfoEnabled()) { LOGGER.info(...); } +---- ++ +While this would work for cases where the message can be dropped due to insufficient level, this approach is still prone to other filtering cases; e.g., maybe the associated xref:manual/markers.adoc[marker] is not accepted. Review Comment: Maybe this should be an admonition with a slightly longer example? ```java if (logger.isInfoEnabled()) { logger.info("Hello guards!"; } ``` is OK, but: ```java if (logger.isInfoEnabled()) { logger.info(MY_MARKER, "Hello guards!"); } ``` not. ########## src/site/antora/modules/ROOT/partials/manual/api-intro.adoc: ########## @@ -0,0 +1,72 @@ +//// + 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. +//// + +To write logs, you need a `Logger` instance which you will retrieve from the `LogManager`. +You can use the `Logger` instance to write logs by using methods like `info()`, `warn()`, `error()`, etc. +These methods are named after the _log levels_ they represent, a way to categorize log events by severity. +The log message can also contain placeholders written as `{}` that will be replaced by the arguments passed to the method. + +[source,java] +---- +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; + +public class DbTableService { + + private static final Logger LOGGER = LogManager.getLogger(); // <1> + + public void truncateTable(String tableName) throws IOException { + LOGGER.warn("truncating table `{}`", tableName); // <2> + db.truncate(tableName); + } + +} +---- +<1> The returned `Logger` instance is thread-safe and reusable. +Unless explicitly provided as an argument, `getLogger()` associates the returned `Logger` with the enclosing class, that is, `DbTableService` in this example. +<2> The placeholder `{}` in the message will be replaced with the value of `tableName` + +The generated **log event** will be enriched with the log level (i.e., `WARN`), but also timestamp, class & method name, line number, and several other information. Review Comment: I think it is worth mentioning "context data" too. ########## src/site/antora/modules/ROOT/pages/manual/api.adoc: ########## @@ -14,187 +14,323 @@ See the License for the specific language governing permissions and limitations under the License. //// + +:jboss-logging-link: https://github.com/jboss-logging/jboss-logging[JBoss Logging] +:jcl-link: https://commons.apache.org/proper/commons-logging/[JCL (Apache Commons Logging)] +:jpl-link: https://openjdk.org/jeps/264[JPL (Java Platform Logging)] +:jul-link: https://docs.oracle.com/en/java/javase/{java-target-version}/core/java-logging-overview.html[JUL (Java Logging)] +:logback-link: https://logback.qos.ch/[Logback] +:slf4j-link: https://www.slf4j.org/[SLF4J] + = Log4j API -== Overview +Log4j is essentially composed of a logging API called *Log4j API*, and its reference implementation called *Log4j Core*. -The Log4j 2 API provides the interface that applications should code to -and provides the adapter components required for implementers to create -a logging implementation. Although Log4j 2 is broken up between an API -and an implementation, the primary purpose of doing so was not to allow -multiple implementations, although that is certainly possible, but to -clearly define what classes and methods are safe to use in "normal" -application code. +.What is a logging API and a logging implementation? +[%collapsible] +==== +Logging APIs:: +A logging API is an interface your code or your dependencies directly logs against. +It is implementation agnostic. +Log4j API, {slf4j-link}, {jul-link}, {jcl-link}, {jpl-link} and {jboss-logging-link} are major logging APIs. -=== Hello World! +Logging implementation:: +A logging implementation is only required at runtime and can be changed without the need to recompile your software. +Log4j Core, {jul-link}, {logback-link} are the most well-known logging implementations. +==== -No introduction would be complete without the customary Hello, World -example. Here is ours. First, a Logger with the name "HelloWorld" is -obtained from the -link:../javadoc/log4j-api/org/apache/logging/log4j/LogManager.html[`LogManager`]. -Next, the logger is used to write the "Hello, World!" message, however -the message will be written only if the Logger is configured to allow -informational messages. +[TIP] +==== +Are you looking for a crash course on how to use Log4j in your application or library? +See xref:5min.adoc[]. +You can also check out xref:manual/installation.adoc[] for the complete installation instructions. +==== -[source,java] ----- -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +Log4j API provides -public class HelloWorld { - private static final Logger logger = LogManager.getLogger("HelloWorld"); - public static void main(String[] args) { - logger.info("Hello, World!"); - } -} ----- +* A logging API that libraries and applications can code to +* Adapter components to create a logging implementation -The output from the call to `logger.info()` will vary significantly -depending on the configuration used. See the -xref:manual/configuration.adoc[Configuration] section for more details. +This page tries to cover the most prominent Log4j API features that libraries and applications can code to. -=== Substituting Parameters +== Introduction -Frequently the purpose of logging is to provide information about what -is happening in the system, which requires including information about -the objects being manipulated. In Log4j 1.x this could be accomplished -by doing: +include::partial$manual/api-intro.adoc[leveloffset=+1] -[source,java] ----- -if (logger.isDebugEnabled()) { - logger.debug("Logging in user " + user.getName() + " with birthday " + user.getBirthdayCalendar()); -} ----- +[#best-practice] +== Best practices + +There are several widespread bad practices while using Log4j API. +Let's try to walk through the most common ones and see how to fix them. + +[#best-practice-toString] +=== Don't use `toString()` + +include::partial$manual/api-best-practice-dont-use-toString.adoc[] + +[#best-practice-exception] +=== Pass exception as the last extra argument + +include::partial$manual/api-best-practice-exception-as-last-argument.adoc[] + +[#best-practice-concat] +=== Don't use string concatenation + +include::partial$manual/api-best-practice-dont-use-string-concat.adoc[] + +[#best-practice-supplier] +=== Use ``Supplier``s to pass computationally expensive arguments + +include::partial$manual/api-best-practice-use-supplier.adoc[] + +[#loggers] +== Loggers -Doing this repeatedly has the effect of making the code feel like it is -more about logging than the actual task at hand. In addition, it results -in the logging level being checked twice; once on the call to -isDebugEnabled and once on the debug method. A better alternative would -be: +link:../javadoc/log4j-api/org/apache/logging/log4j/Logger.html[`Logger`]s obtained using link:../javadoc/log4j-api/org/apache/logging/log4j/LogManager.html[`LogManager`] is the primary entry point for logging. +In this section we will introduce you to further details about ``Logger``s. + +[#logger-names] +=== Logger names + +Most logging implementations use a hierarchical scheme for matching logger names with logging configuration. +In this scheme, the logger name hierarchy is represented by `.` (dot) characters in the logger name, in a fashion very similar to the hierarchy used for Java package names. +For example, `org.apache.logging.appender` and `org.apache.logging.filter` both have `org.apache.logging` as their parent. + +In most cases, applications name their loggers by passing the current class's name to `LogManager.getLogger(...)`. +Because this usage is so common, Log4j provides that as the default when the logger name parameter is either omitted or is null. +For example, all `Logger`-typed variables below will have a name of `com.mycompany.LoggerNameTest`: [source,java] ---- -logger.debug("Logging in user {} with birthday {}", user.getName(), user.getBirthdayCalendar()); +package com.mycompany; + +public class LoggerNameTest { + + Logger logger1 = LogManager.getLogger(LoggerNameTest.class); + + Logger logger2 = LogManager.getLogger(LoggerNameTest.class.getName()); + + Logger logger3 = LogManager.getLogger(); + +} ---- -With the code above the logging level will only be checked once and the -String construction will only occur when debug logging is enabled. +**We suggest you to use `LogManager.getLogger()` without any arguments** since it delivers the same functionality with less characters and is not prone to copy-paste errors. -=== Formatting Parameters +[#formatter-logger] +=== Formatter logger -Formatter Loggers leave formatting up to you if `toString()` is not what -you want. To facilitate formatting, you can use the same format strings -as Java's -http://docs.oracle.com/javase/6/docs/api/java/util/Formatter.html#syntax[`Formatter`]. -For example: +The `Logger` instance returned by default replaces the occurrences of `{}` placeholders with the `toString()` output of the associated parameter. +If you need more control over how the parameters are formatted, you can also use the http://docs.oracle.com/javase/6/docs/api/java/util/Formatter.html#syntax[`java.util.Formatter`] format strings by obtaining your `Logger` using link:../javadoc/log4j-api/org/apache/logging/log4j/LogManager.html#getFormatterLogger(java.lang.Class)[`LogManager#getFormatterLogger()`]: [source,java] ---- -public static Logger logger = LogManager.getFormatterLogger("Foo"); - +Logger logger = LogManager.getFormatterLogger(); logger.debug("Logging in user %s with birthday %s", user.getName(), user.getBirthdayCalendar()); logger.debug("Logging in user %1$s with birthday %2$tm %2$te,%2$tY", user.getName(), user.getBirthdayCalendar()); logger.debug("Integer.MAX_VALUE = %,d", Integer.MAX_VALUE); logger.debug("Long.MAX_VALUE = %,d", Long.MAX_VALUE); ---- -To use a formatter Logger, you must call one of the `LogManager` -link:../javadoc/log4j-api/org/apache/logging/log4j/LogManager.html#getFormatterLogger(java.lang.Class)[`getFormatterLogger`] -methods. The output for this example shows that `Calendar::toString` is -verbose compared to custom formatting: +Loggers returned by `getFormatterLogger()` are referred as *formatter loggers*. + +[#printf] +==== `printf()` method + +Formatter loggers give fine-grained control over the output format, but have the drawback that the correct type must be specified. +For example, passing anything other than a decimal integer for a `%d` format parameter gives an exception. +If your main usage is to use `{}`-style parameters, but occasionally you need fine-grained control over the output format, you can use the `Logger#printf()` method: [source,java] ---- -2012-12-12 11:56:19,633 [main] DEBUG: User John Smith with birthday java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/New_York",offset=-18000000,dstSavings=3600000,useDaylight=true,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/New_York,offset=-18000000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=?,YEAR=1995,MONTH=4,WEEK_OF_YEAR=?,WEEK_OF_MONTH=?,DAY_OF_MONTH=23,DAY_OF_YEAR=?,DAY_OF_WEEK=?,DAY_OF_WEEK_IN_MONTH=?,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=?,ZONE_OFFSET=?,DST_OFFSET=?] -2012-12-12 11:56:19,643 [main] DEBUG: User John Smith with birthday 05 23, 1995 -2012-12-12 11:56:19,643 [main] DEBUG: Integer.MAX_VALUE = 2,147,483,647 -2012-12-12 11:56:19,643 [main] DEBUG: Long.MAX_VALUE = 9,223,372,036,854,775,807 +Logger logger = LogManager.getLogger("Foo"); +logger.debug("Opening connection to {}...", someDataSource); +logger.printf(Level.INFO, "Hello, %s!", userName); ---- -=== Mixing Loggers with Formatter Loggers +[#formatter-perf] +==== Formatter performance + +Keep in mind that, contrary to the formatter logger, the default Log4j logger (i.e., `{}`-style parameters) is heavily optimized for several use cases and can operate xref:manual/garbagefree.adoc[garbage-free] when configured correctly. +You might reconsider your formatter logger usages for latency sensitive applications. + +[#resource-logger] +=== Resource logger + +Resource loggers, introduced in Log4j API `2.24.0`, is a special kind of `Logger` that: + +* is a regular class member variable that will be garbage collected along with the class instance +* enriches generated log events with data associated with the resource (i.e., the class instance) + +xref:manual/resource-logger.adoc[Read more on resource loggers...] + +[#event-logger] +=== Event logger + +link:../javadoc/log4j-api/org/apache/logging/log4j/LogManager.html[`EventLogger`] provides a simple way to log structured events conforming with the `STRCUTURED-DATA` format defined in https://tools.ietf.org/html/rfc5424[RFC 5424 (The Syslog Protocol)]. -Formatter loggers give fine-grained control over the output format, but -have the drawback that the correct type must be specified (for example, -passing anything other than a decimal integer for a %d format parameter -gives an exception). +xref:manual/eventlogging.adoc[Read more on event loggers...] -If your main usage is to use \{}-style parameters, but occasionally you -need fine-grained control over the output format, you can use the -`printf` method: +[#feature-fluent-api] +== Fluent API + +The fluent API allows you to log using a fluent interface: [source,java] ---- -public static Logger logger = LogManager.getLogger("Foo"); - -logger.debug("Opening connection to {}...", someDataSource); -logger.printf(Level.INFO, "Logging in user %1$s with birthday %2$tm %2$te,%2$tY", user.getName(), user.getBirthdayCalendar()); +logger.atInfo() + .withMarker(marker) + .withLocation() + .withThrowable(exception) + .log("Login for user `{}` failed", userId); ---- -[#LambdaSupport] -=== Java 8 lambda support for lazy logging +xref:manual/logbuilder.adoc[Read more on the Fluent API...] + +[#fish-tagging] +== Fish tagging Review Comment: Nice section :100: ! We should probably also add the logger name as a "tag". -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: notifications-unsubscr...@logging.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org