blob: 2f4c7ce73935c20a2ab0ceca2ebc3656c2322915 [file] [log] [blame]
Matthias Andreas Benkard692f48d2021-08-31 21:06:50 +02001/**
2 * Provides structured logging to standard output according to the Google Cloud Logging
3 * specification.
Matthias Andreas Benkard42da9f12021-09-02 18:47:28 +02004 *
5 * <ul>
6 * <li><a href="#sect-summary">Summary</a>
7 * <li><a href="#sect-activation">Activation</a>
8 * <li><a href="#sect-usage">Usage</a>
9 * </ul>
10 *
11 * <h2 id="sect-summary">Summary</h2>
12 *
13 * <p>This package contains a log formatter for JBoss Logging in the form of a Quarkus plugin that
14 * implements the <a href="https://cloud.google.com/logging/docs/structured-logging">Google Cloud
15 * Logging JSON format</a> on standard output.
16 *
17 * <p>It is possible to log unstructured text, structured data, or a mixture of both depending on
18 * the situation.
19 *
Matthias Andreas Benkard20210242022-01-15 10:39:30 +010020 * <h2 id="sect-activation">Installation</h2>
Matthias Andreas Benkard42da9f12021-09-02 18:47:28 +020021 *
22 * <ul>
Matthias Andreas Benkard20210242022-01-15 10:39:30 +010023 * <li><a href="#sect-installation-maven">Installation with Maven</a>
24 * <li><a href="#sect-installation-gradle">Installation with Gradle</a>
Matthias Andreas Benkard42da9f12021-09-02 18:47:28 +020025 * </ul>
26 *
27 * <p>Add the runtime POM to your dependency list. As long as the JAR is on the classpath at both
28 * build time and runtime, the log formatter automatically registers itself on startup.
29 *
Matthias Andreas Benkard20210242022-01-15 10:39:30 +010030 * <h3 id="sect-installation-maven">Installation with Maven</h3>
Matthias Andreas Benkard42da9f12021-09-02 18:47:28 +020031 *
32 * <pre>{@code
33 * <project>
34 * ...
35 *
36 * <dependencies>
37 * ...
38 *
39 * <dependency>
40 * <groupId>eu.mulk.quarkus-googlecloud-jsonlogging</groupId>
Matthias Andreas Benkard20210242022-01-15 10:39:30 +010041 * <artifactId>quarkus-googlecloud-jsonlogging-core</artifactId>
42 * <version>4.0.0</version>
Matthias Andreas Benkard42da9f12021-09-02 18:47:28 +020043 * </dependency>
44 *
45 * ...
46 * </dependencies>
47 *
48 * ...
49 * </project>
50 * }</pre>
51 *
Matthias Andreas Benkard20210242022-01-15 10:39:30 +010052 * <h3 id="sect-installation-gradle">Installation with Gradle</h3>
Matthias Andreas Benkard42da9f12021-09-02 18:47:28 +020053 *
54 * <pre>{@code
55 * dependencies {
56 * ...
57 *
Matthias Andreas Benkard20210242022-01-15 10:39:30 +010058 * implementation("eu.mulk.quarkus-googlecloud-jsonlogging:quarkus-googlecloud-jsonlogging-core:4.0.0")
Matthias Andreas Benkard42da9f12021-09-02 18:47:28 +020059 *
60 * ...
61 * }
62 * }</pre>
63 *
64 * <h2 id="sect-usage">Usage</h2>
65 *
66 * <ul>
67 * <li><a href="#sect-usage-parameter">Using Label and StructuredParameter</a>
68 * <li><a href="#sect-usage-provider">Using LabelProvider and StructuredParameterProvider</a>
69 * <li><a href="#sect-usage-mdc">Using the Mapped Diagnostic Context</a>
70 * </ul>
71 *
72 * <p>Logging unstructured data requires no code changes. All logs are automatically converted to
73 * Google-Cloud-Logging-compatible JSON.
74 *
75 * <p>Structured data can be logged in one of 3 different ways: by passing {@link
76 * eu.mulk.quarkus.googlecloud.jsonlogging.Label}s and {@link
77 * eu.mulk.quarkus.googlecloud.jsonlogging.StructuredParameter}s as parameters to individual log
78 * entries, by supplying {@link eu.mulk.quarkus.googlecloud.jsonlogging.LabelProvider}s and {@link
79 * eu.mulk.quarkus.googlecloud.jsonlogging.StructuredParameterProvider}s, or by using the Mapped
80 * Diagnostic Context.
81 *
82 * <h3 id="sect-usage-parameter">Using Label and StructuredParameter</h3>
83 *
84 * <p>Instances of {@link eu.mulk.quarkus.googlecloud.jsonlogging.Label} and {@link
85 * eu.mulk.quarkus.googlecloud.jsonlogging.StructuredParameter} can be passed as log parameters to
86 * the {@code *f} family of logging functions on JBoss Logging's {@link org.jboss.logging.Logger}.
87 *
88 * <p>Simple key–value pairs are represented by {@link
89 * eu.mulk.quarkus.googlecloud.jsonlogging.KeyValueParameter}.
90 *
91 * <p><strong>Example:</strong>
92 *
93 * <pre>{@code
94 * logger.logf(
95 * "Request rejected: unauthorized.",
96 * Label.of("requestId", "123"),
97 * KeyValueParameter.of("resource", "/users/mulk"),
98 * KeyValueParameter.of("method", "PATCH"),
99 * KeyValueParameter.of("reason", "invalid token"));
100 * }</pre>
101 *
102 * Result:
103 *
104 * <pre>{@code
105 * {
106 * "jsonPayload": {
107 * "message": "Request rejected: unauthorized.",
108 * "resource": "/users/mulk",
109 * "method": "PATCH",
110 * "reason": "invalid token"
111 * },
112 * "labels": {
113 * "requestId": "123"
114 * }
115 * }
116 * }</pre>
117 *
118 * <h3 id="sect-usage-provider">Using LabelProvider and StructuredParameterProvider</h3>
119 *
Matthias Andreas Benkard20210242022-01-15 10:39:30 +0100120 * <p>If you pass {@link eu.mulk.quarkus.googlecloud.jsonlogging.LabelProvider}s and {@link
121 * eu.mulk.quarkus.googlecloud.jsonlogging.StructuredParameterProvider}s to {@link
122 * eu.mulk.quarkus.googlecloud.jsonlogging.Formatter}, then they are consulted to provide labels and
123 * parameters for each message that is logged. This can be used to provide contextual information
124 * such as tracing and request IDs stored in thread-local storage.
125 *
126 * <p>If you are using the Quarkus extension, CDI beans that implement these interfaces are
127 * automatically detected at build time and passed to the formatter on startup.
Matthias Andreas Benkard42da9f12021-09-02 18:47:28 +0200128 *
129 * <p><strong>Example:</strong>
130 *
131 * <pre>{@code
132 * @Singleton
133 * @Unremovable
134 * public final class TraceLogParameterProvider implements StructuredParameterProvider, LabelProvider {
135 *
136 * @Override
137 * public StructuredParameter getParameter() {
138 * var b = Json.createObjectBuilder();
139 * b.add("traceId", Span.current().getSpanContext().getTraceId());
140 * b.add("spanId", Span.current().getSpanContext().getSpanId());
141 * return () -> b;
142 * }
143 *
144 * @Override
145 * public Collection<Label> getLabels() {
146 * return List.of(Label.of("requestId", "123"));
147 * }
148 * }
149 * }</pre>
150 *
151 * Result:
152 *
153 * <pre>{@code
154 * {
155 * "jsonPayload": {
156 * "message": "Request rejected: unauthorized.",
157 * "traceId": "39f9a49a9567a8bd7087b708f8932550",
158 * "spanId": "c7431b14630b633d"
159 * },
160 * "labels": {
161 * "requestId": "123"
162 * }
163 * }
164 * }</pre>
165 *
166 * <h3 id="sect-usage-mdc">Using the Mapped Diagnostic Context</h3>
167 *
168 * <p>Any key–value pairs in JBoss Logging's thread-local {@link org.jboss.logging.MDC} are added to
169 * the resulting JSON.
170 *
171 * <p><strong>Example:</strong>
172 *
173 * <pre>{@code
174 * MDC.put("resource", "/users/mulk");
175 * MDC.put("method", "PATCH");
176 * logger.logf("Request rejected: unauthorized.");
177 * }</pre>
178 *
179 * Result:
180 *
181 * <pre>{@code
182 * {
183 * "jsonPayload": {
184 * "message": "Request rejected: unauthorized.",
185 * "resource": "/users/mulk",
186 * "method": "PATCH"
187 * }
188 * }
189 * }</pre>
Matthias Andreas Benkard692f48d2021-08-31 21:06:50 +0200190 */
191package eu.mulk.quarkus.googlecloud.jsonlogging;