Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Log4j and Logback appenders opt-in to using GlobalOpenTelemetry #8791

Merged
merged 5 commits into from
Jun 29, 2023
Merged
Show file tree
Hide file tree
Changes from 4 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
20 changes: 20 additions & 0 deletions instrumentation/log4j/log4j-appender-2.17/library/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,23 @@ The following demonstrates how you might configure the appender in your `log4j.x

In this example Log4j2 log events will be sent to both the console appender and
the `OpenTelemetryAppender`.

In order to function, `OpenTelemetryAppender` needs access to an `OpenTelemetry` instance. This must
be set programmatically during application startup as follows:

```java
import io.opentelemetry.instrumentation.log4j.appender.v2_17.OpenTelemetryAppender;
import io.opentelemetry.sdk.OpenTelemetrySdk;

public class Application {

public static void main(String[] args) {
OpenTelemetrySdk openTelemetrySdk = // Configure OpenTelemetrySdk

// Find OpenTelemetryAppender in log4j configuration and install openTelemetrySdk
OpenTelemetryAppender.install(openTelemetrySdk);

// ... proceed with application
}
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import static java.util.Collections.emptyList;

import com.google.errorprone.annotations.CanIgnoreReturnValue;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.logs.LogRecordBuilder;
import io.opentelemetry.instrumentation.log4j.appender.v2_17.internal.ContextDataAccessor;
Expand All @@ -20,13 +19,16 @@
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Core;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.Property;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
Expand All @@ -44,7 +46,29 @@ public class OpenTelemetryAppender extends AbstractAppender {
static final String PLUGIN_NAME = "OpenTelemetry";

private final LogEventMapper<ReadOnlyStringMap> mapper;
@Nullable private OpenTelemetry openTelemetry;
private OpenTelemetry openTelemetry;

/**
* Installs the {@code openTelemetry} instance on any {@link OpenTelemetryAppender}s identified in
* the {@link LoggerContext}.
*/
public static void install(OpenTelemetry openTelemetry) {
org.apache.logging.log4j.spi.LoggerContext loggerContextSpi = LogManager.getContext(false);
if (!(loggerContextSpi instanceof LoggerContext)) {
return;
}
LoggerContext loggerContext = (LoggerContext) loggerContextSpi;
Configuration config = loggerContext.getConfiguration();
config
.getAppenders()
.values()
.forEach(
appender -> {
if (appender instanceof OpenTelemetryAppender) {
((OpenTelemetryAppender) appender).setOpenTelemetry(openTelemetry);
}
});
}

@PluginBuilderFactory
public static <B extends Builder<B>> B builder() {
Expand Down Expand Up @@ -97,6 +121,7 @@ public B setCaptureContextDataAttributes(String captureContextDataAttributes) {
return asBuilder();
}

/** Configures the {@link OpenTelemetry} used to append logs. */
@CanIgnoreReturnValue
public B setOpenTelemetry(OpenTelemetry openTelemetry) {
this.openTelemetry = openTelemetry;
Expand All @@ -105,6 +130,10 @@ public B setOpenTelemetry(OpenTelemetry openTelemetry) {

@Override
public OpenTelemetryAppender build() {
OpenTelemetry openTelemetry = this.openTelemetry;
if (openTelemetry == null) {
openTelemetry = OpenTelemetry.noop();
}
return new OpenTelemetryAppender(
getName(),
getLayout(),
Expand Down Expand Up @@ -152,14 +181,14 @@ private static List<String> splitAndFilterBlanksAndNulls(String value) {
.collect(Collectors.toList());
}

/**
* Configures the {@link OpenTelemetry} used to append logs. This MUST be called for the appender
* to function. See {@link #install(OpenTelemetry)} for simple installation option.
*/
public void setOpenTelemetry(OpenTelemetry openTelemetry) {
this.openTelemetry = openTelemetry;
}

private OpenTelemetry getOpenTelemetry() {
return openTelemetry == null ? GlobalOpenTelemetry.get() : openTelemetry;
}

@Override
public void append(LogEvent event) {
String instrumentationName = event.getLoggerName();
Expand All @@ -168,7 +197,7 @@ public void append(LogEvent event) {
}

LogRecordBuilder builder =
getOpenTelemetry()
this.openTelemetry
.getLogsBridge()
.loggerBuilder(instrumentationName)
.build()
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,18 @@
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies;
import static java.util.concurrent.TimeUnit.MILLISECONDS;

import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.logs.Severity;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanContext;
import io.opentelemetry.context.Scope;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
import io.opentelemetry.sdk.logs.SdkLoggerProvider;
import io.opentelemetry.sdk.logs.data.LogRecordData;
import io.opentelemetry.sdk.logs.export.SimpleLogRecordProcessor;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.testing.exporter.InMemoryLogRecordExporter;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
Expand All @@ -30,26 +34,72 @@
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.message.FormattedMessage;
import org.apache.logging.log4j.message.StringMapMessage;
import org.apache.logging.log4j.message.StructuredDataMessage;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

abstract class OpenTelemetryAppenderConfigTestBase {
class OpenTelemetryAppenderTest {

static final Logger logger = LogManager.getLogger("TestLogger");
private static final Logger logger = LogManager.getLogger("TestLogger");

static InMemoryLogRecordExporter logRecordExporter;
static Resource resource;
static InstrumentationScopeInfo instrumentationScopeInfo;
static OpenTelemetry openTelemetry;
private static InMemoryLogRecordExporter logRecordExporter;
private static Resource resource;
private static InstrumentationScopeInfo instrumentationScopeInfo;
private static OpenTelemetry openTelemetry;

@BeforeAll
static void setupAll() {
logRecordExporter = InMemoryLogRecordExporter.create();
resource = Resource.getDefault();
instrumentationScopeInfo = InstrumentationScopeInfo.create("TestLogger");

SdkLoggerProvider loggerProvider =
SdkLoggerProvider.builder()
.setResource(resource)
.addLogRecordProcessor(SimpleLogRecordProcessor.create(logRecordExporter))
.build();

GlobalOpenTelemetry.resetForTest();
jack-berg marked this conversation as resolved.
Show resolved Hide resolved
openTelemetry = OpenTelemetrySdk.builder().setLoggerProvider(loggerProvider).build();
OpenTelemetryAppender.install(openTelemetry);
}

@BeforeEach
void setup() {
logRecordExporter.reset();
ThreadContext.clearAll();
}

@AfterAll
static void cleanupAll() {
// This is to make sure that other test classes don't have issues with the logger provider set
OpenTelemetryAppender.install(null);
}

@Test
void initializeWithBuilder() {
OpenTelemetryAppender appender =
OpenTelemetryAppender.builder()
.setName("OpenTelemetryAppender")
.setOpenTelemetry(openTelemetry)
.build();
appender.start();

appender.append(
Log4jLogEvent.newBuilder()
.setMessage(new FormattedMessage("log message 1", (Object) null))
.build());

List<LogRecordData> logDataList = logRecordExporter.getFinishedLogRecordItems();
assertThat(logDataList)
.satisfiesExactly(logRecordData -> assertThat(logDataList.get(0)).hasBody("log message 1"));
}

@Test
void logNoSpan() {
logger.info("log message 1");
Expand Down
20 changes: 20 additions & 0 deletions instrumentation/logback/logback-appender-1.0/library/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,23 @@ The following demonstrates how you might configure the appender in your `logback

In this example Logback log events will be sent to both the console appender and
the `OpenTelemetryAppender`.

In order to function, `OpenTelemetryAppender` needs access to an `OpenTelemetry` instance. This must
be set programmatically during application startup as follows:

```java
import io.opentelemetry.instrumentation.logback.OpenTelemetryAppender;
import io.opentelemetry.sdk.OpenTelemetrySdk;

public class Application {

public static void main(String[] args) {
OpenTelemetrySdk openTelemetrySdk = // Configure OpenTelemetrySdk

// Find OpenTelemetryAppender in logback configuration and install openTelemetrySdk
OpenTelemetryAppender.install(openTelemetrySdk);

// ... proceed with application
}
}
```
Loading