Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ subprojects {
version = "0.1.0-SNAPSHOT"

repositories {
mavenLocal()
mavenCentral()
}

dependencies {
// using the bom ensures that all of your opentelemetry dependency versions are aligned
implementation(platform("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha:2.22.0-alpha"))
implementation(platform("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha:2.23.0-alpha-SNAPSHOT"))
}

spotless {
Expand Down
34 changes: 34 additions & 0 deletions log-appender-log4j2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# OpenTelemetry with Log4j2

This sample app demonstrates an application emitting logs through a variety of logging APIs (OpenTelemetry API, log4j1, log4j2, JUL, slf4j) and configuring those logs to be sent an OTLP receiver via the OpenTelemetry SDK, and to the console via log4j2.

* Install and run a OTLP receiver listening at `localhost:4318`. [otel-tui](https://github.com/ymtdzzz/otel-tui) is a good choice for local development.

* Run the application:

```shell
../gradlew run

> Task :opentelemetry-examples-log-appender-log4j2:run
log4j2: 08:49:54.249 [main] INFO log4j2-logger - A log4j2 log message.
log4j2: 08:49:54.263 [main] INFO log4j1-logger - A log4j1 log message.
log4j2: 08:49:54.263 [main] INFO slf4j-logger - A slf4j log message.
log4j2: 08:49:54.263 [main] INFO jul-logger - A JUL log message.
log4j2: 08:49:54.265 [main] INFO otel-logger - An OTEL log message.
```

* Or run the application with the javaagent:

```shell
../gradlew run -PrunWithAgent

> Task :opentelemetry-examples-log-appender-log4j2:run
[otel.javaagent 2025-12-08 08:54:48:330 -0600] [main] INFO io.opentelemetry.javaagent.tooling.VersionLogger - opentelemetry-javaagent - version: 2.23.0-SNAPSHOT
log4j2: 08:54:55.599 [main] INFO log4j2-logger - A log4j2 log message.
log4j2: 08:54:55.625 [main] INFO log4j1-logger - A log4j1 log message.
log4j2: 08:54:55.626 [main] INFO slf4j-logger - A slf4j log message.
log4j2: 08:54:55.626 [main] INFO jul-logger - A JUL log message.
log4j2: 08:54:55.629 [main] INFO otel-logger - An OTEL log message.
```

* A log message from each logging API appears exactly once in the console and OTLP receiver
81 changes: 81 additions & 0 deletions log-appender-log4j2/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
plugins {
id("java")
id("application")
}

description = "OpenTelemetry Log4j2 SDK Example"
val moduleName by extra { "io.opentelemetry.examples.log-appender" }

java {
toolchain {
// logback 1.4.x+ requires java 11
languageVersion.set(JavaLanguageVersion.of(11))
}
}

val agent = configurations.create("agent")

dependencies {
implementation(platform("org.apache.logging.log4j:log4j-bom:2.25.2"))

// Slf4J API
implementation("org.slf4j:slf4j-api:2.0.17")
// Log4j2 API
implementation("org.apache.logging.log4j:log4j-api")
// Log4j1 API (and bridge to SLF4J)
implementation("org.slf4j:log4j-over-slf4j:2.0.17")
// OTEL API
implementation("io.opentelemetry:opentelemetry-api")

// JUL to SLF4J bridge
implementation("org.slf4j:jul-to-slf4j:2.0.17")
// Log4j1 to SLF4J bridge
implementation("org.slf4j:slf4j-api:2.0.17")

// SLF4J binding for Log4j2
implementation("org.apache.logging.log4j:log4j-slf4j2-impl")

// Log4j2 SDK
implementation("org.apache.logging.log4j:log4j-core")
implementation("io.opentelemetry.instrumentation:opentelemetry-log4j-appender-2.17")

// OTEL SDK
implementation("io.opentelemetry:opentelemetry-sdk")
implementation("io.opentelemetry:opentelemetry-exporter-otlp")
implementation("io.opentelemetry:opentelemetry-sdk-extension-incubator")

agent("io.opentelemetry.javaagent:opentelemetry-javaagent:2.23.0-SNAPSHOT")
}

val copyAgent = tasks.register<Copy>("copyAgent") {
from(agent.singleFile)
into(layout.buildDirectory.dir("agent"))
rename("opentelemetry-javaagent-.*\\.jar", "opentelemetry-javaagent.jar")
}

tasks.getByName("run") {
dependsOn(copyAgent)
}

application {
mainClass = "io.opentelemetry.example.logappender.Application"

if (project.hasProperty("runWithAgent")) {
applicationDefaultJvmArgs = listOf("-javaagent:build/agent/opentelemetry-javaagent.jar")
}
}

tasks.register<JavaExec>("runWithoutAgent") {
group = ApplicationPlugin.APPLICATION_GROUP
classpath = sourceSets.main.get().runtimeClasspath
mainClass = "io.opentelemetry.example.logappender.Application"
}

tasks.register<JavaExec>("runWithAgent") {
dependsOn(copyAgent)

group = ApplicationPlugin.APPLICATION_GROUP
classpath = sourceSets.main.get().runtimeClasspath
mainClass = "io.opentelemetry.example.logappender.Application"
jvmArgs = listOf("-javaagent:build/agent/opentelemetry-javaagent.jar")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package io.opentelemetry.example.logappender;

import static io.opentelemetry.semconv.ServiceAttributes.SERVICE_NAME;

import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.logs.Severity;
import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter;
import io.opentelemetry.instrumentation.log4j.appender.v2_17.OpenTelemetryAppender;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.extension.incubator.slf4j.Slf4jBridgeProcessor;
import io.opentelemetry.sdk.logs.SdkLoggerProvider;
import io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.samplers.Sampler;
import java.util.logging.Logger;
import org.apache.logging.log4j.LogManager;
import org.slf4j.LoggerFactory;
import org.slf4j.bridge.SLF4JBridgeHandler;

public class Application {

public static void main(String[] args) {
// If javaagent isn't installed, initialize opentelemetry SDK and install it in the log4j2
// OpenTelemetryAppender
OpenTelemetry openTelemetry;
if (!GlobalOpenTelemetry.isSet()) {
openTelemetry = initializeOpenTelemetry();
OpenTelemetryAppender.install(openTelemetry);
} else {
openTelemetry = GlobalOpenTelemetry.get();
}

// Install JUL to SLF4J bridging
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();

// Initialize loggers and log from all APIs

// log4j2
org.apache.logging.log4j.Logger log4j2Logger = LogManager.getLogger("log4j2-logger");
log4j2Logger.info("A log4j2 log message.");

// log4j1
org.apache.log4j.Logger log4j1Logger = org.apache.log4j.Logger.getLogger("log4j1-logger");
log4j1Logger.info("A log4j1 log message.");

// slf4j
org.slf4j.Logger slf4jLogger = LoggerFactory.getLogger("slf4j-logger");
slf4jLogger.info("A slf4j log message.");

// jul
java.util.logging.Logger julLogger = Logger.getLogger("jul-logger");
julLogger.info("A JUL log message.");

// otel
io.opentelemetry.api.logs.Logger otelLogger = openTelemetry.getLogsBridge().get("otel-logger");
otelLogger.logRecordBuilder().setSeverity(Severity.INFO).setBody("An OTEL log message.").emit();
}

private static OpenTelemetry initializeOpenTelemetry() {
OpenTelemetrySdk sdk =
OpenTelemetrySdk.builder()
.setTracerProvider(SdkTracerProvider.builder().setSampler(Sampler.alwaysOn()).build())
.setLoggerProvider(
SdkLoggerProvider.builder()
.setResource(
Resource.getDefault().toBuilder()
.put(SERVICE_NAME, "log4j-example")
.build())
.addLogRecordProcessor(Slf4jBridgeProcessor.create())
.addLogRecordProcessor(
BatchLogRecordProcessor.builder(OtlpHttpLogRecordExporter.builder().build())
.build())
.build())
.build();

// Add hook to close SDK, which flushes logs
Runtime.getRuntime().addShutdownHook(new Thread(sdk::close));

return sdk;
}
}
15 changes: 15 additions & 0 deletions log-appender-log4j2/src/main/resources/log4j2.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="ConsoleAppender" target="SYSTEM_OUT" follow="true">
<PatternLayout pattern="log4j2: %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<OpenTelemetry name="OpenTelemetryAppender" captureMapMessageAttributes="true" captureExperimentalAttributes="true"/>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="OpenTelemetryAppender" />
<AppenderRef ref="ConsoleAppender" />
</Root>
</Loggers>
</Configuration>
34 changes: 34 additions & 0 deletions log-appender-logback/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# OpenTelemetry with Logback

This sample app demonstrates an application emitting logs through a variety of logging APIs (OpenTelemetry API, log4j1, log4j2, JUL, slf4j) and configuring those logs to be sent an OTLP receiver via the OpenTelemetry SDK, and to the console via logback.

* Install and run a OTLP receiver listening at `localhost:4318`. [otel-tui](https://github.com/ymtdzzz/otel-tui) is a good choice for local development.

* Run the application:

```shell
../gradlew run

> Task :opentelemetry-examples-log-appender-logback:run
logback: 08:53:12.625 [main] INFO log4j2-logger - A log4j2 log message.
logback: 08:53:12.633 [main] INFO log4j1-logger - A log4j1 log message.
logback: 08:53:12.633 [main] INFO slf4j-logger - A slf4j log message.
logback: 08:53:12.633 [main] INFO jul-logger - A JUL log message.
logback: 08:53:12.634 [main] INFO otel-logger - An OTEL log message.
```

* Or run the application with the javaagent:

```shell
../gradlew run -PrunWithAgent

> Task :opentelemetry-examples-log-appender-logback:run
logback: 08:47:33.317 [main] INFO i.o.javaagent.tooling.VersionLogger - opentelemetry-javaagent - version: 2.23.0-SNAPSHOT
logback: 08:47:33.337 [main] INFO log4j2-logger - A log4j2 log message.
logback: 08:47:33.340 [main] INFO log4j1-logger - A log4j1 log message.
logback: 08:47:33.340 [main] INFO slf4j-logger - A slf4j log message.
logback: 08:47:33.340 [main] INFO jul-logger - A JUL log message.
logback: 08:47:33.343 [main] INFO otel-logger - An OTEL log message.
```

* A log message from each logging API appears exactly once in the console and OTLP receiver
78 changes: 78 additions & 0 deletions log-appender-logback/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
plugins {
id("java")
id("application")
}

description = "OpenTelemetry Logback SDK Example"
val moduleName by extra { "io.opentelemetry.examples.log-appender" }

java {
toolchain {
// logback 1.4.x+ requires java 11
languageVersion.set(JavaLanguageVersion.of(11))
}
}

val agent = configurations.create("agent")

dependencies {
implementation(platform("org.apache.logging.log4j:log4j-bom:2.25.2"))

// Slf4J API
implementation("org.slf4j:slf4j-api:2.0.17")
// Log4j2 API
implementation("org.apache.logging.log4j:log4j-api")
// Log4j1 API (and bridge to SLF4J)
implementation("org.slf4j:log4j-over-slf4j:2.0.17")
// OTEL API
implementation("io.opentelemetry:opentelemetry-api")

// JUL to SLF4J bridge
implementation("org.slf4j:jul-to-slf4j:2.0.17")
// Log4j2 to SLF4J bridge
implementation("org.apache.logging.log4j:log4j-to-slf4j")

// Logback SDK and SLF4J binding for logback
implementation("ch.qos.logback:logback-classic:1.5.21")
implementation("io.opentelemetry.instrumentation:opentelemetry-logback-appender-1.0")

// OTEL SDK
implementation("io.opentelemetry:opentelemetry-sdk")
implementation("io.opentelemetry:opentelemetry-exporter-otlp")
implementation("io.opentelemetry:opentelemetry-sdk-extension-incubator")

agent("io.opentelemetry.javaagent:opentelemetry-javaagent:2.23.0-SNAPSHOT")
}

val copyAgent = tasks.register<Copy>("copyAgent") {
from(agent.singleFile)
into(layout.buildDirectory.dir("agent"))
rename("opentelemetry-javaagent-.*\\.jar", "opentelemetry-javaagent.jar")
}

tasks.getByName("run") {
dependsOn(copyAgent)
}

application {
mainClass = "io.opentelemetry.example.logappender.Application"

if (project.hasProperty("runWithAgent")) {
applicationDefaultJvmArgs = listOf("-javaagent:build/agent/opentelemetry-javaagent.jar")
}
}

tasks.register<JavaExec>("runWithoutAgent") {
group = ApplicationPlugin.APPLICATION_GROUP
classpath = sourceSets.main.get().runtimeClasspath
mainClass = "io.opentelemetry.example.logappender.Application"
}

tasks.register<JavaExec>("runWithAgent") {
dependsOn(copyAgent)

group = ApplicationPlugin.APPLICATION_GROUP
classpath = sourceSets.main.get().runtimeClasspath
mainClass = "io.opentelemetry.example.logappender.Application"
jvmArgs = listOf("-javaagent:build/agent/opentelemetry-javaagent.jar")
}
Loading
Loading