Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

updates for spring-jms-3 jakarta changes #1179

Merged
merged 1 commit into from
Mar 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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