Skip to content

Commit b40a708

Browse files
committed
feat(javaagent-log-appender): split javaagent-log-appender package
1 parent 4b461f4 commit b40a708

File tree

13 files changed

+322
-30
lines changed

13 files changed

+322
-30
lines changed

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ of them assume you have docker running on your local machine.
3838
- [Configuring Log Appenders](log-appender)
3939
- This module demonstrates how to configure the Log4j and Logback appenders to
4040
bridge logs into the OpenTelemetry Log SDK.
41+
- [Configuring Log Appenders when using JavaAgent](javaagent-log-appender)
42+
- This module demonstrates how to configure the Log4j and Logback appenders to
43+
bridge logs into the OpenTelemetry Log SDK when using JavaAgent.
4144
- [Configuring the Logging Exporters](logging)
4245
- This module contains a fully-functional example of configuring the
4346
OpenTelemetry SDK to use a logging exporter.

javaagent-log-appender/README.md

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# OpenTelemetry Log Appender Example
2+
3+
This example demonstrates an application configured to use the OpenTelemetry Log
4+
Appenders to bridge logs into the OpenTelemetry Log SDK, and export
5+
via [OTLP](https://opentelemetry.io/docs/reference/specification/protocol/otlp/).
6+
7+
Details about the example:
8+
9+
* The OpenTelemetry Log SDK is configured to export data to
10+
the [collector](https://opentelemetry.io/docs/collector/), which prints the
11+
logs to the console.
12+
* The application is configured with a variety of log solutions:
13+
* Log4j API [configured](./src/main/resources/log4j2.xml) to print logs to the
14+
console and
15+
the [OpenTelemetry Log4J Appender](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/instrumentation/log4j/log4j-appender-2.17/library/README.md).
16+
* SLF4J API [configured with Logback](./src/main/resources/logback.xml) to
17+
print logs to the console and
18+
the [OpenTelemetry Logback Appender](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/instrumentation/logback/logback-appender-1.0/library/README.md).
19+
* [JUL to SLF4J](./build.gradle.kts), which bridges JUL logs to the SLF4J API, and
20+
ultimately to Logback.
21+
* Demonstrates how trace context is propagated to logs when recorded within a
22+
span.
23+
24+
## Prerequisites
25+
26+
* Java 1.8
27+
* Docker compose
28+
29+
# How to run
30+
31+
Run the collector via docker
32+
33+
```shell
34+
docker-compose up
35+
```
36+
37+
In a separate shell, run the application
38+
39+
```shell
40+
export \
41+
OTEL_SERVICE_NAME=log4j-example \
42+
OTEL_EXPORTER_OTLP_PROTOCOL=grpc \
43+
OTEL_METRICS_EXPORTER=none \
44+
OTEL_TRACES_EXPORTER=none \
45+
OTEL_LOGS_EXPORTER=otlp
46+
47+
../gradlew run
48+
```
49+
50+
Watch the collector logs to see exported log records
+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
plugins {
2+
id("java")
3+
id("application")
4+
}
5+
6+
description = "OpenTelemetry Log Appender Example using JavaAgent"
7+
val moduleName by extra { "io.opentelemetry.examples.javaagent-log-appender" }
8+
9+
java {
10+
toolchain {
11+
// logback 1.4.x+ requires java 11
12+
languageVersion.set(JavaLanguageVersion.of(11))
13+
}
14+
}
15+
16+
val agent = configurations.create("agent")
17+
18+
dependencies {
19+
// Slf4J / logback
20+
implementation("org.slf4j:slf4j-api:2.0.16")
21+
implementation("ch.qos.logback:logback-core:1.5.9")
22+
implementation("ch.qos.logback:logback-classic:1.5.9")
23+
24+
// JUL to SLF4J bridge
25+
implementation("org.slf4j:jul-to-slf4j:2.0.16")
26+
27+
// Log4j
28+
implementation(platform("org.apache.logging.log4j:log4j-bom:2.24.1"))
29+
implementation("org.apache.logging.log4j:log4j-api")
30+
implementation("org.apache.logging.log4j:log4j-core")
31+
32+
// OpenTelemetry core
33+
implementation("io.opentelemetry:opentelemetry-api")
34+
implementation("io.opentelemetry.semconv:opentelemetry-semconv")
35+
36+
// OpenTelemetry log4j / logback appenders
37+
implementation("io.opentelemetry.instrumentation:opentelemetry-log4j-appender-2.17")
38+
implementation("io.opentelemetry.instrumentation:opentelemetry-logback-appender-1.0")
39+
40+
// OpenTelemetry JavaAgent
41+
agent("io.opentelemetry.javaagent:opentelemetry-javaagent:2.8.0")
42+
}
43+
44+
application {
45+
mainClass = "io.opentelemetry.example.logappender.Application"
46+
}
47+
48+
49+
tasks.named<JavaExec>("run") {
50+
doFirst {
51+
jvmArgs("-javaagent:${agent.singleFile}")
52+
}
53+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
version: '3'
2+
services:
3+
collector:
4+
image: otel/opentelemetry-collector-contrib:0.111.0
5+
volumes:
6+
- ./otel-config.yaml:/otel-config.yaml
7+
command: ["--config=/otel-config.yaml"]
8+
ports:
9+
- "4317:4317"
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
receivers:
2+
otlp:
3+
protocols:
4+
grpc:
5+
endpoint: collector:4317
6+
exporters:
7+
debug:
8+
verbosity: detailed
9+
nop:
10+
service:
11+
pipelines:
12+
logs:
13+
receivers: [otlp]
14+
exporters: [debug]
15+
traces:
16+
receivers: [otlp]
17+
exporters: [debug]
18+
metrics:
19+
receivers: [otlp]
20+
exporters: [nop]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package io.opentelemetry.example.logappender;
2+
3+
import io.opentelemetry.api.GlobalOpenTelemetry;
4+
import io.opentelemetry.api.common.AttributeKey;
5+
import io.opentelemetry.api.logs.Severity;
6+
import io.opentelemetry.api.trace.Span;
7+
import io.opentelemetry.context.Scope;
8+
import java.util.HashMap;
9+
import java.util.Map;
10+
import java.util.logging.Level;
11+
import java.util.logging.Logger;
12+
import org.apache.logging.log4j.LogManager;
13+
import org.apache.logging.log4j.ThreadContext;
14+
import org.apache.logging.log4j.message.MapMessage;
15+
import org.slf4j.LoggerFactory;
16+
import org.slf4j.bridge.SLF4JBridgeHandler;
17+
18+
public class Application {
19+
20+
private static final org.apache.logging.log4j.Logger log4jLogger =
21+
LogManager.getLogger("log4j-logger");
22+
private static final org.slf4j.Logger slf4jLogger = LoggerFactory.getLogger("slf4j-logger");
23+
private static final java.util.logging.Logger julLogger = Logger.getLogger("jul-logger");
24+
25+
public static void main(String[] args) {
26+
// Route JUL logs to slf4j
27+
SLF4JBridgeHandler.removeHandlersForRootLogger();
28+
SLF4JBridgeHandler.install();
29+
30+
// Log using log4j API
31+
maybeRunWithSpan(() -> log4jLogger.info("A log4j log message without a span"), false);
32+
maybeRunWithSpan(() -> log4jLogger.info("A log4j log message with a span"), true);
33+
Map<String, Object> mapMessage = new HashMap<>();
34+
mapMessage.put("key", "value");
35+
mapMessage.put("message", "A log4j structured message");
36+
maybeRunWithSpan(() -> log4jLogger.info(new MapMessage<>(mapMessage)), false);
37+
ThreadContext.clearAll();
38+
maybeRunWithSpan(
39+
() -> log4jLogger.info("A log4j log message with an exception", new Exception("error!")),
40+
false);
41+
42+
// Log using slf4j API w/ logback backend
43+
maybeRunWithSpan(() -> slf4jLogger.info("A slf4j log message without a span"), false);
44+
maybeRunWithSpan(() -> slf4jLogger.info("A slf4j log message with a span"), true);
45+
maybeRunWithSpan(
46+
() ->
47+
slf4jLogger
48+
.atInfo()
49+
.setMessage("A slf4j structured message")
50+
.addKeyValue("key", "value")
51+
.log(),
52+
false);
53+
maybeRunWithSpan(
54+
() -> slf4jLogger.info("A slf4j log message with an exception", new Exception("error!")),
55+
false);
56+
57+
// Log using JUL API, bridged to slf4j, w/ logback backend
58+
maybeRunWithSpan(() -> julLogger.info("A JUL log message without a span"), false);
59+
maybeRunWithSpan(() -> julLogger.info("A JUL log message with a span"), true);
60+
maybeRunWithSpan(
61+
() ->
62+
julLogger.log(
63+
Level.INFO, "A JUL log message with an exception", new Exception("error!")),
64+
false);
65+
66+
// Log using OpenTelemetry Log Bridge API
67+
// WARNING: This illustrates how to write appenders which bridge logs from
68+
// existing frameworks into the OpenTelemetry Log Bridge API. These APIs
69+
// SHOULD NOT be used by end users in place of existing log APIs (i.e. Log4j, Slf4, JUL).
70+
io.opentelemetry.api.logs.Logger customAppenderLogger =
71+
GlobalOpenTelemetry.get().getLogsBridge().get("custom-log-appender");
72+
maybeRunWithSpan(
73+
() ->
74+
customAppenderLogger
75+
.logRecordBuilder()
76+
.setSeverity(Severity.INFO)
77+
.setBody("A log message from a custom appender without a span")
78+
.setAttribute(AttributeKey.stringKey("key"), "value")
79+
.emit(),
80+
false);
81+
maybeRunWithSpan(
82+
() ->
83+
customAppenderLogger
84+
.logRecordBuilder()
85+
.setSeverity(Severity.INFO)
86+
.setBody("A log message from a custom appender with a span")
87+
.setAttribute(AttributeKey.stringKey("key"), "value")
88+
.emit(),
89+
true);
90+
}
91+
92+
private static void maybeRunWithSpan(Runnable runnable, boolean withSpan) {
93+
if (!withSpan) {
94+
runnable.run();
95+
return;
96+
}
97+
Span span = GlobalOpenTelemetry.getTracer("my-tracer").spanBuilder("my-span").startSpan();
98+
try (Scope unused = span.makeCurrent()) {
99+
runnable.run();
100+
} finally {
101+
span.end();
102+
}
103+
}
104+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Configuration status="WARN" packages="io.opentelemetry.instrumentation.log4j.appender.v2_17">
3+
<Appenders>
4+
<Console name="ConsoleAppender" target="SYSTEM_OUT" follow="true">
5+
<PatternLayout pattern="log4j2: %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
6+
</Console>
7+
<OpenTelemetry name="OpenTelemetryAppender" captureMapMessageAttributes="true" captureExperimentalAttributes="true"/>
8+
</Appenders>
9+
<Loggers>
10+
<Root level="info">
11+
<AppenderRef ref="OpenTelemetryAppender" />
12+
<AppenderRef ref="ConsoleAppender" />
13+
</Root>
14+
</Loggers>
15+
</Configuration>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<configuration>
3+
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
4+
<encoder>
5+
<pattern>
6+
logback: %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg %kvp{DOUBLE}%n
7+
</pattern>
8+
</encoder>
9+
</appender>
10+
<appender name="OpenTelemetry"
11+
class="io.opentelemetry.instrumentation.logback.appender.v1_0.OpenTelemetryAppender">
12+
<captureExperimentalAttributes>true</captureExperimentalAttributes>
13+
<captureKeyValuePairAttributes>true</captureKeyValuePairAttributes>
14+
</appender>
15+
<root level="INFO">
16+
<appender-ref ref="console"/>
17+
<appender-ref ref="OpenTelemetry"/>
18+
</root>
19+
</configuration>

log-appender/README.md

-7
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,6 @@ docker-compose up
3737
In a separate shell, run the application
3838

3939
```shell
40-
export \
41-
OTEL_SERVICE_NAME=log4j-example \
42-
OTEL_EXPORTER_OTLP_PROTOCOL=grpc \
43-
OTEL_METRICS_EXPORTER=none \
44-
OTEL_TRACES_EXPORTER=none \
45-
OTEL_LOGS_EXPORTER=otlp
46-
4740
../gradlew run
4841
```
4942

log-appender/build.gradle.kts

+4-15
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ plugins {
33
id("application")
44
}
55

6-
description = "OpenTelemetry Log Appender Example using JavaAgent"
7-
val moduleName by extra { "io.opentelemetry.examples.javaagent-log-appender" }
6+
description = "OpenTelemetry Log Appender Example"
7+
val moduleName by extra { "io.opentelemetry.examples.log-appender" }
88

99
java {
1010
toolchain {
@@ -13,8 +13,6 @@ java {
1313
}
1414
}
1515

16-
val agent = configurations.create("agent")
17-
1816
dependencies {
1917
// Slf4J / logback
2018
implementation("org.slf4j:slf4j-api:2.0.16")
@@ -30,24 +28,15 @@ dependencies {
3028
implementation("org.apache.logging.log4j:log4j-core")
3129

3230
// OpenTelemetry core
33-
implementation("io.opentelemetry:opentelemetry-api")
31+
implementation("io.opentelemetry:opentelemetry-sdk")
32+
implementation("io.opentelemetry:opentelemetry-exporter-otlp")
3433
implementation("io.opentelemetry.semconv:opentelemetry-semconv")
3534

3635
// OpenTelemetry log4j / logback appenders
3736
implementation("io.opentelemetry.instrumentation:opentelemetry-log4j-appender-2.17")
3837
implementation("io.opentelemetry.instrumentation:opentelemetry-logback-appender-1.0")
39-
40-
// OpenTelemetry JavaAgent
41-
agent("io.opentelemetry.javaagent:opentelemetry-javaagent:2.8.0")
4238
}
4339

4440
application {
4541
mainClass = "io.opentelemetry.example.logappender.Application"
4642
}
47-
48-
49-
tasks.named<JavaExec>("run") {
50-
doFirst {
51-
jvmArgs("-javaagent:${agent.singleFile}")
52-
}
53-
}

log-appender/otel-config.yaml

-7
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,8 @@ receivers:
66
exporters:
77
debug:
88
verbosity: detailed
9-
nop:
109
service:
1110
pipelines:
1211
logs:
1312
receivers: [otlp]
1413
exporters: [debug]
15-
traces:
16-
receivers: [otlp]
17-
exporters: [debug]
18-
metrics:
19-
receivers: [otlp]
20-
exporters: [nop]

0 commit comments

Comments
 (0)