diff --git a/activemq-opentelemetry/pom.xml b/activemq-opentelemetry/pom.xml new file mode 100644 index 00000000000..e60ad1809c9 --- /dev/null +++ b/activemq-opentelemetry/pom.xml @@ -0,0 +1,115 @@ + + + + + 4.0.0 + + + org.apache.activemq + activemq-parent + 6.3.0-SNAPSHOT + + + activemq-opentelemetry + bundle + ActiveMQ :: OpenTelemetry + ActiveMQ OpenTelemetry tracing support + + + + + + + + ${project.groupId} + activemq-broker + + + + io.opentelemetry + opentelemetry-api + + + io.opentelemetry + opentelemetry-context + + + + + + + ${project.groupId} + activemq-kahadb-store + test + + + ${project.groupId} + activemq-broker + test-jar + test + + + io.opentelemetry + opentelemetry-sdk-testing + test + + + io.opentelemetry + opentelemetry-sdk + test + + + junit + junit + test + + + org.apache.logging.log4j + log4j-slf4j2-impl + test + + + org.apache.logging.log4j + log4j-core + test + + + + + + + org.apache.felix + maven-bundle-plugin + true + + + org.apache.activemq.opentelemetry + org.apache.activemq.broker.util.opentelemetry*;version=${project.version};-noimport:=true;-split-package:=merge-first + + org.apache.activemq*;version=${project.version};resolution:=optional, + io.opentelemetry.*;resolution:=optional, + * + + <_noee>true + + + + + + + diff --git a/activemq-opentelemetry/src/main/java/org/apache/activemq/broker/util/opentelemetry/ActiveMQMessageTextMapGetter.java b/activemq-opentelemetry/src/main/java/org/apache/activemq/broker/util/opentelemetry/ActiveMQMessageTextMapGetter.java new file mode 100644 index 00000000000..a3835ad5690 --- /dev/null +++ b/activemq-opentelemetry/src/main/java/org/apache/activemq/broker/util/opentelemetry/ActiveMQMessageTextMapGetter.java @@ -0,0 +1,53 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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 org.apache.activemq.broker.util.opentelemetry; + +import java.io.IOException; +import java.util.Collections; + +import io.opentelemetry.context.propagation.TextMapGetter; +import org.apache.activemq.command.Message; + +public class ActiveMQMessageTextMapGetter implements TextMapGetter { + + public static final ActiveMQMessageTextMapGetter INSTANCE = new ActiveMQMessageTextMapGetter(); + + @Override + public Iterable keys(Message message) { + try { + if (message.getProperties() != null) { + return message.getProperties().keySet(); + } + } catch (IOException e) { + // ignore + } + return Collections.emptyList(); + } + + @Override + public String get(Message message, String key) { + try { + Object value = message.getProperty(key); + if (value instanceof String) { + return (String) value; + } + } catch (IOException e) { + // ignore + } + return null; + } +} diff --git a/activemq-opentelemetry/src/main/java/org/apache/activemq/broker/util/opentelemetry/ActiveMQMessageTextMapSetter.java b/activemq-opentelemetry/src/main/java/org/apache/activemq/broker/util/opentelemetry/ActiveMQMessageTextMapSetter.java new file mode 100644 index 00000000000..152129ad4a6 --- /dev/null +++ b/activemq-opentelemetry/src/main/java/org/apache/activemq/broker/util/opentelemetry/ActiveMQMessageTextMapSetter.java @@ -0,0 +1,41 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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 org.apache.activemq.broker.util.opentelemetry; + +import java.io.IOException; + +import io.opentelemetry.context.propagation.TextMapSetter; +import org.apache.activemq.command.Message; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ActiveMQMessageTextMapSetter implements TextMapSetter { + + private static final Logger LOG = LoggerFactory.getLogger(ActiveMQMessageTextMapSetter.class); + + public static final ActiveMQMessageTextMapSetter INSTANCE = new ActiveMQMessageTextMapSetter(); + + @Override + public void set(Message message, String key, String value) { + try { + message.setProperty(key, value); + message.setMarshalledProperties(null); + } catch (IOException e) { + LOG.warn("Failed to set trace context property '{}' on message", key, e); + } + } +} diff --git a/activemq-opentelemetry/src/main/java/org/apache/activemq/broker/util/opentelemetry/OpenTelemetryBrokerPlugin.java b/activemq-opentelemetry/src/main/java/org/apache/activemq/broker/util/opentelemetry/OpenTelemetryBrokerPlugin.java new file mode 100644 index 00000000000..b30bd9b5b86 --- /dev/null +++ b/activemq-opentelemetry/src/main/java/org/apache/activemq/broker/util/opentelemetry/OpenTelemetryBrokerPlugin.java @@ -0,0 +1,202 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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 org.apache.activemq.broker.util.opentelemetry; + +import java.util.concurrent.ConcurrentHashMap; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanBuilder; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.propagation.TextMapPropagator; +import org.apache.activemq.broker.BrokerPluginSupport; +import org.apache.activemq.broker.ConsumerBrokerExchange; +import org.apache.activemq.broker.ProducerBrokerExchange; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.MessageAck; +import org.apache.activemq.command.MessageDispatch; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A broker plugin that provides OpenTelemetry distributed tracing support. + * Traces message send, dispatch, and acknowledge operations with proper + * context propagation via W3C TraceContext. + * + * @org.apache.xbean.XBean element="openTelemetryPlugin" + */ +public class OpenTelemetryBrokerPlugin extends BrokerPluginSupport { + + private static final Logger LOG = LoggerFactory.getLogger(OpenTelemetryBrokerPlugin.class); + private static final String INSTRUMENTATION_NAME = "org.apache.activemq"; + + private boolean traceProducer = true; + private boolean traceConsumer = true; + private boolean traceAcknowledge = true; + + private final ConcurrentHashMap dispatchSpans = new ConcurrentHashMap<>(); + + public boolean isTraceProducer() { + return traceProducer; + } + + public void setTraceProducer(boolean traceProducer) { + this.traceProducer = traceProducer; + } + + public boolean isTraceConsumer() { + return traceConsumer; + } + + public void setTraceConsumer(boolean traceConsumer) { + this.traceConsumer = traceConsumer; + } + + public boolean isTraceAcknowledge() { + return traceAcknowledge; + } + + public void setTraceAcknowledge(boolean traceAcknowledge) { + this.traceAcknowledge = traceAcknowledge; + } + + @Override + public void send(ProducerBrokerExchange producerExchange, Message messageSend) throws Exception { + if (!traceProducer) { + super.send(producerExchange, messageSend); + return; + } + + TextMapPropagator propagator = GlobalOpenTelemetry.getPropagators().getTextMapPropagator(); + Tracer tracer = GlobalOpenTelemetry.getTracer(INSTRUMENTATION_NAME); + + // Extract any existing context from the message (e.g., set by client) + Context parentContext = propagator.extract(Context.current(), messageSend, ActiveMQMessageTextMapGetter.INSTANCE); + + String destinationName = messageSend.getDestination().getPhysicalName(); + SpanBuilder spanBuilder = tracer.spanBuilder(destinationName + " publish") + .setSpanKind(SpanKind.PRODUCER) + .setParent(parentContext) + .setAttribute("messaging.system", "activemq") + .setAttribute("messaging.destination.name", destinationName) + .setAttribute("messaging.operation", "publish"); + + if (messageSend.getMessageId() != null) { + spanBuilder.setAttribute("messaging.message.id", messageSend.getMessageId().toString()); + } + if (producerExchange.getConnectionContext() != null + && producerExchange.getConnectionContext().getClientId() != null) { + spanBuilder.setAttribute("messaging.client_id", producerExchange.getConnectionContext().getClientId()); + } + + Span span = spanBuilder.startSpan(); + try { + // Inject trace context into the message for downstream propagation + Context contextWithSpan = parentContext.with(span); + propagator.inject(contextWithSpan, messageSend, ActiveMQMessageTextMapSetter.INSTANCE); + + super.send(producerExchange, messageSend); + } catch (Exception e) { + span.setStatus(StatusCode.ERROR, e.getMessage()); + span.recordException(e); + throw e; + } finally { + span.end(); + } + } + + @Override + public void preProcessDispatch(MessageDispatch messageDispatch) { + if (traceConsumer && messageDispatch != null && messageDispatch.getMessage() != null) { + try { + TextMapPropagator propagator = GlobalOpenTelemetry.getPropagators().getTextMapPropagator(); + Tracer tracer = GlobalOpenTelemetry.getTracer(INSTRUMENTATION_NAME); + + Message message = messageDispatch.getMessage(); + Context extractedContext = propagator.extract(Context.current(), message, ActiveMQMessageTextMapGetter.INSTANCE); + + String destinationName = message.getDestination().getPhysicalName(); + SpanBuilder spanBuilder = tracer.spanBuilder(destinationName + " deliver") + .setSpanKind(SpanKind.CONSUMER) + .setParent(extractedContext) + .setAttribute("messaging.system", "activemq") + .setAttribute("messaging.destination.name", destinationName) + .setAttribute("messaging.operation", "deliver"); + + if (message.getMessageId() != null) { + spanBuilder.setAttribute("messaging.message.id", message.getMessageId().toString()); + } + + Span span = spanBuilder.startSpan(); + dispatchSpans.put(messageDispatch, span); + } catch (Exception e) { + LOG.warn("Failed to create deliver span", e); + } + } + super.preProcessDispatch(messageDispatch); + } + + @Override + public void postProcessDispatch(MessageDispatch messageDispatch) { + if (messageDispatch != null) { + Span span = dispatchSpans.remove(messageDispatch); + if (span != null) { + span.end(); + } + } + super.postProcessDispatch(messageDispatch); + } + + @Override + public void acknowledge(ConsumerBrokerExchange consumerExchange, MessageAck ack) throws Exception { + if (!traceAcknowledge) { + super.acknowledge(consumerExchange, ack); + return; + } + + Tracer tracer = GlobalOpenTelemetry.getTracer(INSTRUMENTATION_NAME); + + String destinationName = ack.getDestination() != null ? ack.getDestination().getPhysicalName() : "unknown"; + SpanBuilder spanBuilder = tracer.spanBuilder(destinationName + " ack") + .setSpanKind(SpanKind.INTERNAL) + .setAttribute("messaging.system", "activemq") + .setAttribute("messaging.destination.name", destinationName) + .setAttribute("messaging.operation", "ack"); + + if (ack.getLastMessageId() != null) { + spanBuilder.setAttribute("messaging.message.id", ack.getLastMessageId().toString()); + } + if (consumerExchange.getConnectionContext() != null + && consumerExchange.getConnectionContext().getClientId() != null) { + spanBuilder.setAttribute("messaging.client_id", consumerExchange.getConnectionContext().getClientId()); + } + + Span span = spanBuilder.startSpan(); + try { + super.acknowledge(consumerExchange, ack); + } catch (Exception e) { + span.setStatus(StatusCode.ERROR, e.getMessage()); + span.recordException(e); + throw e; + } finally { + span.end(); + } + } +} diff --git a/activemq-opentelemetry/src/test/java/org/apache/activemq/broker/util/opentelemetry/OpenTelemetryBrokerPluginTest.java b/activemq-opentelemetry/src/test/java/org/apache/activemq/broker/util/opentelemetry/OpenTelemetryBrokerPluginTest.java new file mode 100644 index 00000000000..80834d464f7 --- /dev/null +++ b/activemq-opentelemetry/src/test/java/org/apache/activemq/broker/util/opentelemetry/OpenTelemetryBrokerPluginTest.java @@ -0,0 +1,244 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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 org.apache.activemq.broker.util.opentelemetry; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import jakarta.jms.Connection; +import jakarta.jms.DeliveryMode; +import jakarta.jms.MessageConsumer; +import jakarta.jms.MessageProducer; +import jakarta.jms.Session; +import jakarta.jms.TextMessage; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; +import io.opentelemetry.context.propagation.ContextPropagators; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; +import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerPlugin; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class OpenTelemetryBrokerPluginTest { + + private BrokerService broker; + private TransportConnector connector; + private InMemorySpanExporter spanExporter; + private Connection connection; + private Session session; + private final String queueName = "TEST.OTEL"; + + @Before + public void setUp() throws Exception { + GlobalOpenTelemetry.resetForTest(); + + spanExporter = InMemorySpanExporter.create(); + SdkTracerProvider tracerProvider = SdkTracerProvider.builder() + .addSpanProcessor(SimpleSpanProcessor.create(spanExporter)) + .build(); + + OpenTelemetrySdk.builder() + .setTracerProvider(tracerProvider) + .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) + .buildAndRegisterGlobal(); + + OpenTelemetryBrokerPlugin plugin = new OpenTelemetryBrokerPlugin(); + + broker = new BrokerService(); + broker.setBrokerName("otelTestBroker"); + broker.setPersistent(false); + broker.setUseJmx(false); + broker.setPlugins(new BrokerPlugin[]{plugin}); + connector = broker.addConnector("tcp://localhost:0"); + broker.start(); + broker.waitUntilStarted(); + + connection = new ActiveMQConnectionFactory(connector.getConnectUri()).createConnection(); + connection.start(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + @After + public void tearDown() throws Exception { + if (session != null) session.close(); + if (connection != null) connection.close(); + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + } + GlobalOpenTelemetry.resetForTest(); + } + + @Test + public void testPublishSpanCreatedOnSend() throws Exception { + MessageProducer producer = session.createProducer(session.createQueue(queueName)); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + TextMessage message = session.createTextMessage("test"); + producer.send(message); + producer.close(); + + // Allow async broker processing to complete + Thread.sleep(500); + + List spans = spanExporter.getFinishedSpanItems(); + assertTrue("Expected at least one span", spans.size() >= 1); + + SpanData publishSpan = findSpan(spans, queueName + " publish"); + assertNotNull("Publish span should exist", publishSpan); + assertEquals(SpanKind.PRODUCER, publishSpan.getKind()); + assertEquals("activemq", publishSpan.getAttributes().get(io.opentelemetry.api.common.AttributeKey.stringKey("messaging.system"))); + assertEquals(queueName, publishSpan.getAttributes().get(io.opentelemetry.api.common.AttributeKey.stringKey("messaging.destination.name"))); + assertEquals("publish", publishSpan.getAttributes().get(io.opentelemetry.api.common.AttributeKey.stringKey("messaging.operation"))); + } + + @Test + public void testTraceContextPropagatedInMessageProperties() throws Exception { + MessageProducer producer = session.createProducer(session.createQueue(queueName)); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + TextMessage message = session.createTextMessage("propagation test"); + producer.send(message); + producer.close(); + + MessageConsumer consumer = session.createConsumer(session.createQueue(queueName)); + jakarta.jms.Message received = consumer.receive(5000); + assertNotNull("Should receive message", received); + + // The message should have traceparent property injected by the plugin + String traceparent = received.getStringProperty("traceparent"); + assertNotNull("traceparent property should be set", traceparent); + assertTrue("traceparent should follow W3C format", traceparent.startsWith("00-")); + + consumer.close(); + } + + @Test + public void testDeliverSpanCreatedOnDispatch() throws Exception { + MessageConsumer consumer = session.createConsumer(session.createQueue(queueName)); + + MessageProducer producer = session.createProducer(session.createQueue(queueName)); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + producer.send(session.createTextMessage("deliver test")); + producer.close(); + + jakarta.jms.Message received = consumer.receive(5000); + assertNotNull("Should receive message", received); + consumer.close(); + + // Allow time for postProcessDispatch + Thread.sleep(500); + + List spans = spanExporter.getFinishedSpanItems(); + SpanData deliverSpan = findSpan(spans, queueName + " deliver"); + assertNotNull("Deliver span should exist", deliverSpan); + assertEquals(SpanKind.CONSUMER, deliverSpan.getKind()); + assertEquals("activemq", deliverSpan.getAttributes().get(io.opentelemetry.api.common.AttributeKey.stringKey("messaging.system"))); + assertEquals("deliver", deliverSpan.getAttributes().get(io.opentelemetry.api.common.AttributeKey.stringKey("messaging.operation"))); + } + + @Test + public void testAckSpanCreatedOnAcknowledge() throws Exception { + MessageConsumer consumer = session.createConsumer(session.createQueue(queueName)); + + MessageProducer producer = session.createProducer(session.createQueue(queueName)); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + producer.send(session.createTextMessage("ack test")); + producer.close(); + + jakarta.jms.Message received = consumer.receive(5000); + assertNotNull("Should receive message", received); + consumer.close(); + + // Allow time for ack processing + Thread.sleep(500); + + List spans = spanExporter.getFinishedSpanItems(); + SpanData ackSpan = findSpan(spans, queueName + " ack"); + assertNotNull("Ack span should exist", ackSpan); + assertEquals(SpanKind.INTERNAL, ackSpan.getKind()); + assertEquals("activemq", ackSpan.getAttributes().get(io.opentelemetry.api.common.AttributeKey.stringKey("messaging.system"))); + assertEquals("ack", ackSpan.getAttributes().get(io.opentelemetry.api.common.AttributeKey.stringKey("messaging.operation"))); + } + + @Test + public void testDisabledProducerTracing() throws Exception { + // Stop and reconfigure with tracing disabled + connection.close(); + broker.stop(); + broker.waitUntilStopped(); + spanExporter.reset(); + + OpenTelemetryBrokerPlugin plugin = new OpenTelemetryBrokerPlugin(); + plugin.setTraceProducer(false); + plugin.setTraceConsumer(false); + plugin.setTraceAcknowledge(false); + + broker = new BrokerService(); + broker.setBrokerName("otelTestBroker2"); + broker.setPersistent(false); + broker.setUseJmx(false); + broker.setPlugins(new BrokerPlugin[]{plugin}); + connector = broker.addConnector("tcp://localhost:0"); + broker.start(); + broker.waitUntilStarted(); + + connection = new ActiveMQConnectionFactory(connector.getConnectUri()).createConnection(); + connection.start(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageProducer producer = session.createProducer(session.createQueue(queueName)); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + producer.send(session.createTextMessage("no trace")); + producer.close(); + + MessageConsumer consumer = session.createConsumer(session.createQueue(queueName)); + consumer.receive(5000); + consumer.close(); + + Thread.sleep(500); + + List spans = spanExporter.getFinishedSpanItems(); + assertFalse("Should have no publish spans when tracing disabled", + spans.stream().anyMatch(s -> s.getName().contains("publish"))); + assertFalse("Should have no deliver spans when tracing disabled", + spans.stream().anyMatch(s -> s.getName().contains("deliver"))); + assertFalse("Should have no ack spans when tracing disabled", + spans.stream().anyMatch(s -> s.getName().contains("ack"))); + } + + private SpanData findSpan(List spans, String name) { + return spans.stream() + .filter(s -> s.getName().equals(name)) + .findFirst() + .orElse(null); + } +} diff --git a/assembly/pom.xml b/assembly/pom.xml index e4a9922b4dc..a86496989ac 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -136,6 +136,10 @@ ${project.groupId} activemq-shiro + + ${project.groupId} + activemq-opentelemetry + ${project.groupId} activemq-spring diff --git a/assembly/src/release/conf/activemq.xml b/assembly/src/release/conf/activemq.xml index 9f32bd90f59..33b18e2a501 100644 --- a/assembly/src/release/conf/activemq.xml +++ b/assembly/src/release/conf/activemq.xml @@ -96,6 +96,15 @@ + + + + + + + + + file:${activemq.conf}/credentials.properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bom/pom.xml b/bom/pom.xml index d70f15f14eb..11a9fcf9440 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -147,6 +147,11 @@ activemq-shiro ${project.version} + + org.apache.activemq + activemq-opentelemetry + ${project.version} + org.apache.activemq activemq-spring diff --git a/pom.xml b/pom.xml index 2745d052477..9d7b3650daf 100644 --- a/pom.xml +++ b/pom.xml @@ -96,6 +96,7 @@ 4.2.10.Final 2.1.0 2.1.0 + 1.43.0 2.0.17 1.1.2 6.2.17 @@ -211,6 +212,7 @@ activemq-rar activemq-run activemq-shiro + activemq-opentelemetry activemq-spring activemq-runtime-config activemq-tooling @@ -348,6 +350,11 @@ activemq-shiro ${project.version} + + org.apache.activemq + activemq-opentelemetry + ${project.version} + org.apache.activemq activemq-spring @@ -661,6 +668,15 @@ true + + + io.opentelemetry + opentelemetry-bom + ${opentelemetry-version} + pom + import + + org.springframework