Skip to content

Commit

Permalink
feat(javaagent-log-appender): split javaagent-log-appender package
Browse files Browse the repository at this point in the history
  • Loading branch information
smoke committed Oct 10, 2024
1 parent 4b461f4 commit b40a708
Show file tree
Hide file tree
Showing 13 changed files with 322 additions and 30 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
50 changes: 50 additions & 0 deletions javaagent-log-appender/README.md
Original file line number Diff line number Diff line change
@@ -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
53 changes: 53 additions & 0 deletions javaagent-log-appender/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -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<JavaExec>("run") {
doFirst {
jvmArgs("-javaagent:${agent.singleFile}")
}
}
9 changes: 9 additions & 0 deletions javaagent-log-appender/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -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"
20 changes: 20 additions & 0 deletions javaagent-log-appender/otel-config.yaml
Original file line number Diff line number Diff line change
@@ -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]
Original file line number Diff line number Diff line change
@@ -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<String, Object> 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();
}
}
}
15 changes: 15 additions & 0 deletions javaagent-log-appender/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" packages="io.opentelemetry.instrumentation.log4j.appender.v2_17">
<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>
19 changes: 19 additions & 0 deletions javaagent-log-appender/src/main/resources/logback.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>
logback: %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg %kvp{DOUBLE}%n
</pattern>
</encoder>
</appender>
<appender name="OpenTelemetry"
class="io.opentelemetry.instrumentation.logback.appender.v1_0.OpenTelemetryAppender">
<captureExperimentalAttributes>true</captureExperimentalAttributes>
<captureKeyValuePairAttributes>true</captureKeyValuePairAttributes>
</appender>
<root level="INFO">
<appender-ref ref="console"/>
<appender-ref ref="OpenTelemetry"/>
</root>
</configuration>
7 changes: 0 additions & 7 deletions log-appender/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```

Expand Down
19 changes: 4 additions & 15 deletions log-appender/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -13,8 +13,6 @@ java {
}
}

val agent = configurations.create("agent")

dependencies {
// Slf4J / logback
implementation("org.slf4j:slf4j-api:2.0.16")
Expand All @@ -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<JavaExec>("run") {
doFirst {
jvmArgs("-javaagent:${agent.singleFile}")
}
}
7 changes: 0 additions & 7 deletions log-appender/otel-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Loading

0 comments on commit b40a708

Please sign in to comment.