Skip to content

Commit

Permalink
Option to export Logback and Log4j 2 markers (#2529)
Browse files Browse the repository at this point in the history
  • Loading branch information
jeanbisutti committed Oct 20, 2022
1 parent 980b744 commit 4bc9c67
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,10 @@ public static class PreviewConfiguration {

public boolean captureLogbackCodeAttributes;

public boolean captureLogbackMarker;

public boolean captureLog4jMarker;

// this is to support interoperability with other systems
// intentionally not allowing the removal of w3c propagator since that is key to many Azure
// integrated experiences
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,14 @@ private static void enableInstrumentations(Configuration config, Map<String, Str
properties.put(
"otel.instrumentation.logback-appender.experimental.capture-code-attributes", "true");
}
if (config.preview.captureLogbackMarker) {
properties.put(
"otel.instrumentation.logback-appender.experimental.capture-marker-attribute", "true");
}
if (config.preview.captureLog4jMarker) {
properties.put(
"otel.instrumentation.log4j-appender.experimental.capture-marker-attribute", "true");
}
if (config.preview.instrumentation.akka.enabled) {
properties.put("otel.instrumentation.akka-actor.enabled", "true");
properties.put("otel.instrumentation.akka-http.enabled", "true");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.azure.monitor.opentelemetry.exporter.implementation.models.SeverityLevel;
import com.azure.monitor.opentelemetry.exporter.implementation.models.TelemetryItem;
import com.azure.monitor.opentelemetry.exporter.implementation.utils.FormattedTime;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.logs.Severity;
import io.opentelemetry.api.trace.SpanContext;
Expand All @@ -27,6 +28,12 @@ public class LogDataMapper {
private final boolean captureLoggingLevelAsCustomDimension;
private final BiConsumer<AbstractTelemetryBuilder, Resource> telemetryInitializer;

private static final AttributeKey<String> OTEL_LOG4J_MARKER =
AttributeKey.stringKey("log4j.marker");

private static final AttributeKey<String> OTEL_LOGBACK_MARKER =
AttributeKey.stringKey("logback.marker");

public LogDataMapper(
boolean captureLoggingLevelAsCustomDimension,
BiConsumer<AbstractTelemetryBuilder, Resource> telemetryInitializer) {
Expand Down Expand Up @@ -171,6 +178,10 @@ private static void setExtraAttributes(
telemetryBuilder.addProperty("LineNumber", String.valueOf(value));
return;
}
if (OTEL_LOG4J_MARKER.getKey().equals(key) || OTEL_LOGBACK_MARKER.getKey().equals(key)) {
telemetryBuilder.addProperty("Marker", String.valueOf(value));
return;
}
if (key.startsWith(JBOSS_LOGGING_MDC_PREFIX)) {
telemetryBuilder.addProperty(
key.substring(JBOSS_LOGGING_MDC_PREFIX.length()), String.valueOf(value));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import javax.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.MarkerManager;
import org.apache.logging.log4j.ThreadContext;

@WebServlet("/traceLog4j2")
Expand All @@ -22,6 +23,7 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) {
logger.info("This is log4j2 info.");
ThreadContext.put("MDC key", "MDC value");
logger.warn("This is log4j2 warn.");
logger.warn(MarkerManager.getMarker("aMarker"), "Warn with marker");
ThreadContext.remove("MDC key");
logger.error("This is log4j2 error.");
logger.fatal("This is log4j2 fatal.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
abstract class TraceLog4j2Test {

@RegisterExtension static final SmokeTestExtension testing = SmokeTestExtension.create();
private static final String TRACE_OPERATION_NAME = "GET /TraceLog4j2UsingAgent/traceLog4j2";

@Test
@TargetUri("/traceLog4j2")
Expand All @@ -38,16 +39,18 @@ void testTraceLog4j2() throws Exception {

Envelope rdEnvelope = rdList.get(0);
String operationId = rdEnvelope.getTags().get("ai.operation.id");
List<Envelope> mdList = testing.mockedIngestion.waitForMessageItemsInRequest(3, operationId);
List<Envelope> mdList = testing.mockedIngestion.waitForMessageItemsInRequest(4, operationId);

Envelope mdEnvelope1 = mdList.get(0);
Envelope mdEnvelope2 = mdList.get(1);
Envelope mdEnvelope3 = mdList.get(2);
Envelope mdEnvelope4 = mdList.get(3);

assertThat(rdEnvelope.getSampleRate()).isNull();
assertThat(mdEnvelope1.getSampleRate()).isNull();
assertThat(mdEnvelope2.getSampleRate()).isNull();
assertThat(mdEnvelope3.getSampleRate()).isNull();
assertThat(mdEnvelope4.getSampleRate()).isNull();

RequestData rd = (RequestData) ((Data<?>) rdEnvelope.getData()).getBaseData();

Expand All @@ -57,6 +60,7 @@ void testTraceLog4j2() throws Exception {
MessageData md1 = logs.get(0);
MessageData md2 = logs.get(1);
MessageData md3 = logs.get(2);
MessageData md4 = logs.get(3);

assertThat(md1.getMessage()).isEqualTo("This is log4j2 warn.");
assertThat(md1.getSeverityLevel()).isEqualTo(SeverityLevel.WARNING);
Expand All @@ -66,26 +70,26 @@ void testTraceLog4j2() throws Exception {
assertThat(md1.getProperties()).containsEntry("MDC key", "MDC value");
assertThat(md1.getProperties()).hasSize(4);

assertThat(md2.getMessage()).isEqualTo("This is log4j2 error.");
assertThat(md2.getSeverityLevel()).isEqualTo(SeverityLevel.ERROR);
assertThat(md2.getProperties()).containsEntry("SourceType", "Logger");
assertThat(md1.getProperties()).containsEntry("LoggerName", "smoketestapp");
assertThat(md1.getProperties()).containsKey("ThreadName");
assertThat(md2.getProperties()).hasSize(3);
assertThat(md2.getProperties()).containsEntry("Marker", "aMarker");

assertThat(md3.getMessage()).isEqualTo("This is log4j2 fatal.");
assertThat(md3.getSeverityLevel()).isEqualTo(SeverityLevel.CRITICAL);
assertThat(md3.getMessage()).isEqualTo("This is log4j2 error.");
assertThat(md3.getSeverityLevel()).isEqualTo(SeverityLevel.ERROR);
assertThat(md3.getProperties()).containsEntry("SourceType", "Logger");
assertThat(md3.getProperties()).containsEntry("LoggerName", "smoketestapp");
assertThat(md3.getProperties()).containsKey("ThreadName");
assertThat(md1.getProperties()).containsEntry("LoggerName", "smoketestapp");
assertThat(md1.getProperties()).containsKey("ThreadName");
assertThat(md3.getProperties()).hasSize(3);

SmokeTestExtension.assertParentChild(
rd, rdEnvelope, mdEnvelope1, "GET /TraceLog4j2UsingAgent/traceLog4j2");
SmokeTestExtension.assertParentChild(
rd, rdEnvelope, mdEnvelope2, "GET /TraceLog4j2UsingAgent/traceLog4j2");
SmokeTestExtension.assertParentChild(
rd, rdEnvelope, mdEnvelope3, "GET /TraceLog4j2UsingAgent/traceLog4j2");
assertThat(md4.getMessage()).isEqualTo("This is log4j2 fatal.");
assertThat(md4.getSeverityLevel()).isEqualTo(SeverityLevel.CRITICAL);
assertThat(md4.getProperties()).containsEntry("SourceType", "Logger");
assertThat(md4.getProperties()).containsEntry("LoggerName", "smoketestapp");
assertThat(md4.getProperties()).containsKey("ThreadName");
assertThat(md4.getProperties()).hasSize(3);

SmokeTestExtension.assertParentChild(rd, rdEnvelope, mdEnvelope1, TRACE_OPERATION_NAME);
SmokeTestExtension.assertParentChild(rd, rdEnvelope, mdEnvelope2, TRACE_OPERATION_NAME);
SmokeTestExtension.assertParentChild(rd, rdEnvelope, mdEnvelope3, TRACE_OPERATION_NAME);
SmokeTestExtension.assertParentChild(rd, rdEnvelope, mdEnvelope4, TRACE_OPERATION_NAME);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,8 @@
"logging": {
"level": "warn"
}
},
"preview": {
"captureLog4jMarker": true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;

@WebServlet("/traceLogBack")
public class SimpleTestTraceLogBackServlet extends HttpServlet {
Expand All @@ -24,5 +26,8 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) {
logger.warn("This is logback warn.");
MDC.remove("MDC key");
logger.error("This is logback error.");

Marker marker = MarkerFactory.getMarker("aMarker");
logger.error(marker, "Log with marker");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,11 @@ abstract class TraceLogBackTest {

@RegisterExtension static final SmokeTestExtension testing = SmokeTestExtension.create();

boolean checkLogBackCodeAttributes() {
return true;
// Not really sure that Logback is enabled with Wildfly
// https://anotheria.net/blog/devops/enable-logback-in-jboss/
// https://www.oreilly.com/library/view/wildfly-cookbook/9781784392413/ch04s08.html
boolean isWildflyServer() {
return false;
}

@Test
Expand All @@ -41,7 +44,7 @@ void testTraceLogBack() throws Exception {

Envelope rdEnvelope = rdList.get(0);
String operationId = rdEnvelope.getTags().get("ai.operation.id");
List<Envelope> mdList = testing.mockedIngestion.waitForMessageItemsInRequest(2, operationId);
List<Envelope> mdList = testing.mockedIngestion.waitForMessageItemsInRequest(3, operationId);

Envelope mdEnvelope1 = mdList.get(0);
Envelope mdEnvelope2 = mdList.get(1);
Expand All @@ -57,50 +60,53 @@ void testTraceLogBack() throws Exception {

MessageData md1 = logs.get(0);
MessageData md2 = logs.get(1);
MessageData md3 = logs.get(2);

assertThat(md1.getMessage()).isEqualTo("This is logback warn.");
assertThat(md1.getSeverityLevel()).isEqualTo(SeverityLevel.WARNING);
assertThat(md1.getProperties()).containsEntry("SourceType", "Logger");
assertThat(md1.getProperties()).containsEntry("LoggerName", "smoketestapp");
assertThat(md1.getProperties()).containsKey("ThreadName");
assertThat(md1.getProperties()).containsEntry("MDC key", "MDC value");
assertThat(md1.getProperties())
.containsEntry("SourceType", "Logger")
.containsEntry("LoggerName", "smoketestapp")
.containsKey("ThreadName")
.containsEntry("MDC key", "MDC value");

if (checkLogBackCodeAttributes()) {
assertThat(md1.getProperties())
.containsEntry("FileName", "SimpleTestTraceLogBackServlet.java");
if (!isWildflyServer()) {
assertThat(md1.getProperties())
.containsEntry("FileName", "SimpleTestTraceLogBackServlet.java")
.containsEntry(
"ClassName",
"com.microsoft.applicationinsights.smoketestapp.SimpleTestTraceLogBackServlet");
assertThat(md1.getProperties()).containsEntry("MethodName", "doGet");
assertThat(md1.getProperties()).containsEntry("LineNumber", "24");

assertThat(md1.getProperties()).hasSize(8);
"com.microsoft.applicationinsights.smoketestapp.SimpleTestTraceLogBackServlet")
.containsEntry("MethodName", "doGet")
.containsEntry("LineNumber", "26")
.hasSize(8);
} else {
assertThat(md1.getProperties()).hasSize(4);
}

assertThat(md2.getMessage()).isEqualTo("This is logback error.");
assertThat(md2.getSeverityLevel()).isEqualTo(SeverityLevel.ERROR);
assertThat(md2.getProperties()).containsEntry("SourceType", "Logger");
assertThat(md2.getProperties()).containsEntry("LoggerName", "smoketestapp");
assertThat(md2.getProperties()).containsKey("ThreadName");
assertThat(md2.getProperties())
.containsEntry("SourceType", "Logger")
.containsEntry("LoggerName", "smoketestapp")
.containsKey("ThreadName");

if (checkLogBackCodeAttributes()) {
assertThat(md2.getProperties())
.containsEntry("FileName", "SimpleTestTraceLogBackServlet.java");
if (!isWildflyServer()) {
assertThat(md2.getProperties())
.containsEntry("FileName", "SimpleTestTraceLogBackServlet.java")
.containsEntry(
"ClassName",
"com.microsoft.applicationinsights.smoketestapp.SimpleTestTraceLogBackServlet");
assertThat(md2.getProperties()).containsEntry("MethodName", "doGet");
assertThat(md2.getProperties()).containsEntry("LineNumber", "26");

assertThat(md2.getProperties()).hasSize(7);
"com.microsoft.applicationinsights.smoketestapp.SimpleTestTraceLogBackServlet")
.containsEntry("MethodName", "doGet")
.containsEntry("LineNumber", "28")
.hasSize(7);
} else {
assertThat(md2.getProperties()).hasSize(3);
}

if (!isWildflyServer()) {
assertThat(md3.getProperties()).containsEntry("Marker", "aMarker");
}

SmokeTestExtension.assertParentChild(
rd, rdEnvelope, mdEnvelope1, "GET /TraceLogBackUsingAgent/traceLogBack");
SmokeTestExtension.assertParentChild(
Expand Down Expand Up @@ -128,22 +134,22 @@ void testTraceLogBackWithException() throws Exception {

assertThat(ed.getExceptions().get(0).getMessage()).isEqualTo("Fake Exception");
assertThat(ed.getSeverityLevel()).isEqualTo(SeverityLevel.ERROR);
assertThat(ed.getProperties()).containsEntry("Logger Message", "This is an exception!");
assertThat(ed.getProperties()).containsEntry("SourceType", "Logger");
assertThat(ed.getProperties()).containsEntry("LoggerName", "smoketestapp");
assertThat(ed.getProperties()).containsKey("ThreadName");
assertThat(ed.getProperties()).containsEntry("MDC key", "MDC value");

if (checkLogBackCodeAttributes()) {
assertThat(ed.getProperties())
.containsEntry("FileName", "SimpleTestTraceLogBackWithExceptionServlet.java");
assertThat(ed.getProperties())
.containsEntry("Logger Message", "This is an exception!")
.containsEntry("SourceType", "Logger")
.containsEntry("LoggerName", "smoketestapp")
.containsKey("ThreadName")
.containsEntry("MDC key", "MDC value");

if (!isWildflyServer()) {
assertThat(ed.getProperties())
.containsEntry("FileName", "SimpleTestTraceLogBackWithExceptionServlet.java")
.containsEntry(
"ClassName",
"com.microsoft.applicationinsights.smoketestapp.SimpleTestTraceLogBackWithExceptionServlet");
assertThat(ed.getProperties()).containsEntry("MethodName", "doGet");
assertThat(ed.getProperties()).containsEntry("LineNumber", "21");
assertThat(ed.getProperties()).hasSize(9);
"com.microsoft.applicationinsights.smoketestapp.SimpleTestTraceLogBackWithExceptionServlet")
.containsEntry("MethodName", "doGet")
.containsEntry("LineNumber", "21")
.hasSize(9);
} else {
assertThat(ed.getProperties()).hasSize(5);
}
Expand Down Expand Up @@ -176,16 +182,16 @@ static class Tomcat8Java19Test extends TraceLogBackTest {}
@Environment(WILDFLY_13_JAVA_8)
static class Wildfly13Java8Test extends TraceLogBackTest {
@Override
boolean checkLogBackCodeAttributes() {
return false;
boolean isWildflyServer() {
return true;
}
}

@Environment(WILDFLY_13_JAVA_8_OPENJ9)
static class Wildfly13Java8OpenJ9Test extends TraceLogBackTest {
@Override
boolean checkLogBackCodeAttributes() {
return false;
boolean isWildflyServer() {
return true;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
}
},
"preview": {
"captureLogbackCodeAttributes": true
"captureLogbackCodeAttributes": true,
"captureLogbackMarker": true
}
}

0 comments on commit 4bc9c67

Please sign in to comment.