Skip to content

Commit

Permalink
updates for spring-jms-3 jakarta changes
Browse files Browse the repository at this point in the history
formatting and license updates
  • Loading branch information
tbradellis committed Mar 15, 2023
1 parent 8249671 commit 385fb42
Show file tree
Hide file tree
Showing 5 changed files with 253 additions and 0 deletions.
29 changes: 29 additions & 0 deletions instrumentation/spring-jms-3/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
dependencies {
implementation(project(":agent-bridge"))
implementation("jakarta.jms:jakarta.jms-api:3.1.0")
implementation("org.springframework:spring-jms:6.0.6")

}

jar {
manifest { attributes 'Implementation-Title': 'com.newrelic.instrumentation.spring-jms-3' }
}
verifyInstrumentation {
passesOnly ('org.springframework:spring-jms:[6.0.0,)'){
implementation('jakarta.jms:jakarta.jms-api:3.1.0')
}

excludeRegex 'org.springframework:spring-jms:6.0.0.(RC)[0-9]*$'

}

java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(17))
}
}

site {
title 'Spring JMS'
type 'Messaging'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
*
* * Copyright 2023 New Relic Corporation. All rights reserved.
* * SPDX-License-Identifier: Apache-2.0
*
*/

package com.nr.agent.instrumentation.springjms3;

import com.newrelic.api.agent.ExtendedInboundHeaders;
import com.newrelic.api.agent.HeaderType;
import com.newrelic.api.agent.NewRelic;
import jakarta.jms.JMSException;
import jakarta.jms.Message;

import java.util.Collections;
import java.util.List;
import java.util.logging.Level;

public class InboundWrapper extends ExtendedInboundHeaders {
private final Message delegate;

public InboundWrapper(Message message) {
super();
this.delegate = message;
}

@Override
public String getHeader(String name) {
try {
return delegate.getStringProperty(name);
} catch (JMSException e) {
NewRelic.getAgent().getLogger().log(Level.FINE, e, "Error getting property ({0}) from JMS message.", name);
}
return null;
}

@Override
public List<String> getHeaders(String name) {
String result = getHeader(name);
if (result == null) {
return null;
}
return Collections.singletonList(result);
}

@Override
public HeaderType getHeaderType() {
return HeaderType.MESSAGE;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*
*
* * Copyright 2023 New Relic Corporation. All rights reserved.
* * SPDX-License-Identifier: Apache-2.0
*
*/

package com.nr.agent.instrumentation.springjms3;

import com.newrelic.agent.bridge.TracedMethod;
import com.newrelic.api.agent.DestinationType;
import com.newrelic.api.agent.MessageConsumeParameters;
import com.newrelic.api.agent.NewRelic;
import com.newrelic.api.agent.TransactionNamePriority;
import jakarta.jms.Destination;
import jakarta.jms.JMSException;
import jakarta.jms.Message;
import jakarta.jms.Queue;
import jakarta.jms.TemporaryQueue;
import jakarta.jms.TemporaryTopic;
import jakarta.jms.Topic;

import java.util.Collections;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.logging.Level;

public abstract class JmsMetricUtil {
private static final String CATEGORY = "Message";

/**
* Get the message properties as a map of String to Object
*
* @param msg the message holding 0 or more properties
* @return the map, may be empty, never null
*/
public static Map<String, String> getMessageParameters(Message msg) {

Map<String, String> result = new LinkedHashMap<>(1);

try {
Enumeration<?> parameterEnum = msg.getPropertyNames();
if (parameterEnum == null || !parameterEnum.hasMoreElements()) {
return Collections.emptyMap();
}

while (parameterEnum.hasMoreElements()) {
String key = (String) parameterEnum.nextElement();
Object val = msg.getObjectProperty(key);
result.put(key, ((val == null) ? null : val.toString()));
}
} catch (JMSException e) {
NewRelic.getAgent().getLogger().log(Level.FINE, e, "Unable to capture JMS message property");
}

return result;
}

public static void processConsume(Message message, TracedMethod tracer) {
try {
DestinationType destinationType = getDestinationType(message.getJMSDestination());
String destinationName = getDestinationName(message.getJMSDestination());
tracer.reportAsExternal(MessageConsumeParameters
.library("JMS")
.destinationType(destinationType)
.destinationName(destinationName)
.inboundHeaders(new InboundWrapper(message))
.build());
} catch (JMSException exception) {
NewRelic.getAgent().getLogger().log(Level.FINE, exception,
"Unable to record metrics for JMS message consume.");
}
}

private static String getDestinationName(Destination destination) throws JMSException {
if (destination instanceof TemporaryQueue || destination instanceof TemporaryTopic) {
return "Temp";
}

if (destination instanceof Queue) {
Queue queue = (Queue) destination;
return queue.getQueueName();
}

if (destination instanceof Topic) {
Topic topic = (Topic) destination;
return topic.getTopicName();
}

return "Unknown";
}

private static DestinationType getDestinationType(Destination destination) {
if (destination instanceof TemporaryQueue) {
return DestinationType.TEMP_QUEUE;
} else if (destination instanceof TemporaryTopic) {
return DestinationType.TEMP_TOPIC;
} else if (destination instanceof Queue) {
return DestinationType.NAMED_QUEUE;
} else {
return DestinationType.NAMED_TOPIC;
}
}

public static Message nameTransaction(Message msg) {
if (msg != null) {
try {
Destination dest = msg.getJMSDestination();
if (dest instanceof Queue) {
Queue queue = (Queue) dest;
if (queue instanceof TemporaryQueue) {
NewRelic.getAgent().getTransaction().setTransactionName(TransactionNamePriority.FRAMEWORK_LOW,
false, CATEGORY, "JMS/Queue/Temp");
} else {
NewRelic.getAgent().getTransaction().setTransactionName(TransactionNamePriority.FRAMEWORK_HIGH,
false, CATEGORY, "JMS/Queue/Named", queue.getQueueName());
}
} else if (dest instanceof Topic) {
Topic topic = (Topic) dest;
if (topic instanceof TemporaryTopic) {
NewRelic.getAgent().getTransaction().setTransactionName(TransactionNamePriority.FRAMEWORK_LOW,
false, CATEGORY, "JMS/Topic/Temp");
} else {
NewRelic.getAgent().getTransaction().setTransactionName(TransactionNamePriority.FRAMEWORK_HIGH,
false, CATEGORY, "JMS/Topic/Named", topic.getTopicName());
}
} else {
NewRelic.getAgent().getLogger().log(Level.FINE,
"Error naming JMS transaction: Invalid Message Type.");
}
} catch (JMSException e) {
NewRelic.getAgent().getLogger().log(Level.FINE, e, "Error naming JMS transaction");
}
} else {
// Not a useful transaction.
NewRelic.getAgent().getTransaction().ignore();
}
return msg;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
*
* * Copyright 2023 New Relic Corporation. All rights reserved.
* * SPDX-License-Identifier: Apache-2.0
*
*/

package org.springframework.jms.listener;

import com.newrelic.agent.bridge.AgentBridge;
import com.newrelic.api.agent.Trace;
import com.newrelic.api.agent.weaver.MatchType;
import com.newrelic.api.agent.weaver.Weave;
import com.newrelic.api.agent.weaver.Weaver;
import com.nr.agent.instrumentation.springjms3.JmsMetricUtil;
import jakarta.jms.JMSException;
import jakarta.jms.Message;
import jakarta.jms.Session;

@Weave(type = MatchType.Interface, originalName = "org.springframework.jms.listener.SessionAwareMessageListener" )
public abstract class SessionAwareMessageListener<M extends Message> {

@Trace(dispatcher = true)
public void onMessage(M message, Session session) throws JMSException {
JmsMetricUtil.nameTransaction(message);
JmsMetricUtil.processConsume(message, AgentBridge.getAgent().getTracedMethod());
AgentBridge.getAgent().getTransaction().saveMessageParameters(JmsMetricUtil.getMessageParameters(message));
Weaver.callOriginal();
}
}
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ include 'instrumentation:spring-4.2.0'
include 'instrumentation:spring-4.3.0'
include 'instrumentation:spring-aop-2'
include 'instrumentation:spring-jms-2'
include 'instrumentation:spring-jms-3'
include 'instrumentation:spring-ws-2.0'
include 'instrumentation:spring-webflux-5.0.0'
include 'instrumentation:spring-webflux-5.1.0'
Expand Down

0 comments on commit 385fb42

Please sign in to comment.