From b969cbec8ce24fdd12643dd4205ea48b82199620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Wed, 1 May 2024 16:32:22 +0200 Subject: [PATCH 1/7] Improve Antora code styling --- antora-playbook.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/antora-playbook.yaml b/antora-playbook.yaml index 0b8db66622a..beaabee98cb 100644 --- a/antora-playbook.yaml +++ b/antora-playbook.yaml @@ -83,6 +83,10 @@ ui: .doc h3 { font-size: 1.5rem; font-weight: 400; } .doc h4 { font-size: 1.3rem; font-weight: 500; } .doc h5 { font-size: 1.1rem; font-weight: 500; text-decoration: underline; } + /* Default `code`, `pre`, and `.colist` (source code annotations) fonts are too big, adjust them: */ + .doc .colist>table code, .doc p code, .doc thead code { font-size: 0.8em; } + .doc pre { font-size: 0.7rem; } + .doc .colist { font-size: 0.75rem; } /* Tab header fonts aren't rendered good, adjusting the font weight: */ .tablist > ul li { font-weight: 500; } /* `page-toclevels` greater than 4 are not supported by Antora UI, patching it: */ From 3c280ca41a6ee823ff13315babab7655050aab0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Wed, 1 May 2024 16:43:09 +0200 Subject: [PATCH 2/7] Add `Learn Log4j in 5 minutes!` page --- src/site/antora/modules/ROOT/nav.adoc | 71 +-- src/site/antora/modules/ROOT/pages/5min.adoc | 453 ++++++++++++++++++ .../antora/modules/ROOT/pages/download.adoc | 10 + src/site/antora/modules/ROOT/pages/index.adoc | 30 +- .../ROOT/pages/manual/installation.adoc | 21 +- 5 files changed, 521 insertions(+), 64 deletions(-) create mode 100644 src/site/antora/modules/ROOT/pages/5min.adoc diff --git a/src/site/antora/modules/ROOT/nav.adoc b/src/site/antora/modules/ROOT/nav.adoc index abcc645e4e2..b7789787fdc 100644 --- a/src/site/antora/modules/ROOT/nav.adoc +++ b/src/site/antora/modules/ROOT/nav.adoc @@ -22,43 +22,46 @@ ** link:{logging-services-url}/security[Security] ** xref:thanks.adoc[Thanks] -.Learn -* xref:manual/index.adoc[] -** xref:manual/installation.adoc[] -** xref:manual/architecture.adoc[] -** xref:manual/migration.adoc[] -** xref:manual/api.adoc[] -*** xref:manual/logbuilder.adoc[] -*** xref:manual/flowtracing.adoc[] -*** xref:manual/markers.adoc[] -*** xref:manual/eventlogging.adoc[] -*** xref:manual/messages.adoc[] -*** xref:manual/thread-context.adoc[] -*** xref:manual/scoped-context.adoc[] -*** xref:manual/resource-logger.adoc[] -** xref:manual/configuration.adoc[] -** xref:manual/usage.adoc[] -** xref:manual/cloud.adoc[] -** xref:manual/lookups.adoc[] -** xref:manual/appenders.adoc[] -** xref:manual/layouts.adoc[] -*** xref:manual/json-template-layout.adoc[] -** xref:manual/filters.adoc[] -** xref:manual/async.adoc[] -** xref:manual/garbagefree.adoc[] -** xref:manual/extending.adoc[] -** xref:manual/plugins.adoc[] -** xref:manual/customconfig.adoc[] -** xref:manual/customloglevels.adoc[] -** xref:manual/jmx.adoc[] -** xref:manual/logsep.adoc[] -** xref:manual/performance.adoc[] -* xref:plugin-reference.adoc[Plugin reference] -* xref:javadoc.adoc[Java API reference] -* xref:articles.adoc[Articles] +.Resources * xref:faq.adoc[F.A.Q.] +* xref:5min.adoc[] * xref:development.adoc[] +.xref:manual/index.adoc[] +* xref:manual/installation.adoc[] +* xref:manual/architecture.adoc[] +* xref:manual/migration.adoc[] +* xref:manual/api.adoc[] +** xref:manual/logbuilder.adoc[] +** xref:manual/flowtracing.adoc[] +** xref:manual/markers.adoc[] +** xref:manual/eventlogging.adoc[] +** xref:manual/messages.adoc[] +** xref:manual/thread-context.adoc[] +** xref:manual/scoped-context.adoc[] +** xref:manual/resource-logger.adoc[] +* xref:manual/configuration.adoc[] +* xref:manual/usage.adoc[] +* xref:manual/cloud.adoc[] +* xref:manual/lookups.adoc[] +* xref:manual/appenders.adoc[] +* xref:manual/layouts.adoc[] +** xref:manual/json-template-layout.adoc[] +* xref:manual/filters.adoc[] +* xref:manual/async.adoc[] +* xref:manual/garbagefree.adoc[] +* xref:manual/extending.adoc[] +* xref:manual/plugins.adoc[] +* xref:manual/customconfig.adoc[] +* xref:manual/customloglevels.adoc[] +* xref:manual/jmx.adoc[] +* xref:manual/logsep.adoc[] +* xref:manual/performance.adoc[] + +.References +* xref:plugin-reference.adoc[Plugin reference] +* xref:javadoc.adoc[Java API reference] + .Components * xref:log4j-api.adoc[] * xref:log4j-1.2-api.adoc[] diff --git a/src/site/antora/modules/ROOT/pages/5min.adoc b/src/site/antora/modules/ROOT/pages/5min.adoc new file mode 100644 index 00000000000..6f1d532ddcd --- /dev/null +++ b/src/site/antora/modules/ROOT/pages/5min.adoc @@ -0,0 +1,453 @@ +//// + 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. +//// + += Learn Log4j in 5 minutes! + +You need a crash course on Log4j? +You are at the right place! + +[#what] +== What is logging and Log4j? + +Logging is the action of publishing diagnostics information at certain points of a program execution: + +[source,java] +---- +private void truncateTable(String tableName) { + System.out.format("[WARN] Truncating table `%s`!%n", tableName); + db.truncate(tableName); +} +---- + +This provides observability into an application's runtime. (See {logging-services-url}/what-is-logging.html[What is logging?] page for a longer read.) + +But we can do way better than a `printf()` statement! + +* Enhance the output with additional information (timestamp, class & method name, line number, host, severity, etc.) +* Use different **layouts** (CSV, JSON, etc.) +* Forward to different **appenders** (file, socket, database, queue, etc.) +* **Filter** on demand (e.g., increase verbosity dynamically for troubleshooting purposes) + +Log4j is versatile, industrial-grade Java logging framework delivering all these and more in one product. +It is essentially composed of a **logging API** and its **implementation**: + +Log4j API:: +The logging API your code (programmatically) logs through. +This needs to be available at compile-time and no configuration is needed. + +Log4j Core:: +The logging implementation which is responsible for filtering, routing, encoding, and appending log events. +This needs to be available at runtime and configured by the user. + +[#logging] +== How do I log using Log4j? + +Add the `log4j-api` dependency to your application: + +[tabs] +==== +Maven:: ++ +[source,xml,subs="+attributes"] +---- + + + + + + org.apache.logging.log4j + log4j-bom + {log4j-core-version} + import + pom + + + + + + + org.apache.logging.log4j + log4j-api + + + + +---- + +Gradle:: ++ +[source,groovy,subs="+attributes"] +---- +dependencies { + implementation platform('org.apache.logging.log4j:log4j-bom:{log4j-core-version}') + implementation 'org.apache.logging.log4j:log4j-api' +} +---- +==== + +And start logging: + +[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> This is a thread-safe, reusable `Logger` instance. +The associated class will be captured at initialization – no need for a `getLogger(DbTableService.class)`. +<2> The generated **log event** will be automatically parameter formatted (note the parameter placeholder, i.e., `{}`) and enriched with **level** (i.e., `WARN`), timestamp, class & method name, line number, and several other information. + +Make sure to log exceptions that have diagnostics value: + +[source,java] +---- +LOGGER.warn("truncating table `{}`", tableName); +try { + db.truncate(tableName); +} catch (IOException exception) { + LOGGER.error("failed truncating table `{}`", tableName, exception); // <1> + throw new IOException("failed truncating table: " + tableName, exception); +} +---- +<1> Notice the `error()` method? +Yup, the level is set to `ERROR`. ++ +What about the `exception` in the last argument? +Wait a second! +There is one placeholder in the format (i.e., `{}`), but there are two parameters passed in arguments: `tableName` and `exception`! +What the heck? +Yep, you guessed it right! +Log4j API will attach the last extra argument of type `Throwable` in a separate field to the generated log event. + +[#pitfalls] +=== Common pitfalls + +There are several widespread bad practices. +Let's try to walk through the most common ones. + +[#pitfal-toString] +==== Don't use `toString()` + +[source,java] +---- +// [✗] `Object#toString()` is redundant in arguments +LOGGER.info("userId: {}", userId.toString()); + +// [✓] Underlying message type and layout will deal with arguments +LOGGER.info("userId: {}", userId); +---- + +[#pitfall-exception] +==== Pass exception as the last extra argument + +Using `Throwable#printStackTrace()` or `Throwable#getMessage()` while logging? +Please, don't! + +[source,java] +---- +// [✗] Don't call `Throwable#printStackTrace()`. +// This not only circumvents the logging, but can also leak sensitive information! +exception.printStackTrace(); + +// [✗] Don't use `Throwable#getMessage()`. +// This prevents the log event from getting enriched with the exception. +LOGGER.info("failed", exception.getMessage()); +LOGGER.info("failed for user ID `{}`: {}", userId, exception.getMessage()); + +// [✗] This bloats the log message with duplicate exception message +LOGGER.info("failed for user ID `{}`: {}", userId, exception.getMessage(), exception); + +// [✓] Pass exception as the last extra argument +LOGGER.error("failed", exception); +LOGGER.error("failed for user ID `{}`", userId, exception); +---- + +[#pitfal-concat] +==== Don't use string concatenation + +If you are using `String` concatenation while logging, you are doing something very wrong and dangerous! + +[source,java] +---- +// [✗] Circumvents the handling of arguments by message type and layout. +// More importantly, this code is prone to attacks! +// Imagine `userId` being provided by user with the following content: +// `placeholders for non-existing args to trigger failure: {} {} {dangerousLookup}` +LOGGER.info("failed for user ID: " + userId); + +// [✓] Use message parameters +LOGGER.info("failed for user ID `{}`", userId); +---- + +[#config-app] +== How do I configure Log4j to run my **application**? + +Your code logs through a logging API. +So your dependencies and their dependencies too. +While deploying your application, you need to provide a **logging implementation** along with its configuration to consume all generated log events. + +[IMPORTANT] +==== +Are you implementing not an **application**, but a **library**? +Please skip to the xref:#config-lib[] instead. +==== + +Add the `log4j-core` **runtime** dependency to your application: + +[tabs] +==== +Maven:: ++ +[source,xml,subs="+attributes"] +---- + + + + + + + + + org.apache.logging.log4j + log4j-core + runtime + + + + + org.apache.logging.log4j + log4j-layout-template-json + runtime + + + + + org.apache.logging.log4j + log4j-slf4j2-impl + runtime + + + + + +---- + +Gradle:: ++ +[source,groovy,subs="+attributes"] +---- +dependencies { + + // Assuming you already have the `implementation platform(...)` entry for `log4j-bom` + + // The logging implementation (i.e., Log4j Core) + runtimeOnly 'org.apache.logging.log4j:log4j-core' // <1> + + // Log4j JSON-encoding support + runtimeOnly 'org.apache.logging.log4j:log4j-layout-template-json' // <1> + + // SLF4J-to-Log4j bridge // <2> + runtimeOnly 'org.apache.logging.log4j:log4j-slf4j2-impl' // <1> + +} +---- +==== +<1> Note that the logging implementation and bridges are only needed at runtime! +<2> SLF4J is another widely used logging API. +`log4j-slf4j2-impl` forwards SLF4J calls to Log4j API, which effectively gets processed by Log4j Core too. + +Now it is time to configure Log4j and instruct how the log events should be routed. +Save the following XML document to `src/**main**/resources/log4j2.xml`: + +.An example `src/**main**/resources/log4j2.xml` +[source,xml] +---- + + + + + + + + + + + + + + + + + +---- +<1> xref:manual/appenders.adoc[Appenders] are responsible for writing log events to console, file, socket, database, etc. +<2> xref:manual/appenders.adoc#ConsoleAppender[Console Appender] is used to write logs to the console. +<3> xref:manual/json-template-layout.adoc[JSON Template Layout] is used to encode log events in JSON. +<4> Log events generated by classes in the `com.mycompany` package (incl. its subpackages) and that are of level `INFO` and higher (i.e., `WARN`, `ERROR`, `FATAL`) will be consumed. +<5> Unless specified otherwise, log events of level `WARN` and and higher will be consumed. +<6> Unless specified otherwise, log events will be forwarded to the `console` appender defined earlier. + +You are strongly advised to use a different Log4j configuration for tests. +Continue to xref:#config-test[] + +[#config-lib] +== How do I configure Log4j for my **library**? + +Unlike applications, libraries should be logging implementation agnostic. +That is, **libraries should log through a logging API, but leave the decision of the logging implementation to the application**. +That said, libraries need a logging implementation while running their tests. + +[IMPORTANT] +==== +Are you implementing not a **library**, but an **application**? +Please skip to the xref:#config-app[] instead. +==== + +Add the `log4j-core` **test** dependency to your library: + +[tabs] +==== +Maven:: ++ +[source,xml,subs="+attributes"] +---- + + + + + + + + + org.apache.logging.log4j + log4j-core + test + + + + + org.apache.logging.log4j + log4j-slf4j2-impl + test + + + + + +---- + +Gradle:: ++ +[source,groovy,subs="+attributes"] +---- +dependencies { + + // Assuming you already have the `implementation platform(...)` entry for `log4j-bom` + + // The logging implementation (i.e., Log4j Core) + testOnly 'org.apache.logging.log4j:log4j-core' // <1> + + // SLF4J-to-Log4j bridge // <2> + testOnly 'org.apache.logging.log4j:log4j-slf4j2-impl' // <1> + +} +---- +==== +<1> Note that the logging implementation and bridges are only needed for tests! +<2> SLF4J is another widely used logging API. +`log4j-slf4j2-impl` forwards SLF4J calls to Log4j API, which effectively gets processed by Log4j Core too. + +Next, you need a `src/**test**/resources/log4j2.xml`. +See xref:#config-test[] + +[#config-test] +== How do I configure Log4j for tests? + +For tests, prefer a human-readable layout with increased verbosity. +Save the following XML document to `src/**test**/resources/log4j2.xml`: + +.An example `src/**test**/resources/log4j2.xml` +[source,xml] +---- + + + + + + + + + + + + + + + + + +---- +<1> xref:manual/layouts.adoc#PatternLayout[Pattern Layout] is used for a human-readable layout. +<2> Increased logging verbosity for the `com.mycompany` package. + +[#next] +== What is next? + +Installation:: +While shared dependency management snippets should get you going, it can also be challenging depending on your use case. +Are you dealing with a Spring Boot application? +Is it running in a Java EE container? +Do you need to take into account other logging APIs such as JUL, JPL, JCL, etc.? +See xref:manual/installation.adoc[] for the complete installation guide. + +Configuration:: +Log4j can be configured in several ways in various file formats (XML, JSON, Properties, and YAML). +See the xref:manual/configuration.adoc[] page for details. + +Appenders & Layouts:: +Log4j contains several xref:manual/appenders.adoc[appenders] and xref:manual/layouts.adoc[layouts] to compose a configuration that best suit your needs. + +Performance:: +Do you want to get the best performance out of your logging system? +Make sure to check out the xref:manual/performance.adoc[] page. + +Architecture:: +Want to learn more about loggers, contexts, and how these are all wired together? +See the xref:manual/architecture.adoc[] page. + +Support:: +Confused? +Having problem while setting up Log4j? +See the {logging-services-url}/support.html[Support] page. diff --git a/src/site/antora/modules/ROOT/pages/download.adoc b/src/site/antora/modules/ROOT/pages/download.adoc index 0666d48ac91..27dbfa84425 100644 --- a/src/site/antora/modules/ROOT/pages/download.adoc +++ b/src/site/antora/modules/ROOT/pages/download.adoc @@ -21,3 +21,13 @@ You can manually download all published Log4j distributions, verify them, and se * Are you looking for **the Log4j installation instructions**? Proceed to xref:manual/installation.adoc[]. * Are you looking for the list of changes associated with a particular release? Proceed to xref:release-notes.adoc[]. + +[#older] +== Older releases + +Are you looking for old versions of Log4j? +While we recommend to always use the latest version, you can find the older versions here: + +* {logging-services-url}/1.x/[Log4j 1.x (End of Life, Java 1.4)] +* {logging-services-url}/2.3.x/[Log4j 2.3.x (Java 6)] +* {logging-services-url}/2.12.x/[Log4j 2.12.x (Java 7)] diff --git a/src/site/antora/modules/ROOT/pages/index.adoc b/src/site/antora/modules/ROOT/pages/index.adoc index 879c5ab4cc7..2ccc92b10ca 100644 --- a/src/site/antora/modules/ROOT/pages/index.adoc +++ b/src/site/antora/modules/ROOT/pages/index.adoc @@ -23,11 +23,12 @@ The project is actively maintained by a {logging-services-url}/team-list.html[te [#shortcuts] == Shortcuts -- xref:manual/installation.adoc[How can I add Log4j artifacts to my Maven/Ivy/Gradle project?] -- xref:manual/usage.adoc[How can I use the Log4j API?] + +- xref:5min.adoc[] +- xref:manual/installation.adoc[How can I install Log4j? Which dependencies are needed?] - xref:manual/configuration.adoc[How can I configure my `log4j2.xml`?] - xref:release-notes.adoc[Where are the release notes?] -- {logging-services-url}/support[**I need help!**] +- {logging-services-url}/support.html[**I need help!**] [#features] == Features @@ -60,26 +61,3 @@ Extensibility:: Log4j contains a fully-fledged xref:manual/plugins.adoc[plugin support] that users can leverage to extend its functionality. You can easily add your own components (layouts, appenders, filters, etc.) or customizing existing ones (e.g., adding new directives to the xref:manual/layouts.adoc#PatternLayout[Pattern] or xref:manual/json-template-layout.adoc#extending[JSON Template Layout]). Check out the xref:manual/extending.adoc[Extending Log4j] page. - -[#requirements] -== Requirements - -Log4j 2 runtime requires a minimum of Java 8. -Older versions of Java are supported by previous releases. - -[#older-releases] -== Older releases - -Are you looking for old versions of Log4j? -While we recommend to always use the latest version, you can find the older versions here: - -* {logging-services-url}/1.x/[Log4j 1.x (End of Life, Java 1.4)] -* {logging-services-url}/2.3.x/[Log4j 2.3.x (Java 6)] -* {logging-services-url}/2.12.x/[Log4j 2.12.x (Java 7)] - -[#compat] -== Compatibility - -The `log4j-1.2-api` module provides compatibility for applications using the Log4j 1 logging methods. -Log4j 2 also provides support for Log4j 1 configuration files. -See xref:manual/migration.adoc#ConfigurationCompatibility[Log4j 2 compatibility with Log4j 1] for more information. diff --git a/src/site/antora/modules/ROOT/pages/manual/installation.adoc b/src/site/antora/modules/ROOT/pages/manual/installation.adoc index c2ac9f13c9d..1e027bb7450 100644 --- a/src/site/antora/modules/ROOT/pages/manual/installation.adoc +++ b/src/site/antora/modules/ROOT/pages/manual/installation.adoc @@ -391,6 +391,8 @@ Since version `1.3.0` https://commons.apache.org/proper/commons-logging/[Apache You can enforce the version of a transitive dependency using the dependency management mechanism appropriate to your build tool: +[tabs] +==== Maven:: Maven users should add an entry to the `` section of their POM file: + @@ -408,6 +410,7 @@ Maven users should add an entry to the `` section of their Gradle:: + Gradle users should refer to the https://docs.gradle.org/current/userguide/platforms.html#sub:using-platform-to-control-transitive-deps[Using a platform to control transitive versions] of the Gradle documentation. +==== [#impl-core-bridge-jboss-logging] ===== Installing JBoss Logging-to-Log4j bridge @@ -484,13 +487,15 @@ log4j2.xml:: + https://logging.apache.org/xml/ns/log4j-config-2.xsd"> - + + + - + @@ -504,7 +509,10 @@ log4j2.json:: "Configuration": { "Appenders": { "Console": { - "name": "CONSOLE" + "name": "CONSOLE", + "PatternLayout": { + "pattern": "%d [%t] %5p %c{1.} - %m%n" // <1> + } } }, "Loggers": { @@ -527,6 +535,8 @@ Configuration: Appenders: Console: name: CONSOLE + PatternLayout: + pattern: "%d [%t] %5p %c{1.} - %m%n" # <1> Loggers: Root: level: INFO @@ -540,11 +550,14 @@ log4j2.properties:: ---- appender.0.type = Console appender.0.name = CONSOLE +appender.0.layout = PatternLayout # <1> +appender.0.layout.pattern = %d [%t] %5p %c{1.} - %m%n rootLogger.level = INFO rootLogger.appenderRef.0.ref = CONSOLE ---- ==== +<1> While xref:manual/layouts.adoc#PatternLayout[Pattern Layout] is a good first choice and preferable for tests, we recommend using a structured format such as xref:manual/json-template-layout.adoc[] for production deployments. In order to use these formats, the following additional dependencies are required: From b48bfe372f344c05adb7f30c08108946eb0924ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Wed, 1 May 2024 16:55:26 +0200 Subject: [PATCH 3/7] Fix CSS --- antora-playbook.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/antora-playbook.yaml b/antora-playbook.yaml index beaabee98cb..6bafbcabee0 100644 --- a/antora-playbook.yaml +++ b/antora-playbook.yaml @@ -88,10 +88,10 @@ ui: .doc pre { font-size: 0.7rem; } .doc .colist { font-size: 0.75rem; } /* Tab header fonts aren't rendered good, adjusting the font weight: */ - .tablist > ul li { font-weight: 500; } + .tablist > ul li { font-weight: 500; } /* `page-toclevels` greater than 4 are not supported by Antora UI, patching it: */ .toc .toc-menu li[data-level="4"] a { - padding-left: 2.75rem + padding-left: 2.75rem; } /* Replace the default highlight.js color for strings from red (unnecessarily signaling something negative) to green: */ .hljs-string { From fb1f06bdbd2ac958f35b0fcbcebc801240ec73ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Thu, 2 May 2024 08:28:37 +0200 Subject: [PATCH 4/7] Improve wording on appenders, layouts, etc. --- src/site/antora/modules/ROOT/pages/5min.adoc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/site/antora/modules/ROOT/pages/5min.adoc b/src/site/antora/modules/ROOT/pages/5min.adoc index 6f1d532ddcd..31c57c28889 100644 --- a/src/site/antora/modules/ROOT/pages/5min.adoc +++ b/src/site/antora/modules/ROOT/pages/5min.adoc @@ -37,10 +37,10 @@ This provides observability into an application's runtime. (See {logging-service But we can do way better than a `printf()` statement! -* Enhance the output with additional information (timestamp, class & method name, line number, host, severity, etc.) -* Use different **layouts** (CSV, JSON, etc.) -* Forward to different **appenders** (file, socket, database, queue, etc.) -* **Filter** on demand (e.g., increase verbosity dynamically for troubleshooting purposes) +* Enhance the message with additional information (timestamp, class & method name, line number, host, severity, etc.) +* Write the message in a different way, using a different **layout** (CSV, JSON, etc.) +* Write the message to a different medium, using a different **appender** (file, socket, database, queue, etc.) +* Write only some of the messages, using a **filter** (e.g. filter by severity, content, etc.) Log4j is versatile, industrial-grade Java logging framework delivering all these and more in one product. It is essentially composed of a **logging API** and its **implementation**: From 280462133cd5ea8dec7edfdddbc8445519df0707 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Thu, 2 May 2024 08:30:38 +0200 Subject: [PATCH 5/7] Avoid using `parameter formatted` --- src/site/antora/modules/ROOT/pages/5min.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/site/antora/modules/ROOT/pages/5min.adoc b/src/site/antora/modules/ROOT/pages/5min.adoc index 31c57c28889..de740a1bf8d 100644 --- a/src/site/antora/modules/ROOT/pages/5min.adoc +++ b/src/site/antora/modules/ROOT/pages/5min.adoc @@ -119,7 +119,7 @@ public class DbTableService { ---- <1> This is a thread-safe, reusable `Logger` instance. The associated class will be captured at initialization – no need for a `getLogger(DbTableService.class)`. -<2> The generated **log event** will be automatically parameter formatted (note the parameter placeholder, i.e., `{}`) and enriched with **level** (i.e., `WARN`), timestamp, class & method name, line number, and several other information. +<2> The parameter placeholders `{}` in the message will be automatically replaced with the value of `tableName` and the generated **log event** will be enriched with **level** (i.e., `WARN`), timestamp, class & method name, line number, and several other information. Make sure to log exceptions that have diagnostics value: From 34c325c6e4aa214c737c380af3a481c6b82a4f26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Thu, 2 May 2024 08:44:01 +0200 Subject: [PATCH 6/7] Replace code comments with bullets --- src/site/antora/modules/ROOT/pages/5min.adoc | 69 +++++++++++++------- 1 file changed, 46 insertions(+), 23 deletions(-) diff --git a/src/site/antora/modules/ROOT/pages/5min.adoc b/src/site/antora/modules/ROOT/pages/5min.adoc index de740a1bf8d..e0774cbf402 100644 --- a/src/site/antora/modules/ROOT/pages/5min.adoc +++ b/src/site/antora/modules/ROOT/pages/5min.adoc @@ -152,13 +152,18 @@ Let's try to walk through the most common ones. [#pitfal-toString] ==== Don't use `toString()` +* [ ] `Object#toString()` is redundant in arguments ++ [source,java] ---- -// [✗] `Object#toString()` is redundant in arguments -LOGGER.info("userId: {}", userId.toString()); +/* BAD! */ LOGGER.info("userId: {}", userId.toString()); +---- -// [✓] Underlying message type and layout will deal with arguments -LOGGER.info("userId: {}", userId); +* [x] Underlying message type and layout will deal with arguments ++ +[source,java] +---- +/* GOOD */ LOGGER.info("userId: {}", userId); ---- [#pitfall-exception] @@ -167,23 +172,36 @@ LOGGER.info("userId: {}", userId); Using `Throwable#printStackTrace()` or `Throwable#getMessage()` while logging? Please, don't! +* [ ] Don't call `Throwable#printStackTrace()`. +This not only circumvents the logging, but can also leak sensitive information! ++ [source,java] ---- -// [✗] Don't call `Throwable#printStackTrace()`. -// This not only circumvents the logging, but can also leak sensitive information! -exception.printStackTrace(); +/* BAD! */ exception.printStackTrace(); +---- -// [✗] Don't use `Throwable#getMessage()`. -// This prevents the log event from getting enriched with the exception. -LOGGER.info("failed", exception.getMessage()); -LOGGER.info("failed for user ID `{}`: {}", userId, exception.getMessage()); +* [ ] Don't use `Throwable#getMessage()`. +This prevents the log event from getting enriched with the exception. ++ +[source,java] +---- +/* BAD! */ LOGGER.info("failed", exception.getMessage()); +/* BAD! */ LOGGER.info("failed for user ID `{}`: {}", userId, exception.getMessage()); +---- -// [✗] This bloats the log message with duplicate exception message -LOGGER.info("failed for user ID `{}`: {}", userId, exception.getMessage(), exception); +* [ ] This bloats the log message with duplicate exception message ++ +[source,java] +---- +/* BAD! */ LOGGER.info("failed for user ID `{}`: {}", userId, exception.getMessage(), exception); +---- -// [✓] Pass exception as the last extra argument -LOGGER.error("failed", exception); -LOGGER.error("failed for user ID `{}`", userId, exception); +* [x] Pass exception as the last extra argument ++ +[source,java] +---- +/* GOOD */ LOGGER.error("failed", exception); +/* GOOD */ LOGGER.error("failed for user ID `{}`", userId, exception); ---- [#pitfal-concat] @@ -191,16 +209,21 @@ LOGGER.error("failed for user ID `{}`", userId, exception); If you are using `String` concatenation while logging, you are doing something very wrong and dangerous! +* [ ] Circumvents the handling of arguments by message type and layout. +More importantly, this code is prone to attacks! +Imagine `userId` being provided by user with the following content: +`placeholders for non-existing args to trigger failure: {} {} \{dangerousLookup}` ++ [source,java] ---- -// [✗] Circumvents the handling of arguments by message type and layout. -// More importantly, this code is prone to attacks! -// Imagine `userId` being provided by user with the following content: -// `placeholders for non-existing args to trigger failure: {} {} {dangerousLookup}` -LOGGER.info("failed for user ID: " + userId); +/* BAD! */ LOGGER.info("failed for user ID: " + userId); +---- -// [✓] Use message parameters -LOGGER.info("failed for user ID `{}`", userId); +* [x] Use message parameters ++ +[source,java] +---- +/* GOOD */ LOGGER.info("failed for user ID `{}`", userId); ---- [#config-app] From 89f8827f104be82b799f942d5dc4528fe93031c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Thu, 2 May 2024 08:46:02 +0200 Subject: [PATCH 7/7] Fix usage of `log4j2-test.xml` --- src/site/antora/modules/ROOT/pages/5min.adoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/site/antora/modules/ROOT/pages/5min.adoc b/src/site/antora/modules/ROOT/pages/5min.adoc index e0774cbf402..864dca105b1 100644 --- a/src/site/antora/modules/ROOT/pages/5min.adoc +++ b/src/site/antora/modules/ROOT/pages/5min.adoc @@ -408,16 +408,16 @@ dependencies { <2> SLF4J is another widely used logging API. `log4j-slf4j2-impl` forwards SLF4J calls to Log4j API, which effectively gets processed by Log4j Core too. -Next, you need a `src/**test**/resources/log4j2.xml`. +Next, you need a `src/**test**/resources/log4j2-test.xml`. See xref:#config-test[] [#config-test] == How do I configure Log4j for tests? For tests, prefer a human-readable layout with increased verbosity. -Save the following XML document to `src/**test**/resources/log4j2.xml`: +Save the following XML document to `src/**test**/resources/log4j2-test.xml`: -.An example `src/**test**/resources/log4j2.xml` +.An example `src/**test**/resources/log4j2-test.xml` [source,xml] ----