From cbe87ab0dd0fe912d662e2027be96fef010e5a8b Mon Sep 17 00:00:00 2001 From: Radoslav Kirilov Date: Thu, 10 Oct 2024 11:07:00 +0300 Subject: [PATCH 1/8] feat(javaagent-log-appender): otel collector pipelines for traces and metrics --- log-appender/otel-config.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/log-appender/otel-config.yaml b/log-appender/otel-config.yaml index 32697a5f77..95104e50f4 100644 --- a/log-appender/otel-config.yaml +++ b/log-appender/otel-config.yaml @@ -6,8 +6,15 @@ receivers: exporters: debug: verbosity: detailed + nop: service: pipelines: logs: receivers: [otlp] exporters: [debug] + traces: + receivers: [otlp] + exporters: [debug] + metrics: + receivers: [otlp] + exporters: [nop] From 8d834aa1ec0934aa6ab5d207455c4fd477304147 Mon Sep 17 00:00:00 2001 From: Radoslav Kirilov Date: Thu, 10 Oct 2024 12:09:12 +0300 Subject: [PATCH 2/8] feat(javaagent-log-appender): switch to javaagent --- log-appender/README.md | 7 +++ log-appender/build.gradle.kts | 19 ++++++-- .../example/logappender/Application.java | 45 +------------------ 3 files changed, 23 insertions(+), 48 deletions(-) diff --git a/log-appender/README.md b/log-appender/README.md index eac9529ef2..a720526f2a 100644 --- a/log-appender/README.md +++ b/log-appender/README.md @@ -37,6 +37,13 @@ docker-compose up In a separate shell, run the application ```shell +export \ +OTEL_SERVICE_NAME=log4j-example \ +OTEL_EXPORTER_OTLP_PROTOCOL=grpc \ +OTEL_METRICS_EXPORTER=none \ +OTEL_TRACES_EXPORTER=none \ +OTEL_LOGS_EXPORTER=otlp + ../gradlew run ``` diff --git a/log-appender/build.gradle.kts b/log-appender/build.gradle.kts index 63bc11af15..65f266c4cf 100644 --- a/log-appender/build.gradle.kts +++ b/log-appender/build.gradle.kts @@ -3,8 +3,8 @@ plugins { id("application") } -description = "OpenTelemetry Log Appender Example" -val moduleName by extra { "io.opentelemetry.examples.log-appender" } +description = "OpenTelemetry Log Appender Example using JavaAgent" +val moduleName by extra { "io.opentelemetry.examples.javaagent-log-appender" } java { toolchain { @@ -13,6 +13,8 @@ java { } } +val agent = configurations.create("agent") + dependencies { // Slf4J / logback implementation("org.slf4j:slf4j-api:2.0.16") @@ -28,15 +30,24 @@ dependencies { implementation("org.apache.logging.log4j:log4j-core") // OpenTelemetry core - implementation("io.opentelemetry:opentelemetry-sdk") - implementation("io.opentelemetry:opentelemetry-exporter-otlp") + implementation("io.opentelemetry:opentelemetry-api") implementation("io.opentelemetry.semconv:opentelemetry-semconv") // OpenTelemetry log4j / logback appenders implementation("io.opentelemetry.instrumentation:opentelemetry-log4j-appender-2.17") implementation("io.opentelemetry.instrumentation:opentelemetry-logback-appender-1.0") + + // OpenTelemetry JavaAgent + agent("io.opentelemetry.javaagent:opentelemetry-javaagent:2.8.0") } application { mainClass = "io.opentelemetry.example.logappender.Application" } + + +tasks.named("run") { + doFirst { + jvmArgs("-javaagent:${agent.singleFile}") + } +} diff --git a/log-appender/src/main/java/io/opentelemetry/example/logappender/Application.java b/log-appender/src/main/java/io/opentelemetry/example/logappender/Application.java index 56e801f5b1..b81d5c5d3d 100644 --- a/log-appender/src/main/java/io/opentelemetry/example/logappender/Application.java +++ b/log-appender/src/main/java/io/opentelemetry/example/logappender/Application.java @@ -1,19 +1,10 @@ package io.opentelemetry.example.logappender; import io.opentelemetry.api.GlobalOpenTelemetry; -import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.logs.Severity; import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Scope; -import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter; -import io.opentelemetry.sdk.OpenTelemetrySdk; -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 io.opentelemetry.semconv.ResourceAttributes; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; @@ -32,15 +23,6 @@ public class Application { private static final java.util.logging.Logger julLogger = Logger.getLogger("jul-logger"); public static void main(String[] args) { - // Initialize OpenTelemetry as early as possible - OpenTelemetry openTelemetry = initializeOpenTelemetry(); - // Install OpenTelemetry in log4j appender - io.opentelemetry.instrumentation.log4j.appender.v2_17.OpenTelemetryAppender.install( - openTelemetry); - // Install OpenTelemetry in logback appender - io.opentelemetry.instrumentation.logback.appender.v1_0.OpenTelemetryAppender.install( - openTelemetry); - // Route JUL logs to slf4j SLF4JBridgeHandler.removeHandlersForRootLogger(); SLF4JBridgeHandler.install(); @@ -86,7 +68,7 @@ public static void main(String[] args) { // existing frameworks into the OpenTelemetry Log Bridge API. These APIs // SHOULD NOT be used by end users in place of existing log APIs (i.e. Log4j, Slf4, JUL). io.opentelemetry.api.logs.Logger customAppenderLogger = - openTelemetry.getLogsBridge().get("custom-log-appender"); + GlobalOpenTelemetry.get().getLogsBridge().get("custom-log-appender"); maybeRunWithSpan( () -> customAppenderLogger @@ -107,31 +89,6 @@ public static void main(String[] args) { true); } - private static OpenTelemetry initializeOpenTelemetry() { - OpenTelemetrySdk sdk = - OpenTelemetrySdk.builder() - .setTracerProvider(SdkTracerProvider.builder().setSampler(Sampler.alwaysOn()).build()) - .setLoggerProvider( - SdkLoggerProvider.builder() - .setResource( - Resource.getDefault().toBuilder() - .put(ResourceAttributes.SERVICE_NAME, "log4j-example") - .build()) - .addLogRecordProcessor( - BatchLogRecordProcessor.builder( - OtlpGrpcLogRecordExporter.builder() - .setEndpoint("http://localhost:4317") - .build()) - .build()) - .build()) - .build(); - - // Add hook to close SDK, which flushes logs - Runtime.getRuntime().addShutdownHook(new Thread(sdk::close)); - - return sdk; - } - private static void maybeRunWithSpan(Runnable runnable, boolean withSpan) { if (!withSpan) { runnable.run(); From 55a3557a6e671377e76a4eec10b2a16402b4a700 Mon Sep 17 00:00:00 2001 From: Radoslav Kirilov Date: Thu, 10 Oct 2024 12:12:23 +0300 Subject: [PATCH 3/8] feat(javaagent-log-appender): split javaagent-log-appender package --- README.md | 3 + javaagent-log-appender/README.md | 50 +++++++++ javaagent-log-appender/build.gradle.kts | 53 +++++++++ javaagent-log-appender/docker-compose.yml | 9 ++ javaagent-log-appender/otel-config.yaml | 20 ++++ .../example/logappender/Application.java | 104 ++++++++++++++++++ .../src/main/resources/log4j2.xml | 15 +++ .../src/main/resources/logback.xml | 19 ++++ log-appender/README.md | 7 -- log-appender/build.gradle.kts | 19 +--- log-appender/otel-config.yaml | 7 -- .../example/logappender/Application.java | 45 +++++++- settings.gradle.kts | 1 + 13 files changed, 322 insertions(+), 30 deletions(-) create mode 100644 javaagent-log-appender/README.md create mode 100644 javaagent-log-appender/build.gradle.kts create mode 100644 javaagent-log-appender/docker-compose.yml create mode 100644 javaagent-log-appender/otel-config.yaml create mode 100644 javaagent-log-appender/src/main/java/io/opentelemetry/example/logappender/Application.java create mode 100644 javaagent-log-appender/src/main/resources/log4j2.xml create mode 100644 javaagent-log-appender/src/main/resources/logback.xml diff --git a/README.md b/README.md index 61fede0489..22ff5585af 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,9 @@ of them assume you have docker running on your local machine. - [Configuring Log Appenders](log-appender) - This module demonstrates how to configure the Log4j and Logback appenders to bridge logs into the OpenTelemetry Log SDK. +- [Configuring Log Appenders when using JavaAgent](javaagent-log-appender) + - This module demonstrates how to configure the Log4j and Logback appenders to + bridge logs into the OpenTelemetry Log SDK when using JavaAgent. - [Configuring the Logging Exporters](logging) - This module contains a fully-functional example of configuring the OpenTelemetry SDK to use a logging exporter. diff --git a/javaagent-log-appender/README.md b/javaagent-log-appender/README.md new file mode 100644 index 0000000000..a720526f2a --- /dev/null +++ b/javaagent-log-appender/README.md @@ -0,0 +1,50 @@ +# OpenTelemetry Log Appender Example + +This example demonstrates an application configured to use the OpenTelemetry Log +Appenders to bridge logs into the OpenTelemetry Log SDK, and export +via [OTLP](https://opentelemetry.io/docs/reference/specification/protocol/otlp/). + +Details about the example: + +* The OpenTelemetry Log SDK is configured to export data to + the [collector](https://opentelemetry.io/docs/collector/), which prints the + logs to the console. +* The application is configured with a variety of log solutions: + * Log4j API [configured](./src/main/resources/log4j2.xml) to print logs to the + console and + the [OpenTelemetry Log4J Appender](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/instrumentation/log4j/log4j-appender-2.17/library/README.md). + * SLF4J API [configured with Logback](./src/main/resources/logback.xml) to + print logs to the console and + the [OpenTelemetry Logback Appender](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/instrumentation/logback/logback-appender-1.0/library/README.md). + * [JUL to SLF4J](./build.gradle.kts), which bridges JUL logs to the SLF4J API, and + ultimately to Logback. +* Demonstrates how trace context is propagated to logs when recorded within a + span. + +## Prerequisites + +* Java 1.8 +* Docker compose + +# How to run + +Run the collector via docker + +```shell +docker-compose up +``` + +In a separate shell, run the application + +```shell +export \ +OTEL_SERVICE_NAME=log4j-example \ +OTEL_EXPORTER_OTLP_PROTOCOL=grpc \ +OTEL_METRICS_EXPORTER=none \ +OTEL_TRACES_EXPORTER=none \ +OTEL_LOGS_EXPORTER=otlp + +../gradlew run +``` + +Watch the collector logs to see exported log records diff --git a/javaagent-log-appender/build.gradle.kts b/javaagent-log-appender/build.gradle.kts new file mode 100644 index 0000000000..b4f347e0ac --- /dev/null +++ b/javaagent-log-appender/build.gradle.kts @@ -0,0 +1,53 @@ +plugins { + id("java") + id("application") +} + +description = "OpenTelemetry Log Appender Example using JavaAgent" +val moduleName by extra { "io.opentelemetry.examples.javaagent-log-appender" } + +java { + toolchain { + // logback 1.4.x+ requires java 11 + languageVersion.set(JavaLanguageVersion.of(11)) + } +} + +val agent = configurations.create("agent") + +dependencies { + // Slf4J / logback + implementation("org.slf4j:slf4j-api:2.0.16") + implementation("ch.qos.logback:logback-core:1.5.9") + implementation("ch.qos.logback:logback-classic:1.5.9") + + // JUL to SLF4J bridge + implementation("org.slf4j:jul-to-slf4j:2.0.16") + + // Log4j + implementation(platform("org.apache.logging.log4j:log4j-bom:2.24.1")) + implementation("org.apache.logging.log4j:log4j-api") + implementation("org.apache.logging.log4j:log4j-core") + + // OpenTelemetry core + implementation("io.opentelemetry:opentelemetry-api") + implementation("io.opentelemetry.semconv:opentelemetry-semconv") + + // OpenTelemetry log4j / logback appenders + implementation("io.opentelemetry.instrumentation:opentelemetry-log4j-appender-2.17") + implementation("io.opentelemetry.instrumentation:opentelemetry-logback-appender-1.0") + + // OpenTelemetry JavaAgent + agent("io.opentelemetry.javaagent:opentelemetry-javaagent:2.8.0") +} + +application { + mainClass = "io.opentelemetry.example.logappender.Application" +} + + +tasks.named("run") { + doFirst { + jvmArgs("-javaagent:${agent.singleFile}") + } +} diff --git a/javaagent-log-appender/docker-compose.yml b/javaagent-log-appender/docker-compose.yml new file mode 100644 index 0000000000..7ec653174e --- /dev/null +++ b/javaagent-log-appender/docker-compose.yml @@ -0,0 +1,9 @@ +version: '3' +services: + collector: + image: otel/opentelemetry-collector-contrib:0.111.0 + volumes: + - ./otel-config.yaml:/otel-config.yaml + command: ["--config=/otel-config.yaml"] + ports: + - "4317:4317" diff --git a/javaagent-log-appender/otel-config.yaml b/javaagent-log-appender/otel-config.yaml new file mode 100644 index 0000000000..95104e50f4 --- /dev/null +++ b/javaagent-log-appender/otel-config.yaml @@ -0,0 +1,20 @@ +receivers: + otlp: + protocols: + grpc: + endpoint: collector:4317 +exporters: + debug: + verbosity: detailed + nop: +service: + pipelines: + logs: + receivers: [otlp] + exporters: [debug] + traces: + receivers: [otlp] + exporters: [debug] + metrics: + receivers: [otlp] + exporters: [nop] diff --git a/javaagent-log-appender/src/main/java/io/opentelemetry/example/logappender/Application.java b/javaagent-log-appender/src/main/java/io/opentelemetry/example/logappender/Application.java new file mode 100644 index 0000000000..b81d5c5d3d --- /dev/null +++ b/javaagent-log-appender/src/main/java/io/opentelemetry/example/logappender/Application.java @@ -0,0 +1,104 @@ +package io.opentelemetry.example.logappender; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.logs.Severity; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Scope; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.message.MapMessage; +import org.slf4j.LoggerFactory; +import org.slf4j.bridge.SLF4JBridgeHandler; + +public class Application { + + private static final org.apache.logging.log4j.Logger log4jLogger = + LogManager.getLogger("log4j-logger"); + private static final org.slf4j.Logger slf4jLogger = LoggerFactory.getLogger("slf4j-logger"); + private static final java.util.logging.Logger julLogger = Logger.getLogger("jul-logger"); + + public static void main(String[] args) { + // Route JUL logs to slf4j + SLF4JBridgeHandler.removeHandlersForRootLogger(); + SLF4JBridgeHandler.install(); + + // Log using log4j API + maybeRunWithSpan(() -> log4jLogger.info("A log4j log message without a span"), false); + maybeRunWithSpan(() -> log4jLogger.info("A log4j log message with a span"), true); + Map mapMessage = new HashMap<>(); + mapMessage.put("key", "value"); + mapMessage.put("message", "A log4j structured message"); + maybeRunWithSpan(() -> log4jLogger.info(new MapMessage<>(mapMessage)), false); + ThreadContext.clearAll(); + maybeRunWithSpan( + () -> log4jLogger.info("A log4j log message with an exception", new Exception("error!")), + false); + + // Log using slf4j API w/ logback backend + maybeRunWithSpan(() -> slf4jLogger.info("A slf4j log message without a span"), false); + maybeRunWithSpan(() -> slf4jLogger.info("A slf4j log message with a span"), true); + maybeRunWithSpan( + () -> + slf4jLogger + .atInfo() + .setMessage("A slf4j structured message") + .addKeyValue("key", "value") + .log(), + false); + maybeRunWithSpan( + () -> slf4jLogger.info("A slf4j log message with an exception", new Exception("error!")), + false); + + // Log using JUL API, bridged to slf4j, w/ logback backend + maybeRunWithSpan(() -> julLogger.info("A JUL log message without a span"), false); + maybeRunWithSpan(() -> julLogger.info("A JUL log message with a span"), true); + maybeRunWithSpan( + () -> + julLogger.log( + Level.INFO, "A JUL log message with an exception", new Exception("error!")), + false); + + // Log using OpenTelemetry Log Bridge API + // WARNING: This illustrates how to write appenders which bridge logs from + // existing frameworks into the OpenTelemetry Log Bridge API. These APIs + // SHOULD NOT be used by end users in place of existing log APIs (i.e. Log4j, Slf4, JUL). + io.opentelemetry.api.logs.Logger customAppenderLogger = + GlobalOpenTelemetry.get().getLogsBridge().get("custom-log-appender"); + maybeRunWithSpan( + () -> + customAppenderLogger + .logRecordBuilder() + .setSeverity(Severity.INFO) + .setBody("A log message from a custom appender without a span") + .setAttribute(AttributeKey.stringKey("key"), "value") + .emit(), + false); + maybeRunWithSpan( + () -> + customAppenderLogger + .logRecordBuilder() + .setSeverity(Severity.INFO) + .setBody("A log message from a custom appender with a span") + .setAttribute(AttributeKey.stringKey("key"), "value") + .emit(), + true); + } + + private static void maybeRunWithSpan(Runnable runnable, boolean withSpan) { + if (!withSpan) { + runnable.run(); + return; + } + Span span = GlobalOpenTelemetry.getTracer("my-tracer").spanBuilder("my-span").startSpan(); + try (Scope unused = span.makeCurrent()) { + runnable.run(); + } finally { + span.end(); + } + } +} diff --git a/javaagent-log-appender/src/main/resources/log4j2.xml b/javaagent-log-appender/src/main/resources/log4j2.xml new file mode 100644 index 0000000000..3601b98441 --- /dev/null +++ b/javaagent-log-appender/src/main/resources/log4j2.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/javaagent-log-appender/src/main/resources/logback.xml b/javaagent-log-appender/src/main/resources/logback.xml new file mode 100644 index 0000000000..a14aeb7fae --- /dev/null +++ b/javaagent-log-appender/src/main/resources/logback.xml @@ -0,0 +1,19 @@ + + + + + + logback: %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg %kvp{DOUBLE}%n + + + + + true + true + + + + + + \ No newline at end of file diff --git a/log-appender/README.md b/log-appender/README.md index a720526f2a..eac9529ef2 100644 --- a/log-appender/README.md +++ b/log-appender/README.md @@ -37,13 +37,6 @@ docker-compose up In a separate shell, run the application ```shell -export \ -OTEL_SERVICE_NAME=log4j-example \ -OTEL_EXPORTER_OTLP_PROTOCOL=grpc \ -OTEL_METRICS_EXPORTER=none \ -OTEL_TRACES_EXPORTER=none \ -OTEL_LOGS_EXPORTER=otlp - ../gradlew run ``` diff --git a/log-appender/build.gradle.kts b/log-appender/build.gradle.kts index 65f266c4cf..63bc11af15 100644 --- a/log-appender/build.gradle.kts +++ b/log-appender/build.gradle.kts @@ -3,8 +3,8 @@ plugins { id("application") } -description = "OpenTelemetry Log Appender Example using JavaAgent" -val moduleName by extra { "io.opentelemetry.examples.javaagent-log-appender" } +description = "OpenTelemetry Log Appender Example" +val moduleName by extra { "io.opentelemetry.examples.log-appender" } java { toolchain { @@ -13,8 +13,6 @@ java { } } -val agent = configurations.create("agent") - dependencies { // Slf4J / logback implementation("org.slf4j:slf4j-api:2.0.16") @@ -30,24 +28,15 @@ dependencies { implementation("org.apache.logging.log4j:log4j-core") // OpenTelemetry core - implementation("io.opentelemetry:opentelemetry-api") + implementation("io.opentelemetry:opentelemetry-sdk") + implementation("io.opentelemetry:opentelemetry-exporter-otlp") implementation("io.opentelemetry.semconv:opentelemetry-semconv") // OpenTelemetry log4j / logback appenders implementation("io.opentelemetry.instrumentation:opentelemetry-log4j-appender-2.17") implementation("io.opentelemetry.instrumentation:opentelemetry-logback-appender-1.0") - - // OpenTelemetry JavaAgent - agent("io.opentelemetry.javaagent:opentelemetry-javaagent:2.8.0") } application { mainClass = "io.opentelemetry.example.logappender.Application" } - - -tasks.named("run") { - doFirst { - jvmArgs("-javaagent:${agent.singleFile}") - } -} diff --git a/log-appender/otel-config.yaml b/log-appender/otel-config.yaml index 95104e50f4..32697a5f77 100644 --- a/log-appender/otel-config.yaml +++ b/log-appender/otel-config.yaml @@ -6,15 +6,8 @@ receivers: exporters: debug: verbosity: detailed - nop: service: pipelines: logs: receivers: [otlp] exporters: [debug] - traces: - receivers: [otlp] - exporters: [debug] - metrics: - receivers: [otlp] - exporters: [nop] diff --git a/log-appender/src/main/java/io/opentelemetry/example/logappender/Application.java b/log-appender/src/main/java/io/opentelemetry/example/logappender/Application.java index b81d5c5d3d..56e801f5b1 100644 --- a/log-appender/src/main/java/io/opentelemetry/example/logappender/Application.java +++ b/log-appender/src/main/java/io/opentelemetry/example/logappender/Application.java @@ -1,10 +1,19 @@ package io.opentelemetry.example.logappender; import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.logs.Severity; import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Scope; +import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter; +import io.opentelemetry.sdk.OpenTelemetrySdk; +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 io.opentelemetry.semconv.ResourceAttributes; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; @@ -23,6 +32,15 @@ public class Application { private static final java.util.logging.Logger julLogger = Logger.getLogger("jul-logger"); public static void main(String[] args) { + // Initialize OpenTelemetry as early as possible + OpenTelemetry openTelemetry = initializeOpenTelemetry(); + // Install OpenTelemetry in log4j appender + io.opentelemetry.instrumentation.log4j.appender.v2_17.OpenTelemetryAppender.install( + openTelemetry); + // Install OpenTelemetry in logback appender + io.opentelemetry.instrumentation.logback.appender.v1_0.OpenTelemetryAppender.install( + openTelemetry); + // Route JUL logs to slf4j SLF4JBridgeHandler.removeHandlersForRootLogger(); SLF4JBridgeHandler.install(); @@ -68,7 +86,7 @@ public static void main(String[] args) { // existing frameworks into the OpenTelemetry Log Bridge API. These APIs // SHOULD NOT be used by end users in place of existing log APIs (i.e. Log4j, Slf4, JUL). io.opentelemetry.api.logs.Logger customAppenderLogger = - GlobalOpenTelemetry.get().getLogsBridge().get("custom-log-appender"); + openTelemetry.getLogsBridge().get("custom-log-appender"); maybeRunWithSpan( () -> customAppenderLogger @@ -89,6 +107,31 @@ public static void main(String[] args) { true); } + private static OpenTelemetry initializeOpenTelemetry() { + OpenTelemetrySdk sdk = + OpenTelemetrySdk.builder() + .setTracerProvider(SdkTracerProvider.builder().setSampler(Sampler.alwaysOn()).build()) + .setLoggerProvider( + SdkLoggerProvider.builder() + .setResource( + Resource.getDefault().toBuilder() + .put(ResourceAttributes.SERVICE_NAME, "log4j-example") + .build()) + .addLogRecordProcessor( + BatchLogRecordProcessor.builder( + OtlpGrpcLogRecordExporter.builder() + .setEndpoint("http://localhost:4317") + .build()) + .build()) + .build()) + .build(); + + // Add hook to close SDK, which flushes logs + Runtime.getRuntime().addShutdownHook(new Thread(sdk::close)); + + return sdk; + } + private static void maybeRunWithSpan(Runnable runnable, boolean withSpan) { if (!withSpan) { runnable.run(); diff --git a/settings.gradle.kts b/settings.gradle.kts index fa1274b7fb..015c5581c4 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -49,6 +49,7 @@ include( ":opentelemetry-examples-http", ":opentelemetry-examples-jaeger", ":opentelemetry-examples-javaagent", + ":opentelemetry-examples-javaagent-log-appender", ":opentelemetry-examples-log-appender", ":opentelemetry-examples-logging", ":opentelemetry-examples-manual-tracing", From 0997ec5732d1558dbe4b2553ed4c3c88275846ca Mon Sep 17 00:00:00 2001 From: Radoslav Kirilov Date: Fri, 11 Oct 2024 10:56:38 +0300 Subject: [PATCH 4/8] feat(javaagent-log-appender): transfer appender settings to system properties JavaAgent instrumentation of Log Appenders does not respect logger configs like `log4j2.xml` or `logback.xml` as it uses direct patching of loggers to do the same and no appenders set in the loggers. --- javaagent-log-appender/build.gradle.kts | 16 +++++++++++----- .../src/main/resources/log4j2.xml | 6 ++---- .../src/main/resources/logback.xml | 8 +------- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/javaagent-log-appender/build.gradle.kts b/javaagent-log-appender/build.gradle.kts index b4f347e0ac..052e191ff0 100644 --- a/javaagent-log-appender/build.gradle.kts +++ b/javaagent-log-appender/build.gradle.kts @@ -33,11 +33,7 @@ dependencies { implementation("io.opentelemetry:opentelemetry-api") implementation("io.opentelemetry.semconv:opentelemetry-semconv") - // OpenTelemetry log4j / logback appenders - implementation("io.opentelemetry.instrumentation:opentelemetry-log4j-appender-2.17") - implementation("io.opentelemetry.instrumentation:opentelemetry-logback-appender-1.0") - - // OpenTelemetry JavaAgent + // OpenTelemetry JavaAgent, this brings its own standalone log4j / logback appenders agent("io.opentelemetry.javaagent:opentelemetry-javaagent:2.8.0") } @@ -49,5 +45,15 @@ application { tasks.named("run") { doFirst { jvmArgs("-javaagent:${agent.singleFile}") + // log4j-appender properties + jvmArgs( + "-Dotel.instrumentation.log4j-appender.experimental.capture-map-message-attributes=true", + "-Dotel.instrumentation.log4j-appender.experimental-log-attributes=true" + ) + // logback-appender properties + jvmArgs( + "-Dotel.instrumentation.logback-appender.experimental-log-attributes=true", + "-Dotel.instrumentation.logback-appender.experimental.capture-key-value-pair-attributes=true" + ) } } diff --git a/javaagent-log-appender/src/main/resources/log4j2.xml b/javaagent-log-appender/src/main/resources/log4j2.xml index 3601b98441..8c91e02f01 100644 --- a/javaagent-log-appender/src/main/resources/log4j2.xml +++ b/javaagent-log-appender/src/main/resources/log4j2.xml @@ -1,15 +1,13 @@ - + - - - \ No newline at end of file + diff --git a/javaagent-log-appender/src/main/resources/logback.xml b/javaagent-log-appender/src/main/resources/logback.xml index a14aeb7fae..348cb1f1af 100644 --- a/javaagent-log-appender/src/main/resources/logback.xml +++ b/javaagent-log-appender/src/main/resources/logback.xml @@ -7,13 +7,7 @@ - - true - true - - - \ No newline at end of file + From 8daa9fe574d08650b8fcbd230bfb92b42a86f16e Mon Sep 17 00:00:00 2001 From: Radoslav Kirilov Date: Thu, 17 Oct 2024 13:48:33 +0300 Subject: [PATCH 5/8] chore: support and use the default `http/protobuf` protocol refs https://github.com/open-telemetry/opentelemetry-java-examples/pull/503#discussion_r1799222630 --- javaagent-log-appender/README.md | 6 +++++- javaagent-log-appender/build.gradle.kts | 2 +- javaagent-log-appender/docker-compose.yml | 1 + javaagent-log-appender/otel-config.yaml | 8 +++++--- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/javaagent-log-appender/README.md b/javaagent-log-appender/README.md index a720526f2a..a4e3f72998 100644 --- a/javaagent-log-appender/README.md +++ b/javaagent-log-appender/README.md @@ -39,7 +39,6 @@ In a separate shell, run the application ```shell export \ OTEL_SERVICE_NAME=log4j-example \ -OTEL_EXPORTER_OTLP_PROTOCOL=grpc \ OTEL_METRICS_EXPORTER=none \ OTEL_TRACES_EXPORTER=none \ OTEL_LOGS_EXPORTER=otlp @@ -48,3 +47,8 @@ OTEL_LOGS_EXPORTER=otlp ``` Watch the collector logs to see exported log records + +NOTE: The OpenTelemetry Java Agent uses `http/protobuf` by default, optionally switch to use `grpc` protocol +```shell +export OTEL_EXPORTER_OTLP_PROTOCOL=grpc +``` diff --git a/javaagent-log-appender/build.gradle.kts b/javaagent-log-appender/build.gradle.kts index 052e191ff0..2a4e4f231d 100644 --- a/javaagent-log-appender/build.gradle.kts +++ b/javaagent-log-appender/build.gradle.kts @@ -33,7 +33,7 @@ dependencies { implementation("io.opentelemetry:opentelemetry-api") implementation("io.opentelemetry.semconv:opentelemetry-semconv") - // OpenTelemetry JavaAgent, this brings its own standalone log4j / logback appenders + // OpenTelemetry Java Agent, this brings its own standalone log4j / logback appenders agent("io.opentelemetry.javaagent:opentelemetry-javaagent:2.8.0") } diff --git a/javaagent-log-appender/docker-compose.yml b/javaagent-log-appender/docker-compose.yml index 7ec653174e..bf50c06a92 100644 --- a/javaagent-log-appender/docker-compose.yml +++ b/javaagent-log-appender/docker-compose.yml @@ -7,3 +7,4 @@ services: command: ["--config=/otel-config.yaml"] ports: - "4317:4317" + - "4318:4318" diff --git a/javaagent-log-appender/otel-config.yaml b/javaagent-log-appender/otel-config.yaml index 95104e50f4..7a645b2d72 100644 --- a/javaagent-log-appender/otel-config.yaml +++ b/javaagent-log-appender/otel-config.yaml @@ -3,18 +3,20 @@ receivers: protocols: grpc: endpoint: collector:4317 + http: + endpoint: "0.0.0.0:4318" exporters: debug: verbosity: detailed nop: service: pipelines: - logs: + metrics: receivers: [otlp] exporters: [debug] traces: receivers: [otlp] exporters: [debug] - metrics: + logs: receivers: [otlp] - exporters: [nop] + exporters: [debug] From da88e35aad100cbc3e9eef8c5d2245634c4f381c Mon Sep 17 00:00:00 2001 From: Radoslav Kirilov Date: Thu, 17 Oct 2024 13:59:32 +0300 Subject: [PATCH 6/8] chore: update readme to outline properly the example refs https://github.com/open-telemetry/opentelemetry-java-examples/pull/503#discussion_r1799246011 refs https://github.com/open-telemetry/opentelemetry-java-examples/pull/503#discussion_r1799248498 --- javaagent-log-appender/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/javaagent-log-appender/README.md b/javaagent-log-appender/README.md index a4e3f72998..be1299b017 100644 --- a/javaagent-log-appender/README.md +++ b/javaagent-log-appender/README.md @@ -1,7 +1,7 @@ -# OpenTelemetry Log Appender Example +# OpenTelemetry Log Appender built-in OpenTelemetry Java Agent Example This example demonstrates an application configured to use the OpenTelemetry Log -Appenders to bridge logs into the OpenTelemetry Log SDK, and export +Appenders built-in OpenTelemetry Java Agent to bridge logs into the OpenTelemetry Log SDK, and export via [OTLP](https://opentelemetry.io/docs/reference/specification/protocol/otlp/). Details about the example: @@ -12,10 +12,10 @@ Details about the example: * The application is configured with a variety of log solutions: * Log4j API [configured](./src/main/resources/log4j2.xml) to print logs to the console and - the [OpenTelemetry Log4J Appender](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/instrumentation/log4j/log4j-appender-2.17/library/README.md). + the [OpenTelemetry Log4J Appender](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/instrumentation/log4j/log4j-appender-2.17/javaagent/README.md). * SLF4J API [configured with Logback](./src/main/resources/logback.xml) to print logs to the console and - the [OpenTelemetry Logback Appender](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/instrumentation/logback/logback-appender-1.0/library/README.md). + the [OpenTelemetry Logback Appender](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/instrumentation/logback/logback-appender-1.0/javaagent/README.md). * [JUL to SLF4J](./build.gradle.kts), which bridges JUL logs to the SLF4J API, and ultimately to Logback. * Demonstrates how trace context is propagated to logs when recorded within a From cfe4157f95465456b95cda4aeeffa34b0e2547a1 Mon Sep 17 00:00:00 2001 From: Radoslav Kirilov Date: Fri, 18 Oct 2024 15:18:47 +0300 Subject: [PATCH 7/8] chore: remove empty line refs https://github.com/open-telemetry/opentelemetry-java-examples/pull/503/files#r1806183086 --- javaagent-log-appender/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/javaagent-log-appender/build.gradle.kts b/javaagent-log-appender/build.gradle.kts index 2a4e4f231d..59b7c32741 100644 --- a/javaagent-log-appender/build.gradle.kts +++ b/javaagent-log-appender/build.gradle.kts @@ -41,7 +41,6 @@ application { mainClass = "io.opentelemetry.example.logappender.Application" } - tasks.named("run") { doFirst { jvmArgs("-javaagent:${agent.singleFile}") From ff05f0dbf6513d042f73c0086706fdf027f391b7 Mon Sep 17 00:00:00 2001 From: Radoslav Kirilov Date: Fri, 18 Oct 2024 15:20:56 +0300 Subject: [PATCH 8/8] chore: update readme to clarify appenders refs https://github.com/open-telemetry/opentelemetry-java-examples/pull/503/files#r1806187111 refs https://github.com/open-telemetry/opentelemetry-java-examples/pull/503/files#r1806187339 --- javaagent-log-appender/README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/javaagent-log-appender/README.md b/javaagent-log-appender/README.md index be1299b017..c3b7b2f105 100644 --- a/javaagent-log-appender/README.md +++ b/javaagent-log-appender/README.md @@ -12,10 +12,12 @@ Details about the example: * The application is configured with a variety of log solutions: * Log4j API [configured](./src/main/resources/log4j2.xml) to print logs to the console and - the [OpenTelemetry Log4J Appender](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/instrumentation/log4j/log4j-appender-2.17/javaagent/README.md). + the OpenTelemetry Java Agent brings built-in + [OpenTelemetry Log4J Appender](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/instrumentation/log4j/log4j-appender-2.17/javaagent/README.md). * SLF4J API [configured with Logback](./src/main/resources/logback.xml) to print logs to the console and - the [OpenTelemetry Logback Appender](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/instrumentation/logback/logback-appender-1.0/javaagent/README.md). + the OpenTelemetry Java Agent brings built-in + [OpenTelemetry Logback Appender](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/instrumentation/logback/logback-appender-1.0/javaagent/README.md). * [JUL to SLF4J](./build.gradle.kts), which bridges JUL logs to the SLF4J API, and ultimately to Logback. * Demonstrates how trace context is propagated to logs when recorded within a