Skip to content

Commit

Permalink
Support tracking the message listener of spring jms
Browse files Browse the repository at this point in the history
  • Loading branch information
hyhyf committed Jul 19, 2024
1 parent 2e08217 commit fd8f52c
Show file tree
Hide file tree
Showing 20 changed files with 735 additions and 2 deletions.
1 change: 1 addition & 0 deletions .github/workflows/plugins-test.3.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ jobs:
- shenyu-2.4.x-grpc-scenario
- shenyu-2.4.x-sofarpc-scenario
- solon-2.x-scenario
- spring-jms-5.x-scenario
steps:
- uses: actions/checkout@v2
with:
Expand Down
2 changes: 1 addition & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Release Notes.
* Improve 4x performance of ContextManagerExtendService.createTraceContext()
* Add a plugin that supports the Solon framework.
* Fixed issues in the MySQL component where the executeBatch method could result in empty SQL statements .

* Add a plugin that supports the spring jms 5.x.

All issues and pull requests are [here](https://github.com/apache/skywalking/milestone/213?closed=1)

Expand Down
1 change: 1 addition & 0 deletions apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
<module>spring-webflux-5.x-webclient-plugin</module>
<module>spring-webflux-6.x-webclient-plugin</module>
<module>resttemplate-commons</module>
<module>spring-jms-5.x-plugin</module>
</modules>
<packaging>pom</packaging>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
~
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.apache.skywalking</groupId>
<artifactId>spring-plugins</artifactId>
<version>9.3.0-SNAPSHOT</version>
</parent>

<artifactId>apm-spring-jms-5.x-plugin</artifactId>

<properties>
<geronimo-jms.version>1.1.1</geronimo-jms.version>
</properties>

<dependencies>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jms_1.1_spec</artifactId>
<version>${geronimo-jms.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* 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.skywalking.apm.plugin.spring.jms;

import org.apache.skywalking.apm.agent.core.context.CarrierItem;
import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;

import javax.jms.Message;
import java.lang.reflect.Method;

public class MessageListenerInterceptor implements InstanceMethodsAroundInterceptor {

private static final String OPERATION_NAME_PREFIX = "Jms/";
private static final String OPERATION_NAME_SUFFIX = "/Execute";

@Override
public void beforeMethod(EnhancedInstance objInst,
Method method,
Object[] allArguments, Class<?>[] argumentsTypes,
MethodInterceptResult result) throws Throwable {
Message message = (Message) allArguments[1];
ContextCarrier contextCarrier = new ContextCarrier();
CarrierItem next = contextCarrier.items();
while (next.hasNext()) {
next = next.next();
Object propertyValue = message.getStringProperty(next.getHeadKey());
if (propertyValue != null) {
next.setHeadValue(propertyValue.toString());
}
}
AbstractSpan activeSpan = ContextManager.createEntrySpan(OPERATION_NAME_PREFIX + message.getJMSDestination() + OPERATION_NAME_SUFFIX, null);
activeSpan.setComponent(ComponentsDefine.SPRING_ASYNC);
ContextManager.extract(contextCarrier);
}

@Override
public Object afterMethod(EnhancedInstance objInst,
Method method,
Object[] allArguments,
Class<?>[] argumentsTypes,
Object ret) throws Throwable {
ContextManager.stopSpan();
return ret;
}

@Override
public void handleMethodException(EnhancedInstance objInst,
Method method,
Object[] allArguments,
Class<?>[] argumentsTypes,
Throwable t) {
ContextManager.activeSpan().log(t);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* 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.skywalking.apm.plugin.spring.jms.define;

import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.MultiClassNameMatch;

import static net.bytebuddy.matcher.ElementMatchers.named;

public class MessageListenerInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {

private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.spring.jms.MessageListenerInterceptor";
public static final String ENHANCE_CLASS = "org.springframework.jms.listener.AbstractMessageListenerContainer";
public static final String ENHANCE_METHOD = "doExecuteListener";

@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}

@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[] {
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named(ENHANCE_METHOD);
}

@Override
public String getMethodsInterceptor() {
return INTERCEPTOR_CLASS;
}

@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}

@Override
protected ClassMatch enhanceClass() {
return MultiClassNameMatch.byMultiClassMatch(ENHANCE_CLASS);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# 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.
spring-jms-5.x=org.apache.skywalking.apm.plugin.spring.jms.define.MessageListenerInstrumentation
3 changes: 2 additions & 1 deletion docs/en/setup/service-agent/java-agent/Plugin-list.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,4 +177,5 @@
- spring-webflux-6.x-webclient
- activemq-artemis-jakarta-client-2.x
- c3p0-0.9.x
- solon-2.x
- solon-2.x
- spring-jms-5.x
1 change: 1 addition & 0 deletions docs/en/setup/service-agent/java-agent/Supported-list.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ metrics based on the tracing data.
* [NATS](https://github.com/nats-io/nats.java) 2.14.x -> 2.15.x
* [ActiveMQ-Artemis](https://github.com/apache/activemq) 2.30.0 -> 2.31.2
* Aliyun ONS 1.x (Optional¹)
* Spring Jms 5.x
* NoSQL
* [aerospike](https://github.com/aerospike/aerospike-client-java) 3.x -> 6.x
* Redis
Expand Down
21 changes: 21 additions & 0 deletions test/plugin/scenarios/spring-jms-5.x-scenario/bin/startup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/bash
#
# 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.

home="$(cd "$(dirname $0)"; pwd)"

java -jar ${agent_opts} ${home}/../libs/spring-jms-5.x-scenario.jar &
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# 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.
segmentItems:
- serviceName: spring-jms-5.x-scenario
segmentSize: ge 2
segments:
- segmentId: not null
spans:
- operationName: ActiveMQ/Queue/test/Producer
parentSpanId: 0
spanId: 1
spanLayer: MQ
startTime: nq 0
endTime: nq 0
componentId: 45
isError: false
spanType: Exit
peer: not blank
tags:
- { key: mq.broker, value: not blank }
- { key: mq.queue, value: test }
skipAnalysis: 'false'
- operationName: GET:/spring-jms-5.x-scenario/case/spring-jms-scenario
parentSpanId: -1
spanId: 0
spanLayer: Http
startTime: nq 0
endTime: nq 0
componentId: 1
isError: false
spanType: Entry
peer: ''
tags:
- { key: url, value: 'http://localhost:8080/spring-jms-5.x-scenario/case/spring-jms-scenario' }
- { key: http.method, value: GET }
- { key: http.status_code, value: '200' }
skipAnalysis: 'false'
- segmentId: not null
spans:
- operationName: ActiveMQ/Queue/test/Consumer
parentSpanId: -1
spanId: 0
spanLayer: MQ
startTime: nq 0
endTime: nq 0
componentId: 46
isError: false
spanType: Entry
peer: not blank
tags:
- { key: mq.broker, value: not blank }
- { key: mq.queue, value: test }
- { key: transmission.latency, value: ge 0 }
refs:
- { parentEndpoint: GET:/spring-jms-5.x-scenario/case/spring-jms-scenario, networkAddress: not null,
refType: CrossProcess, parentSpanId: 1, parentTraceSegmentId: not null,
parentServiceInstance: not null, parentService: not null, traceId: not null }
skipAnalysis: 'false'
- segmentId: not null
spans:
- operationName: Jms/queue://test/Execute
parentSpanId: -1
spanId: 0
spanLayer: Unknown
startTime: nq 0
endTime: nq 0
componentId: 65
isError: false
spanType: Entry
peer: ''
tags:
- { key: transmission.latency, value: ge 0 }
refs:
- { parentEndpoint: GET:/spring-jms-5.x-scenario/case/spring-jms-scenario, networkAddress: not null,
refType: CrossProcess, parentSpanId: 1, parentTraceSegmentId: not null,
parentServiceInstance: not null, parentService: not null, traceId: not null }
skipAnalysis: 'false'
30 changes: 30 additions & 0 deletions test/plugin/scenarios/spring-jms-5.x-scenario/configuration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# 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.

type: jvm
entryService: http://localhost:8080/spring-jms-5.x-scenario/case/spring-jms-scenario
healthCheck: http://localhost:8080/spring-jms-5.x-scenario/case/healthCheck
withPlugins: apm-activemq-5.x-plugin-*.jar
startScript: ./bin/startup.sh
environment:
- activemq.server=tcp://activemq-server:61616
dependencies:
activemq-server:
image: rmohr/activemq:5.14.5
hostname: activemq-server
expose:
- 8161
- 61616
Loading

0 comments on commit fd8f52c

Please sign in to comment.