Skip to content

Commit 45f8d0c

Browse files
cyrille-leclercchalin
authored andcommitted
Fix formatting
1 parent 2312fc7 commit 45f8d0c

File tree

1 file changed

+81
-39
lines changed
  • content/en/blog/2024/collecting-file-based-java-logs-with-opentelemetry

1 file changed

+81
-39
lines changed

content/en/blog/2024/collecting-file-based-java-logs-with-opentelemetry/index.md

+81-39
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,50 @@
11
---
22
title: Collecting file-based Java logs with OpenTelemetry
33
linkTitle: Collecting file-based Java logs with OpenTelemetry
4-
date:
4+
date:
55
author: >
6-
[Cyrille Le Clerc](https://github.com/cyrille-leclerc) (Grafana Labs), [Gregor Zeitlinger](https://github.com/zeitlinger) (Grafana Labs)
6+
[Cyrille Le Clerc](https://github.com/cyrille-leclerc) (Grafana Labs), [Gregor
7+
Zeitlinger](https://github.com/zeitlinger) (Grafana Labs)
78
issue: https://github.com/open-telemetry/opentelemetry.io/issues/5606
89
sig: Java, Specification
910
# prettier-ignore
1011
cSpell:ignore: Clerc cust Cyrille Dotel Gregor Logback logback otlphttp otlpjson resourcedetection SLF4J stdout Zeitlinger
1112
---
12-
If you want to get logs from your Java application ingested into an OpenTelemetry-compatible logs backend, the easiest and recommended way is using an OpenTelemetry protocol (OTLP) exporter.
13-
However, some scenarios require logs to be output to files or stdout due to organizational or reliability needs.
1413

15-
A common approach to centralize logs is to use unstructured logs, parse them with regular expressions, and add contextual attributes.
14+
If you want to get logs from your Java application ingested into an
15+
OpenTelemetry-compatible logs backend, the easiest and recommended way is using
16+
an OpenTelemetry protocol (OTLP) exporter. However, some scenarios require logs
17+
to be output to files or stdout due to organizational or reliability needs.
1618

17-
However, regular expression parsing is problematic. They become complex and fragile quickly when handling all log fields, line breaks in exceptions, and unexpected log format changes. Parsing errors are inevitable with this method.
19+
A common approach to centralize logs is to use unstructured logs, parse them
20+
with regular expressions, and add contextual attributes.
21+
22+
However, regular expression parsing is problematic. They become complex and
23+
fragile quickly when handling all log fields, line breaks in exceptions, and
24+
unexpected log format changes. Parsing errors are inevitable with this method.
1825

1926
## Solution
2027

21-
The OpenTelemetry Java Instrumentation agent and SDK now offer an easy solution to convert logs from frameworks like SLF4J/Logback or Log4j2 into OTel-compliant JSON logs on stdout with all resource and log attributes.
28+
The OpenTelemetry Java Instrumentation agent and SDK now offer an easy solution
29+
to convert logs from frameworks like SLF4J/Logback or Log4j2 into OTel-compliant
30+
JSON logs on stdout with all resource and log attributes.
2231

2332
This is a true turnkey solution:
2433

25-
* No code or dependency changes, just a few configuration adjustments typical for production deployment.
26-
* No complex field mapping in the log collector. Just use the [OTLP/JSON connector](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/connector/otlpjsonconnector) to ingest the payload.
27-
* Automatic correlation between logs, traces, and metrics.
34+
- No code or dependency changes, just a few configuration adjustments typical
35+
for production deployment.
36+
- No complex field mapping in the log collector. Just use the
37+
[OTLP/JSON connector](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/connector/otlpjsonconnector)
38+
to ingest the payload.
39+
- Automatic correlation between logs, traces, and metrics.
2840

2941
This blog post shows how to set up this solution step by step.
3042

31-
* In the first part, we'll show how to configure the Java application to output logs in the OTLP/JSON format.
32-
* In the second part, we'll show how to configure the OpenTelemetry Collector to ingest the logs.
33-
* Finally, we'll show a Kubernetes-specific setup to handle container logs.
43+
- In the first part, we'll show how to configure the Java application to output
44+
logs in the OTLP/JSON format.
45+
- In the second part, we'll show how to configure the OpenTelemetry Collector to
46+
ingest the logs.
47+
- Finally, we'll show a Kubernetes-specific setup to handle container logs.
3448

3549
## Reference architecture
3650

@@ -40,7 +54,8 @@ The deployment architecture looks like the following:
4054

4155
## Configure Java application to output OTLP/JSON logs
4256

43-
No code changes needed. Continue using your preferred logging library, including templated logs, mapped diagnostic context, and structured logging.
57+
No code changes needed. Continue using your preferred logging library, including
58+
templated logs, mapped diagnostic context, and structured logging.
4459

4560
```java
4661
Logger logger = org.slf4j.LoggerFactory.getLogger(MyClass.class);
@@ -55,8 +70,14 @@ logger.atInfo().
5570
.log("placeOrder");
5671
```
5772

58-
Export the logs captured by the OTel Java instrumentation to stdout using the OTel JSON format (aka [OTLP/JSON](https://opentelemetry.io/docs/specs/otlp/#json-protobuf-encoding)).
59-
Configuration parameters for [Logback](https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/logback/logback-appender-1.0/javaagent) and [Log4j](https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/log4j/log4j-appender-2.17/javaagent) are optional but recommended.
73+
Export the logs captured by the OTel Java instrumentation to stdout using the
74+
OTel JSON format (aka
75+
[OTLP/JSON](https://opentelemetry.io/docs/specs/otlp/#json-protobuf-encoding)).
76+
Configuration parameters for
77+
[Logback](https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/logback/logback-appender-1.0/javaagent)
78+
and
79+
[Log4j](https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/log4j/log4j-appender-2.17/javaagent)
80+
are optional but recommended.
6081

6182
```bash
6283
# Tested with opentelemetry-javaagent v2.10.0
@@ -72,16 +93,21 @@ java -javaagent:/path/to/opentelemetry-javaagent.jar \
7293
-jar /path/to/my-app.jar
7394
```
7495

75-
The `-Dotel.logs.exporter=experimental-otlp/stdout` JVM argument and the environment variable `OTEL_LOGS_EXPORTER="experimental-otlp/stdout"` can be used interchangeably.
96+
The `-Dotel.logs.exporter=experimental-otlp/stdout` JVM argument and the
97+
environment variable `OTEL_LOGS_EXPORTER="experimental-otlp/stdout"` can be used
98+
interchangeably.
7699

77100
{{% alert title="Note" color="info" %}}
78101

79-
The OTLP logs exporter is experimental and subject to change.
80-
Check the [Specification PR](https://github.com/open-telemetry/opentelemetry-specification/pull/4183) for the latest updates.
102+
The OTLP logs exporter is experimental and subject to change. Check the
103+
[Specification PR](https://github.com/open-telemetry/opentelemetry-specification/pull/4183)
104+
for the latest updates.
81105

82106
{{% /alert %}}
83107

84-
Verify that OTLP/JSON logs are outputted to stdout. The logs are in the OTLP/JSON format, with a JSON object per line. The log records are nested in the `resourceLogs` array.
108+
Verify that OTLP/JSON logs are outputted to stdout. The logs are in the
109+
OTLP/JSON format, with a JSON object per line. The log records are nested in the
110+
`resourceLogs` array.
85111

86112
```json
87113
{"resourceLogs":[{"resource":{"attributes":[{"key":"deployment.environment.name","value":{"stringValue":"staging"}},{"key":"service.instance.id","value":{"stringValue":"6ad88e10-238c-4fb7-bf97-38df19053366"}},{"key":"service.name","value":{"stringValue":"checkout"}},{"key":"service.namespace","value":{"stringValue":"shop"}},{"key":"service.version","value":{"stringValue":"1.1"}}]},"scopeLogs":[{"scope":{"name":"com.mycompany.checkout.CheckoutServiceServer$CheckoutServiceImpl","attributes":[]},"logRecords":[{"timeUnixNano":"1730435085776869000","observedTimeUnixNano":"1730435085776944000","severityNumber":9,"severityText":"INFO","body":{"stringValue":"Order order-12035 successfully placed"}, "attributes":[{"key":"customerId","value":{"stringValue":"customer-49"}},{"key":"thread.id","value":{"intValue":"44"}},{"key":"thread.name","value":{"stringValue":"grpc-default-executor-1"}}],"flags":1,"traceId":"42de1f0dd124e27619a9f3c10bccac1c","spanId":"270984d03e94bb8b"}]}],"schemaUrl":"https://opentelemetry.io/schemas/1.24.0"}]}
@@ -91,7 +117,8 @@ Verify that OTLP/JSON logs are outputted to stdout. The logs are in the OTLP/JSO
91117

92118
![OpenTelemetry Collector OTLP/JSON pipeline](otel-collector-otlpjson-pipeline.png)
93119

94-
Source: [https://www.otelbin.io/s/69739d790cf279c203fc8efc86ad1a876a2fc01a](https://www.otelbin.io/s/69739d790cf279c203fc8efc86ad1a876a2fc01a)
120+
Source:
121+
[https://www.otelbin.io/s/69739d790cf279c203fc8efc86ad1a876a2fc01a](https://www.otelbin.io/s/69739d790cf279c203fc8efc86ad1a876a2fc01a)
95122

96123
```yaml
97124
# tested with otelcol-contrib v0.112.0
@@ -108,7 +135,7 @@ receivers:
108135
processors:
109136
batch:
110137
resourcedetection:
111-
detectors: ["env", "system"]
138+
detectors: ['env', 'system']
112139
override: false
113140

114141
connectors:
@@ -117,7 +144,7 @@ connectors:
117144
service:
118145
pipelines:
119146
logs/raw_otlpjson:
120-
receivers: [ filelog/otlp-json-logs ]
147+
receivers: [filelog/otlp-json-logs]
121148
# (i) no need for processors before the otlpjson connector
122149
# Declare processors in the shared "logs" pipeline below
123150
processors: []
@@ -135,7 +162,8 @@ exporters:
135162
otlphttp:
136163
```
137164
138-
Verify the logs collected by the OTel Collector by checking the output of the OTel Collector Debug exporter
165+
Verify the logs collected by the OTel Collector by checking the output of the
166+
OTel Collector Debug exporter
139167
140168
```log
141169
2024-11-01T10:03:31.074+0530 info Logs {"kind": "exporter", "data_type": "logs", "name": "debug", "resource logs": 1, "log records": 1}
@@ -170,17 +198,20 @@ Verify the logs in the OpenTelemetry backend.
170198

171199
After the pipeline works end-to-end, ensure production readiness:
172200

173-
* Remove the `debug` exporter from the `logs` pipeline in the OTel Collector configuration.
174-
* Disable file and console exporters in the logging framework (for example, `logback.xml`) but keep using the logging configuration to filter logs. The OTel Java agent will output JSON logs to stdout.
201+
- Remove the `debug` exporter from the `logs` pipeline in the OTel Collector
202+
configuration.
203+
- Disable file and console exporters in the logging framework (for example,
204+
`logback.xml`) but keep using the logging configuration to filter logs. The
205+
OTel Java agent will output JSON logs to stdout.
175206

176207
```xml
177208
<!-- tested with logback-classic v1.5.11 -->
178209
<configuration>
179210
<logger name="com.example" level="debug"/>
180211
<root level="info">
181212
<!-- No appender as the OTel Agent emits otlpjson logs through stdout -->
182-
<!--
183-
IMPORTANT enable a console appender to troubleshoot cases were
213+
<!--
214+
IMPORTANT enable a console appender to troubleshoot cases where
184215
logs are missing in the OTel backend
185216
-->
186217
</root>
@@ -189,21 +220,26 @@ After the pipeline works end-to-end, ensure production readiness:
189220

190221
## Configure an OpenTelemetry Collector in Kubernetes to handle container logs
191222

192-
To support Kubernetes and container specifics, add a standard parsing step in the pipeline without specific mapping configuration.
223+
To support Kubernetes and container specifics, add a standard parsing step in
224+
the pipeline without specific mapping configuration.
193225

194-
Use the OTel Collector File Log Receiver's [`container`](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/pkg/stanza/docs/operators/container.md) parser to handle container logging specifics.
226+
Use the OTel Collector File Log Receiver's
227+
[`container`](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/pkg/stanza/docs/operators/container.md)
228+
parser to handle container logging specifics.
195229

196-
Replace `<<namespace>>`, `<<pod_name>>`, and `<<container_name>>` with the desired values or use a broader [glob pattern](https://pkg.go.dev/v.io/v23/glob) like `*`.
230+
Replace `<<namespace>>`, `<<pod_name>>`, and `<<container_name>>` with the
231+
desired values or use a broader [glob pattern](https://pkg.go.dev/v.io/v23/glob)
232+
like `*`.
197233

198234
```yaml
199235
receivers:
200236
filelog/otlp-json-logs:
201237
# start_at: beginning # for testing purpose, use "start_at: beginning"
202238
include: [/var/log/pods/<<namespace>>_<<pod_name>>_*/<<container_name>>/]
203-
include_file_path: true
239+
include_file_path: true
204240
operators:
205-
- type: container
206-
add_metadata_from_filepath: true
241+
- type: container
242+
add_metadata_from_filepath: true
207243

208244
otlp:
209245
protocols:
@@ -213,7 +249,7 @@ receivers:
213249
processors:
214250
batch:
215251
resourcedetection:
216-
detectors: ["env", "system"]
252+
detectors: ['env', 'system']
217253
override: false
218254

219255
connectors:
@@ -222,7 +258,7 @@ connectors:
222258
service:
223259
pipelines:
224260
logs/raw_otlpjson:
225-
receivers: [ filelog/otlp-json-logs ]
261+
receivers: [filelog/otlp-json-logs]
226262
# (i) no need for processors before the otlpjson connector
227263
# Declare processors in the shared "logs" pipeline below
228264
processors: []
@@ -244,7 +280,13 @@ exporters:
244280
245281
## Conclusion
246282
247-
This blog post showed how to collect file-based Java logs with OpenTelemetry. The solution is easy to set up and provides a turnkey solution for converting logs from frameworks like SLF4J/Logback or Log4j2 into OTel-compliant JSON logs on stdout with all resource and log attributes.
248-
This JSON format is certainly verbose, but it generally has minimal impact on performances and offers a solid balance by providing highly contextualized logs that can be correlated with traces and metrics.
283+
This blog post showed how to collect file-based Java logs with OpenTelemetry.
284+
The solution is easy to set up and provides a turnkey solution for converting
285+
logs from frameworks like SLF4J/Logback or Log4j2 into OTel-compliant JSON logs
286+
on stdout with all resource and log attributes. This JSON format is certainly
287+
verbose, but it generally has minimal impact on performances and offers a solid
288+
balance by providing highly contextualized logs that can be correlated with
289+
traces and metrics.
249290
250-
Any feedback or questions? Reach out on [GitHub](https://github.com/open-telemetry/opentelemetry-specification/pull/4183).
291+
Any feedback or questions? Reach out on
292+
[GitHub](https://github.com/open-telemetry/opentelemetry-specification/pull/4183).

0 commit comments

Comments
 (0)