blob: e8fbaa4f941cb20a76fac8925030a372e69f3eb1 [file] [log] [blame]
Matthias Andreas Benkard80909242022-02-03 20:47:47 +01001// SPDX-FileCopyrightText: © 2021 Matthias Andreas Benkard <code@mail.matthias.benkard.de>
2//
3// SPDX-License-Identifier: GFDL-1.3-or-later
4
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +02005= Quarkus Google Cloud JSON Logging
6Matthias Andreas Benkard
7// Meta
8:experimental:
9:data-uri:
10:sectnums:
11:toc:
12:stem:
13:toclevels: 2
14:description: Quarkus Google Cloud JSON Logging Manual
15:keywords: mulk
16// Settings
17:icons: font
18:source-highlighter: rouge
19
20
21Structured logging to standard output according to the Google Cloud
22Logging specification.
23
24
25== Summary
26
27This package contains a log formatter for JBoss Logging in the form of
28a Quarkus plugin that implements the
29https://cloud.google.com/logging/docs/structured-logging[Google Cloud
30Logging JSON format] on standard output.
31
32It is possible to log unstructured text, structured data, or a mixture
33of both depending on the situation.
34
35
Matthias Andreas Benkard348f2052022-01-15 16:13:01 +010036== Activation (Quarkus)
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +020037
38Add the runtime POM to your dependency list. As long as the JAR is on
39the classpath at both build time and runtime, the log formatter
40automatically registers itself on startup.
41
Matthias Andreas Benkard348f2052022-01-15 16:13:01 +010042If you are using Maven:
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +020043
44[source,xml]
45----
Matthias Andreas Benkard348f2052022-01-15 16:13:01 +010046<dependencies>
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +020047
Matthias Andreas Benkard348f2052022-01-15 16:13:01 +010048 <dependency>
49 <groupId>eu.mulk.quarkus-googlecloud-jsonlogging</groupId>
50 <artifactId>quarkus-googlecloud-jsonlogging</artifactId>
Matthias Andreas Benkard62ee2f52022-10-05 07:57:02 +020051 <version>5.0.0</version>
Matthias Andreas Benkard348f2052022-01-15 16:13:01 +010052 </dependency>
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +020053
Matthias Andreas Benkard348f2052022-01-15 16:13:01 +010054</dependencies>
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +020055----
56
Matthias Andreas Benkard348f2052022-01-15 16:13:01 +010057If you are using Gradle:
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +020058
59[source,groovy]
60----
61dependencies {
Matthias Andreas Benkard62ee2f52022-10-05 07:57:02 +020062 implementation("eu.mulk.quarkus-googlecloud-jsonlogging:quarkus-googlecloud-jsonlogging:5.0.0")
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +020063}
64----
65
Matthias Andreas Benkard090b8852022-09-03 18:23:23 +020066By default the extension is turned on. You can turn the extension on
67or off explicitly by configuring the `quarkus.log.console.google` key
68in `application.properties`:
69
70[source,properties]
71----
72quarkus.log.console.google = true
73----
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +020074
Matthias Andreas Benkard348f2052022-01-15 16:13:01 +010075== Activation (Other Frameworks)
76
77If you are not using Quarkus, you can still make use of the `-core`
78module and wire it into your application in a custom way. Read this
79section for hints on how to do so.
80
81
82=== Installation
83
84If you are using Maven:
85
86[source,xml]
87----
88<dependencies>
89
90 <dependency>
91 <groupId>eu.mulk.quarkus-googlecloud-jsonlogging</groupId>
92 <artifactId>quarkus-googlecloud-jsonlogging-core</artifactId>
Matthias Andreas Benkard62ee2f52022-10-05 07:57:02 +020093 <version>5.0.0</version>
Matthias Andreas Benkard348f2052022-01-15 16:13:01 +010094 </dependency>
95
96</dependencies>
97----
98
99If you are using Gradle:
100
101[source,groovy]
102----
103dependencies {
Matthias Andreas Benkard62ee2f52022-10-05 07:57:02 +0200104 implementation("eu.mulk.quarkus-googlecloud-jsonlogging:quarkus-googlecloud-jsonlogging-core:5.0.0")
Matthias Andreas Benkard348f2052022-01-15 16:13:01 +0100105}
106----
107
108
109=== Wiring (Spring Boot)
110
111If you are using Spring Boot, the easiest way to integrate the log
112formatter is by relying on `spring-boot-starter-logging` (which is
113pulled in by `spring-boot-starter`), excluding Logback, and pulling in
114JBoss Log Manager as the back end for SLF4J:
115
116[source,xml]
117----
118
119<dependencies>
120
121 <dependency>
122 <groupId>eu.mulk.quarkus-googlecloud-jsonlogging</groupId>
123 <artifactId>quarkus-googlecloud-jsonlogging-core</artifactId>
Matthias Andreas Benkard62ee2f52022-10-05 07:57:02 +0200124 <version>5.0.0</version>
Matthias Andreas Benkard348f2052022-01-15 16:13:01 +0100125 </dependency>
126
127 <dependency>
128 <groupId>org.jboss.slf4j</groupId>
129 <artifactId>slf4j-jboss-logmanager</artifactId>
130 <version>1.1.0.Final</version>
131 </dependency>
132
133 <dependency>
134 <groupId>org.springframework.boot</groupId>
135 <artifactId>spring-boot-starter</artifactId>
136 <exclusions>
137 <exclusion>
138 <groupId>ch.qos.logback</groupId>
139 <artifactId>logback-classic</artifactId>
140 </exclusion>
141 </exclusions>
142 </dependency>
143
144</dependencies>
145----
146
147Create a text file called
148`META-INF/services/org.jboss.logmanager.EmbeddedConfigurator` in your
149`resources` directory and put the fully qualified name of
150`DefaultEmbeddedConfigurator` into it:
151
152[source]
153----
154eu.mulk.quarkus.googlecloud.jsonlogging.logmanager.DefaultEmbeddedConfigurator
155----
156
157To configure `java.util.logging`, which is used by Tomcat by default,
158create an entry in `application.properties` that points to
159`logging.properties`:
160
161[source,properties]
162----
163logging.config = classpath:logging.properties
164----
165
166Create the `logging.properties` file in your `resources` directory and
167name `DefaultConsoleHandler` as a handler:
168
169[source,properties]
170----
Matthias Andreas Benkarddb2440e2022-10-23 12:04:13 +0200171handlers = eu.mulk.quarkus.googlecloud.jsonlogging.logmanager.DefaultConsoleHandler
Matthias Andreas Benkard348f2052022-01-15 16:13:01 +0100172----
173
174
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +0200175== Usage
176
177Logging unstructured data requires no code changes. All logs are
178automatically converted to Google-Cloud-Logging-compatible JSON.
179
180Structured data can be logged in one of 3 different ways: by passing
Matthias Andreas Benkard62ee2f52022-10-05 07:57:02 +0200181https://javadocs.dev/eu.mulk.quarkus-googlecloud-jsonlogging/quarkus-googlecloud-jsonlogging-core/5.0.0/eu.mulk.quarkus.googlecloud.jsonlogging.core/eu/mulk/quarkus/googlecloud/jsonlogging/Label.html[Label]s
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +0200182and
Matthias Andreas Benkard62ee2f52022-10-05 07:57:02 +0200183https://javadocs.dev/eu.mulk.quarkus-googlecloud-jsonlogging/quarkus-googlecloud-jsonlogging-core/5.0.0/eu.mulk.quarkus.googlecloud.jsonlogging.core/eu/mulk/quarkus/googlecloud/jsonlogging/StructuredParameter.html[StructuredParameter]s
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +0200184as parameters to individual log entries, by supplying
Matthias Andreas Benkard62ee2f52022-10-05 07:57:02 +0200185https://javadocs.dev/eu.mulk.quarkus-googlecloud-jsonlogging/quarkus-googlecloud-jsonlogging-core/5.0.0/eu.mulk.quarkus.googlecloud.jsonlogging.core/eu/mulk/quarkus/googlecloud/jsonlogging/LabelProvider.html[LabelProvider]s
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +0200186and
Matthias Andreas Benkard62ee2f52022-10-05 07:57:02 +0200187https://javadocs.dev/eu.mulk.quarkus-googlecloud-jsonlogging/quarkus-googlecloud-jsonlogging-core/5.0.0/eu.mulk.quarkus.googlecloud.jsonlogging.core/eu/mulk/quarkus/googlecloud/jsonlogging/StructuredParameterProvider.html[StructuredParameterProvider]s,
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +0200188or by using the Mapped Diagnostic Context.
189
190
191=== Using Label and StructuredParameter
192
193Instances of
Matthias Andreas Benkard62ee2f52022-10-05 07:57:02 +0200194https://javadocs.dev/eu.mulk.quarkus-googlecloud-jsonlogging/quarkus-googlecloud-jsonlogging-core/5.0.0/eu.mulk.quarkus.googlecloud.jsonlogging.core/eu/mulk/quarkus/googlecloud/jsonlogging/Label.html[Label]
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +0200195and
Matthias Andreas Benkard62ee2f52022-10-05 07:57:02 +0200196https://javadocs.dev/eu.mulk.quarkus-googlecloud-jsonlogging/quarkus-googlecloud-jsonlogging-core/5.0.0/eu.mulk.quarkus.googlecloud.jsonlogging.core/eu/mulk/quarkus/googlecloud/jsonlogging/StructuredParameter.html[StructuredParameter]
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +0200197can be passed as log parameters to the `*f` family of logging
198functions on JBoss Logging's
199https://docs.jboss.org/jbosslogging/latest/org/jboss/logging/Logger.html[Logger].
200
201Simple key–value pairs are represented by
Matthias Andreas Benkard62ee2f52022-10-05 07:57:02 +0200202https://javadocs.dev/eu.mulk.quarkus-googlecloud-jsonlogging/quarkus-googlecloud-jsonlogging-core/5.0.0/eu.mulk.quarkus.googlecloud.jsonlogging.core/eu/mulk/quarkus/googlecloud/jsonlogging/KeyValueParameter.html[KeyValueParameter].
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +0200203
204**Example:**
205
206[source,java]
207----
208logger.logf(
209 "Request rejected: unauthorized.",
210 Label.of("requestId", "123"),
211 KeyValueParameter.of("resource", "/users/mulk"),
212 KeyValueParameter.of("method", "PATCH"),
213 KeyValueParameter.of("reason", "invalid token"));
214----
215
216Result:
217
218[source,json]
219----
220{
221 "jsonPayload": {
222 "message": "Request rejected: unauthorized.",
223 "resource": "/users/mulk",
224 "method": "PATCH",
225 "reason": "invalid token"
226 },
227 "labels": {
228 "requestId": "123"
229 }
230}
231----
232
233
234=== Using LabelProvider and StructuredParameterProvider
235
236Any CDI beans that implement
Matthias Andreas Benkard62ee2f52022-10-05 07:57:02 +0200237https://javadocs.dev/eu.mulk.quarkus-googlecloud-jsonlogging/quarkus-googlecloud-jsonlogging-core/5.0.0/eu.mulk.quarkus.googlecloud.jsonlogging.core/eu/mulk/quarkus/googlecloud/jsonlogging/LabelProvider.html[LabelProvider]
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +0200238and
Matthias Andreas Benkard62ee2f52022-10-05 07:57:02 +0200239https://javadocs.dev/eu.mulk.quarkus-googlecloud-jsonlogging/quarkus-googlecloud-jsonlogging-core/5.0.0/eu.mulk.quarkus.googlecloud.jsonlogging.core/eu/mulk/quarkus/googlecloud/jsonlogging/StructuredParameterProvider.html[StructuredParameterProvider]
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +0200240are discovered at build time and consulted to provide labels and
241parameters for each message that is logged. This can be used to
242provide contextual information such as tracing and request IDs stored
243in thread-local storage.
244
Matthias Andreas Benkard93ecfd12022-01-15 14:03:41 +0100245Alternatively, you can also register providers through the Java
246https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/ServiceLoader.html[ServiceLoader]
247mechanism.
248
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +0200249**Example:**
250
251[source,java]
252----
253@Singleton
254@Unremovable
255public final class TraceLogParameterProvider implements StructuredParameterProvider, LabelProvider {
256
257 @Override
258 public StructuredParameter getParameter() {
259 var b = Json.createObjectBuilder();
260 b.add("traceId", Span.current().getSpanContext().getTraceId());
261 b.add("spanId", Span.current().getSpanContext().getSpanId());
262 return () -> b;
263 }
264
265 @Override
266 public Collection<Label> getLabels() {
267 return List.of(Label.of("requestId", "123"));
268 }
269}
270----
271
272Result:
273
274[source,json]
275----
276{
277 "jsonPayload": {
278 "message": "Request rejected: unauthorized.",
279 "traceId": "39f9a49a9567a8bd7087b708f8932550",
280 "spanId": "c7431b14630b633d"
281 },
282 "labels": {
283 "requestId": "123"
284 }
285}
286----
287
288
289=== Using the Mapped Diagnostic Context
290
291Any key–value pairs in JBoss Logging's thread-local
292https://docs.jboss.org/jbosslogging/latest/org/jboss/logging/MDC.html[MDC]
293are added to the resulting JSON.
294
295**Example:**
296
297[source,java]
298----
299MDC.put("resource", "/users/mulk");
300MDC.put("method", "PATCH");
301logger.logf("Request rejected: unauthorized.");
302----
303
304Result:
305
306[source,json]
307----
308{
309 "jsonPayload": {
310 "message": "Request rejected: unauthorized.",
311 "resource": "/users/mulk",
312 "method": "PATCH"
313 }
314}
315----