blob: 506ba638ca8752aede2539093856395c539fb686 [file] [log] [blame]
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +02001= Quarkus Google Cloud JSON Logging
2Matthias Andreas Benkard
3// Meta
4:experimental:
5:data-uri:
6:sectnums:
7:toc:
8:stem:
9:toclevels: 2
10:description: Quarkus Google Cloud JSON Logging Manual
11:keywords: mulk
12// Settings
13:icons: font
14:source-highlighter: rouge
15
16
17Structured logging to standard output according to the Google Cloud
18Logging specification.
19
20
21== Summary
22
23This package contains a log formatter for JBoss Logging in the form of
24a Quarkus plugin that implements the
25https://cloud.google.com/logging/docs/structured-logging[Google Cloud
26Logging JSON format] on standard output.
27
28It is possible to log unstructured text, structured data, or a mixture
29of both depending on the situation.
30
31
Matthias Andreas Benkard348f2052022-01-15 16:13:01 +010032== Activation (Quarkus)
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +020033
34Add the runtime POM to your dependency list. As long as the JAR is on
35the classpath at both build time and runtime, the log formatter
36automatically registers itself on startup.
37
Matthias Andreas Benkard348f2052022-01-15 16:13:01 +010038If you are using Maven:
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +020039
40[source,xml]
41----
Matthias Andreas Benkard348f2052022-01-15 16:13:01 +010042<dependencies>
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +020043
Matthias Andreas Benkard348f2052022-01-15 16:13:01 +010044 <dependency>
45 <groupId>eu.mulk.quarkus-googlecloud-jsonlogging</groupId>
46 <artifactId>quarkus-googlecloud-jsonlogging</artifactId>
47 <version>4.0.0</version>
48 </dependency>
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +020049
Matthias Andreas Benkard348f2052022-01-15 16:13:01 +010050</dependencies>
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +020051----
52
Matthias Andreas Benkard348f2052022-01-15 16:13:01 +010053If you are using Gradle:
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +020054
55[source,groovy]
56----
57dependencies {
Matthias Andreas Benkard20210242022-01-15 10:39:30 +010058 implementation("eu.mulk.quarkus-googlecloud-jsonlogging:quarkus-googlecloud-jsonlogging:4.0.0")
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +020059}
60----
61
62
Matthias Andreas Benkard348f2052022-01-15 16:13:01 +010063== Activation (Other Frameworks)
64
65If you are not using Quarkus, you can still make use of the `-core`
66module and wire it into your application in a custom way. Read this
67section for hints on how to do so.
68
69
70=== Installation
71
72If you are using Maven:
73
74[source,xml]
75----
76<dependencies>
77
78 <dependency>
79 <groupId>eu.mulk.quarkus-googlecloud-jsonlogging</groupId>
80 <artifactId>quarkus-googlecloud-jsonlogging-core</artifactId>
81 <version>4.0.0</version>
82 </dependency>
83
84</dependencies>
85----
86
87If you are using Gradle:
88
89[source,groovy]
90----
91dependencies {
92 implementation("eu.mulk.quarkus-googlecloud-jsonlogging:quarkus-googlecloud-jsonlogging-core:4.0.0")
93}
94----
95
96
97=== Wiring (Spring Boot)
98
99If you are using Spring Boot, the easiest way to integrate the log
100formatter is by relying on `spring-boot-starter-logging` (which is
101pulled in by `spring-boot-starter`), excluding Logback, and pulling in
102JBoss Log Manager as the back end for SLF4J:
103
104[source,xml]
105----
106
107<dependencies>
108
109 <dependency>
110 <groupId>eu.mulk.quarkus-googlecloud-jsonlogging</groupId>
111 <artifactId>quarkus-googlecloud-jsonlogging-core</artifactId>
112 <version>4.0.0</version>
113 </dependency>
114
115 <dependency>
116 <groupId>org.jboss.slf4j</groupId>
117 <artifactId>slf4j-jboss-logmanager</artifactId>
118 <version>1.1.0.Final</version>
119 </dependency>
120
121 <dependency>
122 <groupId>org.springframework.boot</groupId>
123 <artifactId>spring-boot-starter</artifactId>
124 <exclusions>
125 <exclusion>
126 <groupId>ch.qos.logback</groupId>
127 <artifactId>logback-classic</artifactId>
128 </exclusion>
129 </exclusions>
130 </dependency>
131
132</dependencies>
133----
134
135Create a text file called
136`META-INF/services/org.jboss.logmanager.EmbeddedConfigurator` in your
137`resources` directory and put the fully qualified name of
138`DefaultEmbeddedConfigurator` into it:
139
140[source]
141----
142eu.mulk.quarkus.googlecloud.jsonlogging.logmanager.DefaultEmbeddedConfigurator
143----
144
145To configure `java.util.logging`, which is used by Tomcat by default,
146create an entry in `application.properties` that points to
147`logging.properties`:
148
149[source,properties]
150----
151logging.config = classpath:logging.properties
152----
153
154Create the `logging.properties` file in your `resources` directory and
155name `DefaultConsoleHandler` as a handler:
156
157[source,properties]
158----
159handlers = eu.mulk.quarkus.googlecloud.jsonlogging.logmanager.ConsoleHandler
160----
161
162
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +0200163== Usage
164
165Logging unstructured data requires no code changes. All logs are
166automatically converted to Google-Cloud-Logging-compatible JSON.
167
168Structured data can be logged in one of 3 different ways: by passing
169https://javadocs.dev/eu.mulk.quarkus-googlecloud-jsonlogging/quarkus-googlecloud-jsonlogging/3.1.0/eu.mulk.quarkus.googlecloud.jsonlogging/eu/mulk/quarkus/googlecloud/jsonlogging/Label.html[Label]s
170and
171https://javadocs.dev/eu.mulk.quarkus-googlecloud-jsonlogging/quarkus-googlecloud-jsonlogging/3.1.0/eu.mulk.quarkus.googlecloud.jsonlogging/eu/mulk/quarkus/googlecloud/jsonlogging/StructuredParameter.html[StructuredParameter]s
172as parameters to individual log entries, by supplying
173https://javadocs.dev/eu.mulk.quarkus-googlecloud-jsonlogging/quarkus-googlecloud-jsonlogging/3.1.0/eu.mulk.quarkus.googlecloud.jsonlogging/eu/mulk/quarkus/googlecloud/jsonlogging/LabelProvider.html[LabelProvider]s
174and
175https://javadocs.dev/eu.mulk.quarkus-googlecloud-jsonlogging/quarkus-googlecloud-jsonlogging/3.1.0/eu.mulk.quarkus.googlecloud.jsonlogging/eu/mulk/quarkus/googlecloud/jsonlogging/StructuredParameterProvider.html[StructuredParameterProvider]s,
176or by using the Mapped Diagnostic Context.
177
178
179=== Using Label and StructuredParameter
180
181Instances of
182https://javadocs.dev/eu.mulk.quarkus-googlecloud-jsonlogging/quarkus-googlecloud-jsonlogging/3.1.0/eu.mulk.quarkus.googlecloud.jsonlogging/eu/mulk/quarkus/googlecloud/jsonlogging/Label.html[Label]
183and
184https://javadocs.dev/eu.mulk.quarkus-googlecloud-jsonlogging/quarkus-googlecloud-jsonlogging/3.1.0/eu.mulk.quarkus.googlecloud.jsonlogging/eu/mulk/quarkus/googlecloud/jsonlogging/StructuredParameter.html[StructuredParameter]
185can be passed as log parameters to the `*f` family of logging
186functions on JBoss Logging's
187https://docs.jboss.org/jbosslogging/latest/org/jboss/logging/Logger.html[Logger].
188
189Simple key–value pairs are represented by
190https://javadocs.dev/eu.mulk.quarkus-googlecloud-jsonlogging/quarkus-googlecloud-jsonlogging/3.1.0/eu.mulk.quarkus.googlecloud.jsonlogging/eu/mulk/quarkus/googlecloud/jsonlogging/KeyValueParameter.html[KeyValueParameter].
191
192**Example:**
193
194[source,java]
195----
196logger.logf(
197 "Request rejected: unauthorized.",
198 Label.of("requestId", "123"),
199 KeyValueParameter.of("resource", "/users/mulk"),
200 KeyValueParameter.of("method", "PATCH"),
201 KeyValueParameter.of("reason", "invalid token"));
202----
203
204Result:
205
206[source,json]
207----
208{
209 "jsonPayload": {
210 "message": "Request rejected: unauthorized.",
211 "resource": "/users/mulk",
212 "method": "PATCH",
213 "reason": "invalid token"
214 },
215 "labels": {
216 "requestId": "123"
217 }
218}
219----
220
221
222=== Using LabelProvider and StructuredParameterProvider
223
224Any CDI beans that implement
225https://javadocs.dev/eu.mulk.quarkus-googlecloud-jsonlogging/quarkus-googlecloud-jsonlogging/3.1.0/eu.mulk.quarkus.googlecloud.jsonlogging/eu/mulk/quarkus/googlecloud/jsonlogging/LabelProvider.html[LabelProvider]
226and
227https://javadocs.dev/eu.mulk.quarkus-googlecloud-jsonlogging/quarkus-googlecloud-jsonlogging/3.1.0/eu.mulk.quarkus.googlecloud.jsonlogging/eu/mulk/quarkus/googlecloud/jsonlogging/StructuredParameterProvider.html[StructuredParameterProvider]
228are discovered at build time and consulted to provide labels and
229parameters for each message that is logged. This can be used to
230provide contextual information such as tracing and request IDs stored
231in thread-local storage.
232
Matthias Andreas Benkard93ecfd12022-01-15 14:03:41 +0100233Alternatively, you can also register providers through the Java
234https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/ServiceLoader.html[ServiceLoader]
235mechanism.
236
Matthias Andreas Benkard37e804b2021-09-04 22:38:08 +0200237**Example:**
238
239[source,java]
240----
241@Singleton
242@Unremovable
243public final class TraceLogParameterProvider implements StructuredParameterProvider, LabelProvider {
244
245 @Override
246 public StructuredParameter getParameter() {
247 var b = Json.createObjectBuilder();
248 b.add("traceId", Span.current().getSpanContext().getTraceId());
249 b.add("spanId", Span.current().getSpanContext().getSpanId());
250 return () -> b;
251 }
252
253 @Override
254 public Collection<Label> getLabels() {
255 return List.of(Label.of("requestId", "123"));
256 }
257}
258----
259
260Result:
261
262[source,json]
263----
264{
265 "jsonPayload": {
266 "message": "Request rejected: unauthorized.",
267 "traceId": "39f9a49a9567a8bd7087b708f8932550",
268 "spanId": "c7431b14630b633d"
269 },
270 "labels": {
271 "requestId": "123"
272 }
273}
274----
275
276
277=== Using the Mapped Diagnostic Context
278
279Any key–value pairs in JBoss Logging's thread-local
280https://docs.jboss.org/jbosslogging/latest/org/jboss/logging/MDC.html[MDC]
281are added to the resulting JSON.
282
283**Example:**
284
285[source,java]
286----
287MDC.put("resource", "/users/mulk");
288MDC.put("method", "PATCH");
289logger.logf("Request rejected: unauthorized.");
290----
291
292Result:
293
294[source,json]
295----
296{
297 "jsonPayload": {
298 "message": "Request rejected: unauthorized.",
299 "resource": "/users/mulk",
300 "method": "PATCH"
301 }
302}
303----