blob: 9b6da47430da45214986283d1fa717395164ced7 [file] [log] [blame]
////
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.
////
= Getting started
This document aims to guide you through the most important aspects of logging with Log4j.
It is not a comprehensive guide, but it should give you a good starting point.
[#what]
== What is logging?
Logging is the act of publishing diagnostics information at certain points of a program execution.
It means you can write messages to a log file or console to help you understand what your application is doing.
The simplest way to log in Java is to use `System.out.println()`, like this:
[source, java]
----
private void truncateTable(String tableName) {
System.out.println("truncating table"); <1>
db.truncate(tableName);
}
----
<1> The information that a table is being truncated is written to the console.
This is already useful, but the reader of this message does not know what table is being truncated.
Usually, we would like to include the table name in the message, which quickly leads developers to use `System.out.format()` or similar methods.
Log4j helps with formatting strings as we will see later, but for now, let's see how to work without it.
The following code shows how this method can be improved to provide more context about its action.
[source, java]
----
private void truncateTable(String tableName) {
System.out.format("[WARN] truncating table `%s`%n", tableName); <1>
db.truncate(tableName);
}
----
<1> `format()` writes the message to the console, replacing `%s` with the value of `tableName`, and `%n` with a new line.
If the developer decides the truncate the table `fruits`, the output of this code will look like this:
[source,text]
----
[WARN] Truncating table `fruits`
----
This provides observability into an application's runtime, and we can follow the execution flow.
However, there are several drawbacks with the above approach and this is where Log4j comes in.
Log4j will help you to write logs in a more structured way, with more information, and with more flexibility.
[#why]
== Why should I use Log4j?
Log4j is a versatile, industrial-grade Java logging framework, maintained by many contributors.
It can help us with common logging tasks and lets us focus on the application logic.
It helps with:
* Enhancing the message with additional information (timestamp, file, class, and method name, line number, host, severity, etc.)
* Formatting the message according to a given **layout** (CSV, JSON, etc.)
* Writing the message to various targets using an **appender** (console, file, socket, database, queue, etc.)
* **Filter**ing messages to be written (e.g. filter by severity, content, etc.)
[#architecture]
== What is Log4j composed of?
Log4j is essentially composed of a logging API called *Log4j API*, and its reference implementation called *Log4j Core*.
Log4j also bundles several logging bridges to enable Log4j Core consume from foreign logging APIs.
Let's briefly explain these concepts:
include::partial$concepts.adoc[tags=inc;api;impl;bridge]
[#prerequisites]
== What are the installation prerequisites?
We will need a BOM (Bill of Materials) to manage the versions of the dependencies.
This way we won't need to provide the version for each Log4j module explicitly.
include::partial$components/log4j-bom.adoc[]
[#using-api]
== How do I log using Log4j API?
include::partial$manual/api-intro.adoc[]
[#best-practice]
=== Best practices
There are several widespread bad practices while using Log4j API.
Below we will walk through the most common ones and see how to fix them.
For a complete list, refer to xref:manual/api.adoc#best-practice[the Log4j API best practices page].
[#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[]
[#install-app]
== How do I install Log4j Core to run my **application**?
This section explains how to install Log4j Core to run an application.
[IMPORTANT]
====
Are you implementing not an **application**, but a **library**?
Please refer to the <<install-lib>> instead.
====
First, add the `log4j-core` **runtime** dependency to your application.
Second, it is highly recommended to add the `log4j-layout-template-json` **runtime** dependency to encode log events in JSON.
This is the most secure way to format log events and should be preferred over the default `PatternLayout`, at least for production deployments.
[tabs]
====
Maven::
+
[source,xml,subs="+attributes"]
----
<project>
<!-- Assuming `log4j-bom` is added -->
<dependency>
<!-- Logging implementation (Log4j Core) -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<scope>runtime</scope><!--1-->
</dependency>
<!-- Log4j JSON-encoding support -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-layout-template-json</artifactId>
<scope>runtime</scope><!--1-->
</dependency>
</dependency>
</project>
----
Gradle::
+
[source,groovy,subs="+attributes"]
----
dependencies {
// Assuming `log4j-bom` is added
// 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>
}
----
====
<1> For applications, the logging implementation need to be runtime dependencies.
If your application has (direct or transitive!) dependencies that use another logging API, you need to <<logging-bridge,bridge>> that to Log4j.
This way the foreign logging API calls will effectively be consumed by Log4j too.
{slf4j-url}[SLF4J] is another logging API used pretty common in the wild.
(xref:manual/installation.adoc[] covers all supported foreign APIs.)
Let's see how you can use the `log4j-slf4j2-impl` bridge to support SLF4J:
[tabs]
====
Maven::
+
[source,xml,subs="+attributes"]
----
<project>
<!-- Assuming `log4j-bom` is added -->
<dependency>
<!-- Assuming `log4j-core` and `log4j-layout-template-json` is added -->
<!-- SLF4J-to-Log4j bridge --><!--2-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId>
<scope>runtime</scope><!--1-->
</dependency>
</dependency>
</project>
----
Gradle::
+
[source,groovy,subs="+attributes"]
----
dependencies {
// Assuming `log4j-bom`, `log4j-core`, and `log4j-layout-template-json` is added
// SLF4J-to-Log4j bridge // <2>
runtimeOnly 'org.apache.logging.log4j:log4j-slf4j2-impl' // <1>
}
----
====
<1> For applications, bridges need to be runtime dependencies.
<2> Log4j module bridging SLF4J to Log4j
To complete the installation, Log4j needs to be configured.
Please continue with <<config-app>>
[#config-app]
== How do I configure Log4j Core to run my **application**?
This section explains configuring Log4j on how log events should be processed.
xref:manual/configuration.adoc[Log4j supports several configuration inputs and file formats.]
Let's start with a basic and robust configuration where the logs are encoded in JSON and written to the console.
Save the following XML-formatted Log4j **configuration file** to `src/**main**/resources/**log4j2.xml**` in your application.
.An example `src/**main**/resources/**log4j2.xml**`
[source,xml]
----
<?xml version="1.0" encoding="UTF-8"?>
<Configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://logging.apache.org/xml/ns"
xsi:schemaLocation="
https://logging.apache.org/xml/ns
https://logging.apache.org/xml/ns/log4j-config-2.xsd">
<Appenders><!--1-->
<Console name="CONSOLE"><!--2-->
<JsonTemplateLayout/><!--3-->
</Console>
</Appenders>
<Loggers>
<Logger name="com.mycompany" level="INFO"/><!--4-->
<Root level="WARN"><!--5-->
<AppenderRef ref="CONSOLE"/><!--6-->
</Root>
</Loggers>
</Configuration>
----
<1> xref:manual/appenders.adoc[Appenders] are responsible for writing log events to a particular target; console, file, socket, database, queue, etc.
<2> xref:manual/appenders.adoc#ConsoleAppender[Console Appender] writes logs to the console.
<3> xref:manual/layouts.adoc[Layouts] are responsible for encoding log events before appenders writing them.
xref:manual/json-template-layout.adoc[JSON Template Layout] encodes log events in JSON.
<4> Log events generated by classes in the `com.mycompany` package (incl. its sub-packages) and that are of level `INFO` or higher (i.e., `WARN`, `ERROR`, `FATAL`) will be accepted.
<5> Unless specified otherwise, log events of level `WARN` and higher will be accepted.
It serves as the default `<logger>` configuration.
<6> Unless specified otherwise, accepted log events will be forwarded to the `console` appender defined earlier.
Next, you need to configure Log4j for the tests of your application.
Please proceed to <<config-test>>
[#install-lib]
== How do I install Log4j Core for my **library**?
This section explains how to install Log4j Core for libraries.
[IMPORTANT]
====
Are you implementing not a **library**, but an **application**?
Please refer to <<install-app>> instead.
====
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.
Let's see how you can install Log4j Core for your tests.
Start with adding the `log4j-core` dependency in **test** scope to your library:
[tabs]
====
Maven::
+
[source,xml,subs="+attributes"]
----
<project>
<!-- Assuming `log4j-bom` is added -->
<dependency>
<!-- Logging implementation (Log4j Core) -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<scope>test</scope><!--1-->
</dependency>
</dependency>
</project>
----
Gradle::
+
[source,groovy,subs="+attributes"]
----
dependencies {
// Assuming `log4j-bom` is already added
// The logging implementation (i.e., Log4j Core)
testRuntimeOnly 'org.apache.logging.log4j:log4j-core' // <1>
}
----
====
<1> For tests of libraries, the logging implementation is only needed in test scope.
If your library has (direct or transitive!) dependencies that use another logging API, you need to <<logging-bridge,bridge>> that to Log4j.
This way the foreign logging API calls will effectively be consumed by Log4j too.
{slf4j-url}[SLF4J] is another logging API used pretty common in the wild.
(xref:manual/installation.adoc[] covers all supported foreign APIs.)
Let's see how you can use the `log4j-slf4j2-impl` bridge to support SLF4J:
[tabs]
====
Maven::
+
[source,xml,subs="+attributes"]
----
<project>
<!-- Assuming `log4j-bom` is added -->
<dependency>
<!-- Assuming `log4j-core` and `log4j-layout-template-json` is added -->
<!-- SLF4J-to-Log4j bridge --><!--2-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId>
<scope>test</scope><!--1-->
</dependency>
</dependency>
</project>
----
Gradle::
+
[source,groovy,subs="+attributes"]
----
dependencies {
// Assuming `log4j-bom`, `log4j-core`, and `log4j-layout-template-json` is added
// SLF4J-to-Log4j bridge // <2>
runtimeOnly 'org.apache.logging.log4j:log4j-slf4j2-impl' // <1>
}
----
====
<1> For tests of libraries, logging bridges are only needed in test scope.
<2> Log4j module bridging SLF4J to Log4j
Next, you need to you need to configure Log4j.
Please proceed to <<config-test>>
[#config-test]
== How do I configure Log4j Core for tests?
This section explains configuring Log4j on how log events should be processed for tests.
xref:manual/configuration.adoc[Log4j supports several configuration inputs and file formats.]
Let's start with a basic and developer-friendly configuration where the logs are pretty-printed in a human-readable way and written to the console.
Contrast to <<config-app,an application's more conservative Log4j setup>>, for tests, we will go with a more developer-friendly Log4j configuration where
. the logs are pretty-printed to the console, and
. logging verbosity is increased.
While it is not recommended to use xref:manual/pattern-layout.adoc[] in production for security reasons, it is a good choice for tests to encode log events.
We will use it to pretty-print the log event to the console with extra fields: timestamp, thread name, log level, class name, etc.
The rest of the configuration should look familiar from earlier sections.
Save the following XML-formatted Log4j configuration file to `src/**test**/resources/**log4j2-test.xml**`.
.An example `src/**test**/resources/**log4j2-test.xml**`
[source,xml]
----
<?xml version="1.0" encoding="UTF-8"?>
<Configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://logging.apache.org/xml/ns"
xsi:schemaLocation="
https://logging.apache.org/xml/ns
https://logging.apache.org/xml/ns/log4j-config-2.xsd">
<Appenders>
<Console name="CONSOLE">
<PatternLayout pattern="%d [%t] %5p %c{1.} - %m%n"/><!--1-->
</Console>
</Appenders>
<Loggers>
<Logger name="com.mycompany" level="DEBUG"/><!--2-->
<Root level="WARN">
<AppenderRef ref="CONSOLE"/>
</Root>
</Loggers>
</Configuration>
----
<1> xref:manual/pattern-layout.adoc[] is used for encoding the log event in a human-readable way.
<2> Increased logging verbosity for the `com.mycompany` package.
[#next]
== What is next?
At this stage, you know
. How to install Log4j API and log using it
. How to install and configure Log4j Core in your application/library
You can use following pointers to further customize your Log4j setup.
Installation::
While shared dependency management snippets should get you going, your case might necessitate a more intricate setup.
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 a problem while setting up Log4j?
See the {logging-services-url}/support.html[Support] page.