Skip to content

Commit e6ef19f

Browse files
committed
explained code in advance, restructures, clarifying some purpose
1 parent 69169e6 commit e6ef19f

File tree

1 file changed

+133
-60
lines changed

1 file changed

+133
-60
lines changed

src/site/antora/modules/ROOT/pages/5min.adoc

+133-60
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
2020
This document aims to guide you through the most important aspects of logging with Log4j.
2121
It is not a comprehensive guide, but it should give you a good starting point.
22-
If you are looking for a more detailed read, please see {logging-services-url}/what-is-logging.html[What is logging?].
2322
2423
[#what]
2524
== What is logging?
@@ -80,20 +79,12 @@ It will:
8079
* Write the message to a different medium, using a different **appender** (file, socket, database, queue, etc.)
8180
* Write only some of the messages, using a **filter** (e.g. filter by severity, content, etc.)
8281
83-
Log4j is essentially composed of a **logging API** and its **implementation**:
84-
85-
Log4j API::
86-
The logging API your code (programmatically) logs through.
87-
This needs to be available at compile-time and no configuration is needed.
88-
89-
Log4j Core::
90-
The logging implementation is responsible for filtering, routing, encoding, and appending log events.
91-
This needs to be available at runtime and configured by the user.
92-
93-
[#logging]
94-
== How do I write logs using Log4j?
82+
[#install]
83+
== How do to install Log4j?
9584
96-
Add the `log4j-api` dependency to your application:
85+
Add the necessary `log4j-api` dependencies to your application. We will need
86+
a **BOM** (Bill of Materials) to manage the versions of the dependencies.
87+
In addition, we will need the `log4j-api` dependency itself.
9788
9889
[tabs]
9990
====
@@ -136,7 +127,15 @@ dependencies {
136127
----
137128
====
138129
139-
And start logging:
130+
[#logging]
131+
== How do I write logs using Log4j?
132+
133+
To write logs, you need a `Logger` instance which you will retrieve from the `LogManager`.
134+
The `Logger` instance is thread-safe and reusable.
135+
136+
Second, you can use the `Logger` instance to write logs by using methods like `info`, `warn`, `error`, etc.
137+
We will come to them in a moment.
138+
The string can also contain placeholders written as `{}` that will be replaced by the arguments passed to the method.
140139
141140
[source,java]
142141
----
@@ -155,10 +154,20 @@ public class DbTableService {
155154
}
156155
----
157156
<1> This is a thread-safe, reusable `Logger` instance.
158-
The associated class will be captured at initialization – no need for a `getLogger(DbTableService.class)`.
159-
<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.
157+
<2> The placeholder `{}` in the message will be replaced with the value of `tableName`
158+
159+
The generated **log event** will be enriched with the **log level** (i.e., `WARN`),
160+
but also timestamp, class & method name, line number, and several other information.
161+
162+
Log levels are used to categorize log events by severity and control the verbosity of the logs.
163+
Log4j knows various levels, but the most common are `DEBUG`, `WARN`, and `ERROR`.
164+
With them, you can filter out less important logs and focus on the most critical ones.
165+
Previously we used `LOGGER.warn` to log a warning message, which could mean that something is not right, but the application can continue.
166+
Log levels have a priority, and `WARN` is less severe than `ERROR`.
160167
161-
Make sure to log exceptions that have diagnostics value:
168+
Exceptions are often also errors.
169+
In this case, we might use the `ERROR` log level.
170+
Make sure to log exceptions that have diagnostics value - we can simply pass the exception as the last argument to the log method.
162171
163172
[source,java]
164173
----
@@ -170,15 +179,10 @@ try {
170179
throw new IOException("failed truncating table: " + tableName, exception);
171180
}
172181
----
173-
<1> Notice the `error()` method?
174-
Yup, the level is set to `ERROR`.
175-
+
176-
What about the `exception` in the last argument?
177-
Wait a second!
178-
There is one placeholder in the format (i.e., `{}`), but there are two parameters passed in arguments: `tableName` and `exception`!
179-
What the heck?
180-
Yep, you guessed it right!
181-
Log4j API will attach the last extra argument of type `Throwable` in a separate field to the generated log event.
182+
<1> By using `error()` instead of `warn()`, we signal that the operation failed.
183+
184+
While there is only one placeholder in the message, we pass two arguments: `tableName` and `exception`.
185+
Log4j will attach the last extra argument of type `Throwable` in a separate field to the generated log event.
182186
183187
[#pitfalls]
184188
=== Common pitfalls
@@ -262,20 +266,41 @@ Imagine `userId` being provided by the user with the following content:
262266
/* GOOD */ LOGGER.info("failed for user ID `{}`", userId);
263267
----
264268
265-
[#config-app]
266-
== How do I configure Log4j to run my **application**?
269+
[#integrating-log4j]
270+
== Integrating Log4j
271+
272+
Log4j is composed of two main parts, the API and the Core.
273+
With this distinction, you can log through the API and route the log events through the Core.
274+
If you prefer, you can also route the log events through other logging frameworks like SLF4J.
267275
268-
Your code logs through a logging API.
276+
[#log4j-api]
277+
Log4j API::
278+
The logging API your code (programmatically) logs through.
279+
This needs to be available at compile-time and no configuration is needed.
280+
281+
Log4j Core::
282+
The logging implementation is responsible for filtering, routing, encoding, and appending log events.
283+
This needs to be available at runtime and configured by the user.
269284
So your dependencies and their dependencies too.
270285
While deploying your application, you need to provide a **logging implementation** along with its configuration to consume all generated log events.
271286
287+
[#config-app]
288+
== How do I configure Log4j to run my **application**?
289+
290+
The following section describes, how an application can be configured to use Log4j.
291+
It will add a configuration and some other artifacts to your application.
292+
The configuration shown here enhances the security and usability of your application.
293+
272294
[IMPORTANT]
273295
====
274296
Are you implementing not an **application**, but a **library**?
275297
Please skip to the xref:#config-lib[] instead.
276298
====
277299
278-
Add the `log4j-core` **runtime** dependency to your application:
300+
As mentioned, Log4j is using a logging API.
301+
First of all, add the `log4j-core` **runtime** dependency to our application.
302+
Second, it is highly recommended to add the `log4j-layout-template-json` **runtime** dependency to encode log events in JSON.
303+
This is the most secure way to format log events and should preferred over the default `PatternLayout`.
279304
280305
[tabs]
281306
====
@@ -284,8 +309,7 @@ Maven::
284309
[source,xml,subs="+attributes"]
285310
----
286311
<project>
287-
288-
<!-- Assuming you already have the `dependencyManagement > dependencies > dependency` entry for `log4j-bom` -->
312+
<!-- Assuming `log4j-bom` is already added -->
289313
290314
<dependency>
291315
@@ -302,14 +326,6 @@ Maven::
302326
<artifactId>log4j-layout-template-json</artifactId>
303327
<scope>runtime</scope><!--1-->
304328
</dependency>
305-
306-
<!-- SLF4J-to-Log4j bridge --><!--2-->
307-
<dependency>
308-
<groupId>org.apache.logging.log4j</groupId>
309-
<artifactId>log4j-slf4j2-impl</artifactId>
310-
<scope>runtime</scope><!--1-->
311-
</dependency>
312-
313329
</dependency>
314330
315331
</project>
@@ -321,26 +337,26 @@ Gradle::
321337
----
322338
dependencies {
323339
324-
// Assuming you already have the `implementation platform(...)` entry for `log4j-bom`
340+
// Assuming `log4j-bom` is already added
325341
326342
// The logging implementation (i.e., Log4j Core)
327343
runtimeOnly 'org.apache.logging.log4j:log4j-core' // <1>
328344
329345
// Log4j JSON-encoding support
330346
runtimeOnly 'org.apache.logging.log4j:log4j-layout-template-json' // <1>
331-
332-
// SLF4J-to-Log4j bridge // <2>
333-
runtimeOnly 'org.apache.logging.log4j:log4j-slf4j2-impl' // <1>
334-
335347
}
336348
----
337349
====
338-
<1> Note that the logging implementation and bridges are only needed at runtime!
339-
<2> SLF4J is another widely used logging API.
340-
`log4j-slf4j2-impl` forwards SLF4J calls to Log4j API, which effectively gets processed by Log4j Core too.
350+
<1> Note that the logging implementation and bridges are only needed at runtime.
341351
342352
Now it is time to configure Log4j and instruct how the log events should be routed.
343-
Save the following XML document to `src/**main**/resources/log4j2.xml`:
353+
Save the following XML document to `src/**main**/resources/log4j2.xml`.
354+
355+
The xref:manual/json-template-layout.adoc[JSON Template Layout] is used to encode log events in JSON.
356+
Once encoded xref:manual/appenders.adoc[Appenders] are responsible for writing log events to the console, file, socket, database, etc.
357+
358+
The `<logger>` defines, that log events generated by classes in the `com.mycompany` package (incl. its sub-packages) and that are of level `INFO` and higher (i.e., `WARN`, `ERROR`, `FATAL`) will be consumed.
359+
Finally, the `<root>` logger defines that log events of level `WARN` and higher will be consumed unless specified otherwise. It serves as a default configuration.
344360
345361
.An example `src/**main**/resources/log4j2.xml`
346362
[source,xml]
@@ -367,16 +383,62 @@ Save the following XML document to `src/**main**/resources/log4j2.xml`:
367383
368384
</Configuration>
369385
----
370-
<1> xref:manual/appenders.adoc[Appenders] are responsible for writing log events to the console, file, socket, database, etc.
371-
<2> xref:manual/appenders.adoc#ConsoleAppender[Console Appender] is used to write logs to the console.
372-
<3> xref:manual/json-template-layout.adoc[JSON Template Layout] is used to encode log events in JSON.
373-
<4> Log events generated by classes in the `com.mycompany` package (incl. its sub packages) and that are of level `INFO` and higher (i.e., `WARN`, `ERROR`, `FATAL`) will be consumed.
386+
<1> xref:manual/appenders.adoc[Appenders] are responsible for writing log events to their target
387+
<2> xref:manual/appenders.adoc#ConsoleAppender[Console Appender] writes logs to the console.
388+
<3> xref:manual/json-template-layout.adoc[JSON Template Layout] encodes log events in JSON.
389+
<4> Log events generated by classes in the `com.mycompany` package (incl. its sub-packages) that are of level `INFO` and higher will be consumed.
374390
<5> Unless specified otherwise, log events of level `WARN` and higher will be consumed.
375391
<6> Unless specified otherwise, log events will be forwarded to the `console` appender defined earlier.
376392
377-
You are strongly advised to use a different Log4j configuration for tests.
393+
If you want to configure Log4j for tests, you are strongly advised to use a different Log4j configuration.
378394
Continue to xref:#config-test[]
379395
396+
In many cases, you might have a library that logs through SLF4J.
397+
Due to the separation of Log4js API and Core, you can add a bridge to forward SLF4J calls to the Log4j API.
398+
This way, SLF4J calls will be processed by Log4j Core too.
399+
400+
It is similarly easy: just add the new dependency `log4j-slf4j2-impl to your application.
401+
402+
[tabs]
403+
====
404+
Maven::
405+
+
406+
[source,xml,subs="+attributes"]
407+
----
408+
<project>
409+
<!-- Other dependencies -->
410+
411+
<dependency>
412+
<!-- SLF4J-to-Log4j bridge --><!--2-->
413+
<dependency>
414+
<groupId>org.apache.logging.log4j</groupId>
415+
<artifactId>log4j-slf4j2-impl</artifactId>
416+
<scope>runtime</scope><!--1-->
417+
</dependency>
418+
419+
</dependency>
420+
421+
</project>
422+
----
423+
424+
Gradle::
425+
+
426+
[source,groovy,subs="+attributes"]
427+
----
428+
dependencies {
429+
// Other dependencies
430+
431+
// SLF4J-to-Log4j bridge // <2>
432+
runtimeOnly 'org.apache.logging.log4j:log4j-slf4j2-impl' // <1>
433+
434+
}
435+
----
436+
====
437+
<1> Again, we only need a runtime dependency.
438+
<2> This dependency will forward SLF4J calls to the Log4j API.
439+
440+
`log4j-slf4j2-impl` forwards SLF4J calls to Log4j API, which effectively gets processed by Log4j Core too.
441+
380442
[#config-lib]
381443
== How do I configure Log4j for my **library**?
382444
@@ -390,7 +452,9 @@ Are you implementing not a **library**, but an **application**?
390452
Please skip to the xref:#config-app[] instead.
391453
====
392454
393-
Add the `log4j-core` **test** dependency to your library:
455+
Add the `log4j-core` dependency in **test** scope to your library.
456+
Very similar to the previous section, in most cases it is useful to also add the `log4j-slf4j2-impl` dependency.
457+
SLF4J is a widely used logging API and this way, SLF4J calls will be processed by Log4j Core too.
394458
395459
[tabs]
396460
====
@@ -399,8 +463,7 @@ Maven::
399463
[source,xml,subs="+attributes"]
400464
----
401465
<project>
402-
403-
<!-- Assuming you already have the `dependencyManagement > dependencies > dependency` entry for `log4j-bom` -->
466+
<!-- Assuming `log4j-bom` is already added -->
404467
405468
<dependency>
406469
@@ -429,7 +492,7 @@ Gradle::
429492
----
430493
dependencies {
431494
432-
// Assuming you already have the `implementation platform(...)` entry for `log4j-bom`
495+
// Assuming `log4j-bom` is already added
433496
434497
// The logging implementation (i.e., Log4j Core)
435498
testRuntimeOnly 'org.apache.logging.log4j:log4j-core' // <1>
@@ -451,7 +514,14 @@ See xref:#config-test[]
451514
== How do I configure Log4j for tests?
452515
453516
For tests, prefer a human-readable layout with increased verbosity.
454-
Save the following XML document to `src/**test**/resources/log4j2-test.xml`:
517+
While it is not recommended to use the `PatternLayout` in production for security reasons, it is a good choice for tests.
518+
Save the following XML document to `src/**test**/resources/log4j2-test.xml`.
519+
520+
The xref:manual/layouts.adoc#PatternLayout[Pattern Layout] is used for formatting strings in a specific way.
521+
In the below case, it will include the timestamp, thread name, log level, class name, and the message and
522+
print it to the Console.
523+
Very similar to the earlier configuration, the `<logger>` defines what should be logged on
524+
which level and the `<root>` logger serves as a default configuration.
455525
456526
.An example `src/**test**/resources/log4j2-test.xml`
457527
[source,xml]
@@ -484,6 +554,9 @@ Save the following XML document to `src/**test**/resources/log4j2-test.xml`:
484554
[#next]
485555
== What is next?
486556
557+
More details::
558+
If you are looking for a more detailed read, please see {logging-services-url}/what-is-logging.html[What is logging?].
559+
487560
Installation::
488561
While shared dependency management snippets should get you going, your case might necessitate a more intricate setup.
489562
Are you dealing with a Spring Boot application?

0 commit comments

Comments
 (0)