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

add resin plugin #187

Merged
merged 6 commits into from
May 10, 2017
Merged
Show file tree
Hide file tree
Changes from 2 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
5 changes: 5 additions & 0 deletions apm-sniffer/apm-agent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@
<artifactId>apm-mongodb-3.x-plugin</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.skywalking</groupId>
<artifactId>apm-resin-3.x-4.x-plugin</artifactId>
<version>${project.version}</version>
</dependency>

<!-- activation -->
<dependency>
Expand Down
1 change: 1 addition & 0 deletions apm-sniffer/apm-sdk-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<module>tomcat-7.x-8.x-plugin</module>
<module>motan-plugin</module>
<module>mongodb-3.x-plugin</module>
<module>resin-3.x-4.x-plugin</module>
</modules>
<packaging>pom</packaging>

Expand Down
54 changes: 54 additions & 0 deletions apm-sniffer/apm-sdk-plugin/resin-3.x-4.x-plugin/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<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>
<artifactId>apm-sdk-plugin</artifactId>
<groupId>org.skywalking</groupId>
<version>3.1-2017</version>
</parent>

<artifactId>apm-resin-3.x-4.x-plugin</artifactId>
<packaging>jar</packaging>

<name>resin-3.x-4.x-plugin</name>
<url>http://maven.apache.org</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>com.caucho</groupId>
<artifactId>resin</artifactId>
<version>3.0.9</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<!-- 源码插件 -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<!-- 发布时自动将源码同时发布的配置 -->
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package org.skywalking.apm.plugin.resin34x;

import javax.servlet.http.HttpServletRequest;
import org.skywalking.apm.agent.core.context.ContextCarrier;
import org.skywalking.apm.agent.core.context.ContextManager;
import org.skywalking.apm.agent.core.plugin.interceptor.EnhancedClassInstanceContext;
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodInvokeContext;
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.skywalking.apm.trace.Span;
import org.skywalking.apm.trace.tag.Tags;
import org.skywalking.apm.util.StringUtil;

/**
* {@link ResinInterceptor} intercept method of{@link com.caucho.server.dispatch.ServletInvocation#service(javax.servlet.ServletRequest,
* javax.servlet.ServletResponse)} record the resin host, port ,url.
*
* @author baiyang
*/
public class ResinInterceptor implements InstanceMethodsAroundInterceptor {
/**
* Header name that the serialized context data stored in
* {@link HttpServletRequest#getHeader(String)}.
*/
public static final String HEADER_NAME_OF_CONTEXT_DATA = "SWTraceContext";
/**
* Resin component.
*/
public static final String RESIN_COMPONENT = "Resin";

@Override
public void beforeMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
MethodInterceptResult result) {
Object[] args = interceptorContext.allArguments();
HttpServletRequest request = (HttpServletRequest)args[0];
Span span = ContextManager.createSpan(request.getRequestURI());
Tags.COMPONENT.set(span, RESIN_COMPONENT);
Tags.PEER_HOST.set(span, request.getServerName());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Request#getServerName() cannot get the correct client host if Resin is behind a reverse proxy or load balancer. You may need to use HttpServletRequest.getHeader("x-forwarded-proto") instead.

Tags.PEER_PORT.set(span, request.getServerPort());
Tags.SPAN_KIND.set(span, Tags.SPAN_KIND_SERVER);
Tags.URL.set(span, request.getRequestURL().toString());
Tags.SPAN_LAYER.asHttp(span);

String tracingHeaderValue = request.getHeader(HEADER_NAME_OF_CONTEXT_DATA);
if (!StringUtil.isEmpty(tracingHeaderValue)) {
ContextManager.extract(new ContextCarrier().deserialize(tracingHeaderValue));
}
}

@Override
public Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext,
Copy link
Member

@ascrutae ascrutae May 1, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current span need to record status code. and also check the status code, Please see Tomcat plugin

Object ret) {
ContextManager.stopSpan();
return ret;
}

