Skip to content

Commit b9b5441

Browse files
authored
Revamp the explanation on creating loggers (#79)
1 parent 5c844a2 commit b9b5441

File tree

1 file changed

+110
-24
lines changed

1 file changed

+110
-24
lines changed

src/site/antora/modules/ROOT/pages/index.adoc

Lines changed: 110 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -45,77 +45,163 @@ You need to have the `org.apache.logging.log4j:log4j-api-kotlin` dependency in y
4545
4646
Java module name and OSGi `Bundle-SymbolicName` are set to `org.apache.logging.log4j.api.kotlin`.
4747
48-
[#usage]
49-
== Usage
48+
[#create-loggers]
49+
== Creating loggers
5050
51-
You can start using the wrapper by extending from the provided `Logging` interface:
51+
A `Logger` is the primary interface that users interact with Log4j Kotlin.
52+
You can create ``Logger``s particularly in two ways:
53+
54+
* <<class-loggers,Associate them with the class>> (*Recommended!*)
55+
* <<instance-loggers,Associate them with the instance>>
56+
57+
[#class-loggers]
58+
=== [[usage]] Creating class loggers
59+
60+
For most applications, we recommend you to create *a single logger instance per class definition* – not <<instance-loggers,per class instance>>!
61+
This not only avoids creating an extra logger field for each instance, its access pattern transparently communicates the implementation: the `Logger` is statically bound to the class definition.
62+
You can create class loggers in one of following ways:
63+
64+
[#create-companion-logger]
65+
==== Creating a logger in the companion object
66+
67+
This is the traditional approach to create class loggers.
68+
It also happens to be the most efficient one, since the logger lookup is performed once and its result is stored in the companion object shared by all instances of the class.
5269
5370
[source,kotlin]
5471
----
55-
import org.apache.logging.log4j.kotlin.Logging
72+
import org.apache.logging.log4j.kotlin.logger
73+
74+
class DbTableService {
75+
76+
companion object {
5677
57-
class MyClass: BaseClass, Logging {
78+
private val LOGGER = logger() // <1>
5879
59-
fun doStuff() {
60-
logger.info("Doing stuff")
6180
}
6281
63-
fun doStuffWithUser(user: User) {
64-
logger.info { "Doing stuff with ${user.name}." }
82+
fun truncateTable(tableName: String) {
83+
LOGGER.warn { "truncating table `${tableName}`" }
84+
db.truncate(tableName)
6585
}
6686
6787
}
6888
----
89+
<1> Create a `Logger` associated with the static class definition that all instances of the class share
6990
70-
The `Logging` interface can also be mixed into `object` declarations, including companions.
71-
This is generally preferable over the previous approach as there is a single logger created for every instance of the class.
91+
[#extend-companion]
92+
==== Extending companion object from `Logging`
93+
94+
`Logging` interface contains a `logger` getter that you can use by extending the companion object from the `Logging` class:
7295
7396
[source,kotlin]
7497
----
7598
import org.apache.logging.log4j.kotlin.Logging
7699
77-
class MyClass: BaseClass {
100+
class DbTableService {
78101
79-
companion object : Logging
102+
companion object: Logging // <1>
80103
81-
// ...
104+
fun truncateTable(tableName: String) {
105+
logger.warn { "truncating table `${tableName}`" }
106+
db.truncate(tableName)
107+
}
82108
83109
}
84110
----
111+
<1> Extending the companion object from `Logging` effectively creates a single `Logger` instance
112+
. Assigned to the `logger` field
113+
. Associated with the static class definition that all instances of the class share
114+
115+
[NOTE]
116+
====
117+
This getter-based approach incurs an extra overhead (compared to <<create-companion-logger>>) due to the logger lookup involved at runtime.
118+
====
85119
86-
Alternatively, a more traditional style can be used to instantiate a logger instance:
120+
[#instance-loggers]
121+
=== Creating instance loggers
122+
123+
Even though we recommend you to <<class-loggers,create class loggers>>, there might be occasions (most notably while {logging-services-url}/log4j/2.x/manual/webapp.html#log-separation[sharing classes in Jakarta EE environments]) necessitating loggers associated with each instance.
124+
You can achieve this as follows:
125+
126+
[#create-instance-logger]
127+
==== Creating a logger in the class
128+
129+
This is the traditional approach to create instance loggers.
130+
It also happens to be the most efficient one, since the logger lookup is performed once and its result is stored in the instance field.
87131
88132
[source,kotlin]
89133
----
90134
import org.apache.logging.log4j.kotlin.logger
91135
92-
class MyClass: BaseClass {
136+
class DbTableService {
93137
94-
val logger = logger()
138+
private val logger = logger() // <1>
95139
96-
// ...
140+
fun truncateTable(tableName: String) {
141+
logger.warn { "truncating table `${tableName}`" }
142+
db.truncate(tableName)
143+
}
97144
98145
}
99146
----
147+
<1> Create a `Logger` associated with the class instance
100148
101-
The function `logger()` is an extension function on the `Any` type (or more specifically, any type `T` that extends `Any`).
149+
[#extend-instance]
150+
==== Extending the class from `Logging`
102151
103-
Beginning in version 1.3.0, an extension property is also available on classes:
152+
`Logging` interface contains a `logger` getter that you can use by extending the class from `Logging`:
153+
154+
[source,kotlin]
155+
----
156+
import org.apache.logging.log4j.kotlin.Logging
157+
158+
class DbTableService: Logging { // <1>
159+
160+
fun truncateTable(tableName: String) {
161+
logger.warn { "truncating table `${tableName}`" }
162+
db.truncate(tableName)
163+
}
164+
165+
}
166+
----
167+
<1> Extending the class from `Logging` effectively creates a single `Logger` instance
168+
. Assigned to the `logger` field
169+
. Exclusively associated with the class instance (i.e., not shared among instances!)
170+
171+
[NOTE]
172+
====
173+
This getter-based approach incurs an extra overhead (compared to <<create-instance-logger>>) due to the logger lookup involved at runtime.
174+
====
175+
176+
[#logger-extension]
177+
==== Using `logger` extension property
178+
179+
You can use the `logger` extension property to dynamically inject a logger at the spot:
104180
105181
[source,kotlin]
106182
----
107183
import org.apache.logging.log4j.kotlin.logger
108184
109-
class MyClass: BaseClass {
185+
class DbTableService {
110186
111-
fun doStuff() {
112-
logger.info("Hello, world!")
187+
fun truncateTable(tableName: String) {
188+
logger.warn { "truncating table `${tableName}`" } // <1>
189+
db.truncate(tableName)
113190
}
114191
115192
}
116193
----
194+
<1> `logger` will look up the associated `Logger` instance for the encapsulating class
195+
196+
[NOTE]
197+
====
198+
This getter-based approach incurs an extra overhead (compared to <<create-instance-logger>>) due to the logger lookup involved at runtime.
199+
====
200+
201+
[#thread-context]
202+
== Thread context
117203
118-
Also added in version 1.3.0, the `ThreadContext` API has two facade objects provided: `ContextMap` and `ContextStack`.
204+
The `ThreadContext` API has two facade objects provided: `ContextMap` and `ContextStack`.
119205
120206
[source,kotlin]
121207
----

0 commit comments

Comments
 (0)