Skip to content

Commit

Permalink
Add support for jboss-logmanager (open-telemetry#5737)
Browse files Browse the repository at this point in the history
* initialize the package

Signed-off-by: Cuichen Li <[email protected]>

* add jboss-logmanger 2.1 instrumentation

Signed-off-by: Cuichen Li <[email protected]>

* rename the test

Signed-off-by: Cuichen Li <[email protected]>

* clean comment

Signed-off-by: Cuichen Li <[email protected]>

* Revert "Add JBoss java.util.logging support (open-telemetry#5498)"

This reverts commit 8b26cef.

* Remove extra directory

* Remove old jboss log manager test

* Ensure no cross interference

* Change base version to 1.1

* fix styles

Signed-off-by: Cuichen Li <[email protected]>

* run spotless apply

Signed-off-by: Cuichen Li <[email protected]>

* fix codenarc

Signed-off-by: Cuichen Li <[email protected]>

* change the package version and additional module name

Signed-off-by: Cuichen Li <[email protected]>

Co-authored-by: Trask Stalnaker <[email protected]>
  • Loading branch information
2 people authored and RashmiRam committed May 23, 2022
1 parent af4e965 commit bf283a0
Show file tree
Hide file tree
Showing 10 changed files with 323 additions and 73 deletions.
3 changes: 3 additions & 0 deletions instrumentation/java-util-logging/javaagent/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ dependencies {

compileOnly(project(":instrumentation-appender-api-internal"))

// ensure no cross interference
testInstrumentation(project(":instrumentation:jboss-logmanager-1.1:javaagent"))

testImplementation("org.awaitility:awaitility")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,6 @@ public void transform(TypeTransformer transformer) {
.and(takesArguments(1))
.and(takesArgument(0, named("java.util.logging.LogRecord"))),
JavaUtilLoggingInstrumentation.class.getName() + "$LogAdvice");
transformer.applyAdviceToMethod(
isMethod()
.and(isPublic())
.and(named("logRaw"))
.and(takesArguments(1))
.and(takesArgument(0, named("org.jboss.logmanager.ExtLogRecord"))),
JavaUtilLoggingInstrumentation.class.getName() + "$LogAdvice");
}

@SuppressWarnings("unused")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
import io.opentelemetry.sdk.logs.data.Severity
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import spock.lang.Shared
import spock.lang.Unroll

import java.util.logging.Level
Expand All @@ -17,12 +16,7 @@ import static org.awaitility.Awaitility.await

class JavaUtilLoggingTest extends AgentInstrumentationSpecification {

@Shared
private final Object logger = createLogger("abc")

Object createLogger(String name) {
Logger.getLogger(name)
}
private static final Logger logger = Logger.getLogger("abc")

@Unroll
def "test method=#testMethod with testArgs=#testArgs and parent=#parent"() {
Expand Down
25 changes: 0 additions & 25 deletions instrumentation/java-util-logging/jboss-testing/build.gradle.kts

This file was deleted.

29 changes: 29 additions & 0 deletions instrumentation/jboss-logmanager-1.1/javaagent/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
plugins {
id("otel.javaagent-instrumentation")
}

muzzle {
pass {
group.set("org.jboss.logmanager")
module.set("jboss-logmanager")
versions.set("[1.1.0.GA,)")
assertInverse.set(true)
}
}

dependencies {
library("org.jboss.logmanager:jboss-logmanager:1.1.0.GA")

compileOnly(project(":instrumentation-appender-api-internal"))

// ensure no cross interference
testInstrumentation(project(":instrumentation:java-util-logging:javaagent"))

testImplementation("org.awaitility:awaitility")
}

tasks.withType<Test>().configureEach {
// TODO run tests both with and without experimental log attributes
jvmArgs("-Dotel.instrumentation.jboss-logmanager.experimental.capture-mdc-attributes=*")
jvmArgs("-Dotel.instrumentation.jboss-logmanager.experimental-log-attributes=true")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.jbosslogmanager.v1_1;

import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;

import io.opentelemetry.instrumentation.api.appender.internal.LogEmitterProvider;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import io.opentelemetry.javaagent.instrumentation.api.CallDepth;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.jboss.logmanager.ExtLogRecord;
import org.jboss.logmanager.Logger;

public class JbossLogmanagerInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return named("org.jboss.logmanager.Logger");
}

@Override
public void transform(TypeTransformer transformer) {
transformer.applyAdviceToMethod(
isMethod()
.and(isPublic())
.and(named("logRaw"))
.and(takesArguments(1))
.and(takesArgument(0, named("org.jboss.logmanager.ExtLogRecord"))),
JbossLogmanagerInstrumentation.class.getName() + "$CallLogRawAdvice");
}

@SuppressWarnings("unused")
public static class CallLogRawAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static void methodEnter(
@Advice.This() Logger logger,
@Advice.Argument(0) ExtLogRecord record,
@Advice.Local("otelCallDepth") CallDepth callDepth) {
// need to track call depth across all loggers in order to avoid double capture when one
// logging framework delegates to another
callDepth = CallDepth.forClass(LogEmitterProvider.class);
if (callDepth.getAndIncrement() == 0) {
LoggingEventMapper.INSTANCE.capture(logger, record);
}
}

@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void methodExit(@Advice.Local("otelCallDepth") CallDepth callDepth) {
callDepth.decrementAndGet();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.jbosslogmanager.v1_1;

import static java.util.Collections.singletonList;

import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import java.util.List;

@AutoService(InstrumentationModule.class)
public class JbossLogmanagerInstrumentationModule extends InstrumentationModule {

public JbossLogmanagerInstrumentationModule() {
super("jboss-logmanager", "jboss-logmanager-1.1");
}

@Override
public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new JbossLogmanagerInstrumentation());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.jbosslogmanager.v1_1;

import static java.util.Collections.emptyList;

import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.context.Context;
import io.opentelemetry.instrumentation.api.appender.internal.LogBuilder;
import io.opentelemetry.instrumentation.api.appender.internal.Severity;
import io.opentelemetry.instrumentation.api.cache.Cache;
import io.opentelemetry.instrumentation.api.config.Config;
import io.opentelemetry.javaagent.instrumentation.api.appender.internal.AgentLogEmitterProvider;
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.List;
import java.util.Map;
import org.jboss.logmanager.ExtLogRecord;
import org.jboss.logmanager.Level;
import org.jboss.logmanager.Logger;
import org.jboss.logmanager.MDC;

public final class LoggingEventMapper {

public static final LoggingEventMapper INSTANCE = new LoggingEventMapper();

private static final Cache<String, AttributeKey<String>> mdcAttributeKeys = Cache.bounded(100);

private final List<String> captureMdcAttributes;

private static final boolean captureExperimentalAttributes =
Config.get()
.getBoolean("otel.instrumentation.jboss-logmanager.experimental-log-attributes", false);

// cached as an optimization
private final boolean captureAllMdcAttributes;

private LoggingEventMapper() {
this.captureMdcAttributes =
Config.get()
.getList(
"otel.instrumentation.jboss-logmanager.experimental.capture-mdc-attributes",
emptyList());
this.captureAllMdcAttributes =
captureMdcAttributes.size() == 1 && captureMdcAttributes.get(0).equals("*");
}

public void capture(Logger logger, ExtLogRecord record) {
String instrumentationName = logger.getName();
if (instrumentationName == null || instrumentationName.isEmpty()) {
instrumentationName = "ROOT";
}

LogBuilder builder =
AgentLogEmitterProvider.get().logEmitterBuilder(instrumentationName).build().logBuilder();

String message = record.getFormattedMessage();
if (message != null) {
builder.setBody(message);
}

java.util.logging.Level level = record.getLevel();
if (level != null) {
builder.setSeverity(levelToSeverity(level));
builder.setSeverityText(level.toString());
}

AttributesBuilder attributes = Attributes.builder();

Throwable throwable = record.getThrown();
if (throwable != null) {
// TODO (trask) extract method for recording exception into
// instrumentation-appender-api-internal
attributes.put(SemanticAttributes.EXCEPTION_TYPE, throwable.getClass().getName());
attributes.put(SemanticAttributes.EXCEPTION_MESSAGE, throwable.getMessage());
StringWriter writer = new StringWriter();
throwable.printStackTrace(new PrintWriter(writer));
attributes.put(SemanticAttributes.EXCEPTION_STACKTRACE, writer.toString());
}
captureMdcAttributes(attributes);

if (captureExperimentalAttributes) {
Thread currentThread = Thread.currentThread();
attributes.put(SemanticAttributes.THREAD_NAME, currentThread.getName());
attributes.put(SemanticAttributes.THREAD_ID, currentThread.getId());
}

builder.setAttributes(attributes.build());

builder.setContext(Context.current());

builder.emit();
}

private void captureMdcAttributes(AttributesBuilder attributes) {

Map<String, String> context = MDC.copy();

if (captureAllMdcAttributes) {
if (context != null) {
for (Map.Entry<String, String> entry : context.entrySet()) {
attributes.put(
getMdcAttributeKey(String.valueOf(entry.getKey())), String.valueOf(entry.getValue()));
}
}
return;
}

for (String key : captureMdcAttributes) {
Object value = context.get(key);
if (value != null) {
attributes.put(key, value.toString());
}
}
}

public static AttributeKey<String> getMdcAttributeKey(String key) {
return mdcAttributeKeys.computeIfAbsent(
key, k -> AttributeKey.stringKey("jboss-logmanager.mdc." + k));
}

private static Severity levelToSeverity(java.util.logging.Level level) {
int levelInt = level.intValue();
if (levelInt >= Level.FATAL.intValue()) {
return Severity.FATAL;
} else if (levelInt >= Level.ERROR.intValue()) {
return Severity.ERROR;
} else if (levelInt >= Level.WARNING.intValue()) {
return Severity.WARN;
} else if (levelInt >= Level.INFO.intValue()) {
return Severity.INFO;
} else if (levelInt >= Level.DEBUG.intValue()) {
return Severity.DEBUG;
} else if (levelInt >= Level.TRACE.intValue()) {
return Severity.TRACE;
}
return Severity.UNDEFINED_SEVERITY_NUMBER;
}
}
Loading

0 comments on commit bf283a0

Please sign in to comment.