@Override
public void handleMethodException(Throwable t, EnhancedClassInstanceContext context,
InstanceMethodInvokeContext interceptorContext) {
Span span = ContextManager.activeSpan();
span.log(t);
Tags.ERROR.set(span, true);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package org.skywalking.apm.plugin.resin34x.define;

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

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

/**
* {@link ResinInstrumentation} presents that skywalking intercepts {@link com.caucho.server.dispatch.ServletInvocation#service(javax.servlet.ServletRequest,
* javax.servlet.ServletResponse)} by using {@link ResinInterceptor}.
*
* @author baiyang
*/
public class ResinInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {

private static final String ENHANCE_CLASS = "com.caucho.server.dispatch.ServletInvocation";

private static final String METHOD_INTERCET_CLASS = "org.skywalking.apm.plugin.resin34x.ResinInterceptor";

@Override
protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return null;
}

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

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

@Override
protected String enhanceClassName() {
return ENHANCE_CLASS;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.skywalking.apm.plugin.resin.v3x.v4x.define.ResinInstrumentation
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package org.skywalking.apm.plugin.resin34x;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.hamcrest.CoreMatchers;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.skywalking.apm.agent.core.boot.ServiceManager;
import org.skywalking.apm.agent.core.context.TracerContext;
import org.skywalking.apm.agent.core.plugin.interceptor.EnhancedClassInstanceContext;
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodInvokeContext;
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.skywalking.apm.sniffer.mock.context.MockTracerContextListener;
import org.skywalking.apm.sniffer.mock.context.SegmentAssert;
import org.skywalking.apm.trace.LogData;
import org.skywalking.apm.trace.Span;
import org.skywalking.apm.trace.TraceSegment;
import org.skywalking.apm.trace.TraceSegmentRef;
import org.skywalking.apm.trace.tag.Tags;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;

/**
* ResinInterceptorTest
*
* @author baiyang
*/
@RunWith(MockitoJUnitRunner.class)
public class ResinInterceptorTest {

private ResinInterceptor interceptor;
private MockTracerContextListener contextListener;

@Mock
private HttpServletRequest request;
@Mock
private HttpServletResponse response;
@Mock
private EnhancedClassInstanceContext classInstanceContext;
@Mock
private InstanceMethodInvokeContext methodInvokeContext;
@Mock
private MethodInterceptResult methodInterceptResult;

@Before
public void setUp() throws Exception {

ServiceManager.INSTANCE.boot();

interceptor = new ResinInterceptor();
contextListener = new MockTracerContextListener();

TracerContext.ListenerManager.add(contextListener);

when(request.getRequestURI()).thenReturn("/test/testRequestURL");
when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8080/test/testRequestURL"));
when(methodInvokeContext.allArguments()).thenReturn(new Object[] {request, response});
}

@Test
public void testWithoutSerializedContextData() {
interceptor.beforeMethod(classInstanceContext, methodInvokeContext, methodInterceptResult);
interceptor.afterMethod(classInstanceContext, methodInvokeContext, null);

contextListener.assertSize(1);
contextListener.assertTraceSegment(0, new SegmentAssert() {
@Override
public void call(TraceSegment traceSegment) {
assertThat(traceSegment.getSpans().size(), is(1));
Span span = traceSegment.getSpans().get(0);
assertHttpSpan(span);
}
});
}

@Test
public void testWithSerializedContextData() {
when(request.getHeader(ResinInterceptor.HEADER_NAME_OF_CONTEXT_DATA)).thenReturn("302017.1487666919810.624424584.17332.1.1|1|REMOTE_APP|127.0.0.1|Trace.globalId.123|1");

interceptor.beforeMethod(classInstanceContext, methodInvokeContext, methodInterceptResult);
interceptor.afterMethod(classInstanceContext, methodInvokeContext, null);

contextListener.assertSize(1);
contextListener.assertTraceSegment(0, new SegmentAssert() {
@Override
public void call(TraceSegment traceSegment) {
assertThat(traceSegment.getSpans().size(), is(1));
Span span = traceSegment.getSpans().get(0);
assertHttpSpan(span);
assertTraceSegmentRef(traceSegment.getRefs().get(0));
}
});
}

@Test
public void testWithOccurException() {
interceptor.beforeMethod(classInstanceContext, methodInvokeContext, methodInterceptResult);
interceptor.handleMethodException(new RuntimeException(), classInstanceContext, methodInvokeContext);
interceptor.afterMethod(classInstanceContext, methodInvokeContext, null);

contextListener.assertSize(1);
contextListener.assertTraceSegment(0, new SegmentAssert() {
@Override
public void call(TraceSegment traceSegment) {
assertThat(traceSegment.getSpans().size(), is(1));
Span span = traceSegment.getSpans().get(0);
assertHttpSpan(span);
assertThat(span.getLogs().size(), is(1));
assertSpanLog(span.getLogs().get(0));
}
});
}

private void assertSpanLog(LogData logData) {
assertThat(logData.getFields().size(), is(4));
assertThat(logData.getFields().get("event"), CoreMatchers.<Object>is("error"));
assertThat(logData.getFields().get("error.kind"), CoreMatchers.<Object>is(RuntimeException.class.getName()));
assertNull(logData.getFields().get("message"));
}

private void assertTraceSegmentRef(TraceSegmentRef ref) {
assertThat(ref.getSpanId(), is(1));
assertThat(ref.getTraceSegmentId(), is("302017.1487666919810.624424584.17332.1.1"));
}

private void assertHttpSpan(Span span) {
assertThat(span.getOperationName(), is("/test/testRequestURL"));
assertThat(Tags.COMPONENT.get(span), is("Resin"));
assertThat(Tags.URL.get(span), is("http://localhost:8080/test/testRequestURL"));
assertThat(Tags.SPAN_KIND.get(span), is(Tags.SPAN_KIND_SERVER));
assertTrue(Tags.SPAN_LAYER.isHttp(span));
}

@After
public void tearDown() throws Exception {
TracerContext.ListenerManager.remove(new MockTracerContextListener());
}
}