diff --git a/apm-agent-plugins/apm-logging-plugin/apm-jboss-logging-plugin/pom.xml b/apm-agent-plugins/apm-logging-plugin/apm-jboss-logging-plugin/pom.xml
index 44760ec057..6989066900 100644
--- a/apm-agent-plugins/apm-logging-plugin/apm-jboss-logging-plugin/pom.xml
+++ b/apm-agent-plugins/apm-logging-plugin/apm-jboss-logging-plugin/pom.xml
@@ -27,6 +27,24 @@
3.4.2.Final
provided
+
+ org.jboss.logmanager
+ jboss-logmanager
+ 2.1.18.Final
+ provided
+
+
+
+
+ maven-surefire-plugin
+
+
+ org.jboss.logmanager.LogManager
+
+
+
+
+
diff --git a/apm-agent-plugins/apm-logging-plugin/apm-jboss-logging-plugin/src/main/java/co/elastic/apm/agent/jbosslogging/correlation/JBossLogManagerCorrelationHelper.java b/apm-agent-plugins/apm-logging-plugin/apm-jboss-logging-plugin/src/main/java/co/elastic/apm/agent/jbosslogging/correlation/JBossLogManagerCorrelationHelper.java
new file mode 100644
index 0000000000..f7bf3889fd
--- /dev/null
+++ b/apm-agent-plugins/apm-logging-plugin/apm-jboss-logging-plugin/src/main/java/co/elastic/apm/agent/jbosslogging/correlation/JBossLogManagerCorrelationHelper.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package co.elastic.apm.agent.jbosslogging.correlation;
+
+import co.elastic.apm.agent.loginstr.correlation.AbstractLogCorrelationHelper;
+import org.jboss.logmanager.ExtLogRecord;
+
+public class JBossLogManagerCorrelationHelper extends AbstractLogCorrelationHelper.DefaultLogCorrelationHelper {
+
+ private final ThreadLocal cachedRecord = new ThreadLocal<>();
+
+ public boolean beforeLoggingEvent(ExtLogRecord record) {
+ cachedRecord.set(record);
+ return super.beforeLoggingEvent();
+ }
+
+ @Override
+ public void afterLoggingEvent(boolean addedToMdc) {
+ super.afterLoggingEvent(addedToMdc);
+ cachedRecord.remove();
+ }
+
+ @Override
+ protected void addToMdc(String key, String value) {
+ cachedRecord.get().putMdc(key, value);
+ }
+
+ @Override
+ protected void removeFromMdc(String key) {
+ }
+}
diff --git a/apm-agent-plugins/apm-logging-plugin/apm-jboss-logging-plugin/src/main/java/co/elastic/apm/agent/jbosslogging/correlation/JBossLogManagerCorrelationInstrumentation.java b/apm-agent-plugins/apm-logging-plugin/apm-jboss-logging-plugin/src/main/java/co/elastic/apm/agent/jbosslogging/correlation/JBossLogManagerCorrelationInstrumentation.java
new file mode 100644
index 0000000000..5d73d83056
--- /dev/null
+++ b/apm-agent-plugins/apm-logging-plugin/apm-jboss-logging-plugin/src/main/java/co/elastic/apm/agent/jbosslogging/correlation/JBossLogManagerCorrelationInstrumentation.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package co.elastic.apm.agent.jbosslogging.correlation;
+
+import co.elastic.apm.agent.bci.TracerAwareInstrumentation;
+import net.bytebuddy.asm.Advice;
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.description.type.TypeDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.jboss.logmanager.ExtLogRecord;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import static co.elastic.apm.agent.bci.bytebuddy.CustomElementMatchers.classLoaderCanLoadClass;
+import static net.bytebuddy.matcher.ElementMatchers.isBootstrapClassLoader;
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.not;
+import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
+
+/**
+ * Instruments {@link org.jboss.logmanager.Logger#logRaw}
+ */
+public class JBossLogManagerCorrelationInstrumentation extends TracerAwareInstrumentation {
+
+ @Override
+ public Collection getInstrumentationGroupNames() {
+ return Collections.singleton("jboss-logging-correlation");
+ }
+
+ @Override
+ public ElementMatcher.Junction getClassLoaderMatcher() {
+ return not(isBootstrapClassLoader())
+ .and(classLoaderCanLoadClass("org.jboss.logmanager.Logger"));
+ }
+
+ @Override
+ public ElementMatcher super TypeDescription> getTypeMatcher() {
+ return named("org.jboss.logmanager.Logger");
+ }
+
+ @Override
+ public ElementMatcher super MethodDescription> getMethodMatcher() {
+ return named("logRaw").and(takesArgument(0, named("org.jboss.logmanager.ExtLogRecord")));
+ }
+
+ public static class AdviceClass {
+ private static final JBossLogManagerCorrelationHelper helper = new JBossLogManagerCorrelationHelper();
+
+ @Advice.OnMethodEnter(suppress = Throwable.class, inline = false)
+ public static boolean addToMdc(@Advice.Argument(0) ExtLogRecord record) {
+ return helper.beforeLoggingEvent(record);
+ }
+
+ @Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class, inline = false)
+ public static void removeFromMdc(@Advice.Enter boolean addedToMdc) {
+ helper.afterLoggingEvent(addedToMdc);
+ }
+ }
+}
diff --git a/apm-agent-plugins/apm-logging-plugin/apm-jboss-logging-plugin/src/main/resources/META-INF/services/co.elastic.apm.agent.sdk.ElasticApmInstrumentation b/apm-agent-plugins/apm-logging-plugin/apm-jboss-logging-plugin/src/main/resources/META-INF/services/co.elastic.apm.agent.sdk.ElasticApmInstrumentation
index 25455d58f7..97c7e41a1a 100644
--- a/apm-agent-plugins/apm-logging-plugin/apm-jboss-logging-plugin/src/main/resources/META-INF/services/co.elastic.apm.agent.sdk.ElasticApmInstrumentation
+++ b/apm-agent-plugins/apm-logging-plugin/apm-jboss-logging-plugin/src/main/resources/META-INF/services/co.elastic.apm.agent.sdk.ElasticApmInstrumentation
@@ -1 +1,2 @@
co.elastic.apm.agent.jbosslogging.correlation.JBossLoggingCorrelationInstrumentation
+co.elastic.apm.agent.jbosslogging.correlation.JBossLogManagerCorrelationInstrumentation
diff --git a/apm-agent-plugins/apm-logging-plugin/apm-jboss-logging-plugin/src/test/java/co/elastic/apm/agent/jbosslogging/correlation/JBossLogManagerCorrelationInstrumentationTest.java b/apm-agent-plugins/apm-logging-plugin/apm-jboss-logging-plugin/src/test/java/co/elastic/apm/agent/jbosslogging/correlation/JBossLogManagerCorrelationInstrumentationTest.java
new file mode 100644
index 0000000000..61357f37f0
--- /dev/null
+++ b/apm-agent-plugins/apm-logging-plugin/apm-jboss-logging-plugin/src/test/java/co/elastic/apm/agent/jbosslogging/correlation/JBossLogManagerCorrelationInstrumentationTest.java
@@ -0,0 +1,137 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package co.elastic.apm.agent.jbosslogging.correlation;
+
+import co.elastic.apm.agent.AbstractInstrumentationTest;
+import co.elastic.apm.agent.impl.TextHeaderMapAccessor;
+import co.elastic.apm.agent.impl.error.ErrorCapture;
+import co.elastic.apm.agent.impl.transaction.TraceContext;
+import co.elastic.apm.agent.impl.transaction.Transaction;
+import co.elastic.apm.agent.loginstr.correlation.AbstractLogCorrelationHelper;
+import org.jboss.logmanager.ExtHandler;
+import org.jboss.logmanager.ExtLogRecord;
+import org.jboss.logmanager.Level;
+import org.jboss.logmanager.LogManager;
+import org.jboss.logmanager.Logger;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+import java.util.Map;
+import java.util.Objects;
+
+import static co.elastic.apm.agent.impl.transaction.TraceContext.W3C_TRACE_PARENT_TEXTUAL_HEADER_NAME;
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class JBossLogManagerCorrelationInstrumentationTest extends AbstractInstrumentationTest {
+
+ public static final String LOGGER_NAME = "Test-Logger";
+
+ private static final LoggingCorrelationVerifier loggingCorrelationVerifier = new LoggingCorrelationVerifier();
+ private static Logger logger;
+
+ private Transaction transaction;
+
+ @BeforeAll
+ static void initializeLogger() {
+ logger = (org.jboss.logmanager.Logger) LogManager.getLogManager().getLogger(LOGGER_NAME);
+ logger.addHandler(new LoggingCorrelationVerifier());
+ }
+
+ @BeforeEach
+ public void setup() {
+ transaction = Objects.requireNonNull(tracer.startRootTransaction(null)).activate();
+ loggingCorrelationVerifier.reset();
+ }
+
+ @AfterEach
+ public void tearDown() {
+ transaction.deactivate().end();
+ }
+
+ @Test
+ public void testSimple() {
+ assertThat(loggingCorrelationVerifier.isVerified()).isFalse();
+ // TraceContext#toString() returns the text representation of the traceparent header
+ logger.info(transaction.getTraceContext().toString());
+ assertThat(loggingCorrelationVerifier.isVerified()).isTrue();
+ }
+
+ // todo: enable once support for jboss-logmanager error logging is added
+ @Test
+ @Disabled
+ public void testErrorLogging() {
+ assertThat(loggingCorrelationVerifier.isVerified()).isFalse();
+ // TraceContext#toString() returns the text representation of the traceparent header
+ logger.log(Level.ERROR, transaction.getTraceContext().toString(), new RuntimeException());
+ assertThat(loggingCorrelationVerifier.isVerified()).isTrue();
+ }
+
+ private static class LoggingCorrelationVerifier extends ExtHandler {
+ private boolean verified;
+
+ public void reset() {
+ verified = false;
+ }
+
+ public boolean isVerified() {
+ return verified;
+ }
+
+ public void setVerified() {
+ verified = true;
+ }
+
+ @Override
+ protected void doPublish(ExtLogRecord record) {
+ try {
+ Object traceId = record.getMdc(AbstractLogCorrelationHelper.TRACE_ID_MDC_KEY);
+ System.out.println("traceId = " + traceId);
+ assertThat(traceId).isNotNull();
+ Object transactionId = record.getMdc(AbstractLogCorrelationHelper.TRANSACTION_ID_MDC_KEY);
+ System.out.println("transactionId = " + transactionId);
+ assertThat(transactionId).isNotNull();
+ Object errorId = record.getMdc(AbstractLogCorrelationHelper.ERROR_ID_MDC_KEY);
+ System.out.println("errorId = " + transactionId);
+ boolean shouldContainErrorId = record.getLevel().getName().equals("ERROR");
+ String traceParent = record.getMessage();
+ assertThat(traceParent).isNotNull();
+ Map textHeaderMap = Map.of(W3C_TRACE_PARENT_TEXTUAL_HEADER_NAME, traceParent);
+ TraceContext childTraceContext = TraceContext.with64BitId(tracer);
+ TraceContext.