Skip to content

Commit 76fc7de

Browse files
authored
Add @Traced plus MethodInterceptorSpanDecorator with a standard implementation and move shared logic from @Scheduled/@Traced to a base class (#302)
1 parent 82964f0 commit 76fc7de

File tree

18 files changed

+923
-36
lines changed

18 files changed

+923
-36
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
4+
Copyright 2017-2018 The OpenTracing Authors
5+
6+
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
7+
in compliance with the License. You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software distributed under the License
12+
is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13+
or implied. See the License for the specific language governing permissions and limitations under
14+
the License.
15+
16+
-->
17+
<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">
18+
<modelVersion>4.0.0</modelVersion>
19+
<parent>
20+
<groupId>io.opentracing.contrib</groupId>
21+
<artifactId>opentracing-spring-cloud-parent</artifactId>
22+
<version>0.5.8-SNAPSHOT</version>
23+
<relativePath>../../</relativePath>
24+
</parent>
25+
26+
<artifactId>opentracing-spring-cloud-aop</artifactId>
27+
28+
<properties>
29+
<main.basedir>${project.basedir}/../../</main.basedir>
30+
</properties>
31+
32+
33+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/**
2+
* Copyright 2017-2018 The OpenTracing Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5+
* in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License
10+
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11+
* or implied. See the License for the specific language governing permissions and limitations under
12+
* the License.
13+
*/
14+
package io.opentracing.contrib.spring.cloud.aop;
15+
16+
import java.lang.annotation.ElementType;
17+
import java.lang.annotation.Retention;
18+
import java.lang.annotation.RetentionPolicy;
19+
import java.lang.annotation.Target;
20+
21+
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.TYPE})
22+
@Retention(RetentionPolicy.RUNTIME)
23+
public @interface Traced {
24+
25+
String component() default "traced";
26+
27+
String operationName() default "";
28+
29+
}

instrument-starters/opentracing-spring-cloud-core/pom.xml

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@
3030
</properties>
3131

3232
<dependencies>
33+
34+
<dependency>
35+
<groupId>io.opentracing.contrib</groupId>
36+
<artifactId>opentracing-spring-cloud-aop</artifactId>
37+
</dependency>
3338
<dependency>
3439
<groupId>io.opentracing.contrib</groupId>
3540
<artifactId>opentracing-spring-tracer-configuration-starter</artifactId>
@@ -54,6 +59,12 @@
5459
<artifactId>spring-boot-starter-web</artifactId>
5560
<optional>true</optional>
5661
</dependency>
62+
<dependency>
63+
<groupId>io.opentracing.contrib</groupId>
64+
<artifactId>opentracing-spring-web-starter</artifactId>
65+
<version>${version.io.opentracing.contrib-opentracing-spring-web}</version>
66+
<optional>true</optional>
67+
</dependency>
5768

5869
<dependency>
5970
<groupId>io.opentracing</groupId>
@@ -85,9 +96,8 @@
8596
<scope>test</scope>
8697
</dependency>
8798
<dependency>
88-
<groupId>io.opentracing.contrib</groupId>
89-
<artifactId>opentracing-spring-web-starter</artifactId>
90-
<version>${version.io.opentracing.contrib-opentracing-spring-web}</version>
99+
<groupId>org.assertj</groupId>
100+
<artifactId>assertj-core</artifactId>
91101
<scope>test</scope>
92102
</dependency>
93103
</dependencies>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* Copyright 2017-2018 The OpenTracing Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5+
* in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License
10+
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11+
* or implied. See the License for the specific language governing permissions and limitations under
12+
* the License.
13+
*/
14+
package io.opentracing.contrib.spring.cloud.aop;
15+
16+
import org.springframework.boot.context.properties.ConfigurationProperties;
17+
18+
@ConfigurationProperties("opentracing.spring.cloud.aop")
19+
public class AopTracingProperties {
20+
21+
/**
22+
* Enable tracing for {@link org.springframework.scheduling.annotation.Scheduled}
23+
*/
24+
private boolean enabled = true;
25+
26+
public boolean isEnabled() {
27+
return enabled;
28+
}
29+
30+
public void setEnabled(boolean enabled) {
31+
this.enabled = enabled;
32+
}
33+
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/**
2+
* Copyright 2017-2018 The OpenTracing Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5+
* in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License
10+
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11+
* or implied. See the License for the specific language governing permissions and limitations under
12+
* the License.
13+
*/
14+
package io.opentracing.contrib.spring.cloud.aop;
15+
16+
import io.opentracing.Scope;
17+
import io.opentracing.Span;
18+
import io.opentracing.Tracer;
19+
import io.opentracing.contrib.spring.cloud.ExtensionTags;
20+
import io.opentracing.tag.Tags;
21+
import java.lang.annotation.Annotation;
22+
import java.util.ArrayList;
23+
import java.util.List;
24+
import java.util.regex.Pattern;
25+
import org.aspectj.lang.ProceedingJoinPoint;
26+
import org.aspectj.lang.reflect.MethodSignature;
27+
import org.slf4j.Logger;
28+
import org.slf4j.LoggerFactory;
29+
30+
public abstract class BaseTracingAspect {
31+
32+
private static final Logger log = LoggerFactory.getLogger(BaseTracingAspect.class);
33+
private final Tracer tracer;
34+
private final Class<? extends Annotation> annotation;
35+
private final List<MethodInterceptorSpanDecorator> decorators;
36+
private Pattern skipPattern;
37+
38+
public BaseTracingAspect(Tracer tracer, List<MethodInterceptorSpanDecorator> decorators,
39+
Class<? extends Annotation> annotation, Pattern skipPattern) {
40+
this.tracer = tracer;
41+
this.decorators = decorators != null ? decorators : new ArrayList<>();
42+
this.annotation = annotation;
43+
this.skipPattern = skipPattern;
44+
}
45+
46+
/**
47+
* This method should be overridden to add the proper annotation and call {@link
48+
* BaseTracingAspect#internalTrace(ProceedingJoinPoint)}
49+
*/
50+
public abstract Object trace(ProceedingJoinPoint pjp) throws Throwable;
51+
52+
protected Object internalTrace(ProceedingJoinPoint pjp) throws Throwable {
53+
if (skipPattern.matcher(pjp.getTarget().getClass().getName()).matches()) {
54+
return pjp.proceed();
55+
}
56+
57+
// operation name is method name
58+
Span span = tracer.buildSpan(getOperationName(pjp))
59+
.withTag(Tags.COMPONENT.getKey(), getComponent(pjp))
60+
.withTag(ExtensionTags.CLASS_TAG.getKey(), pjp.getTarget().getClass().getSimpleName())
61+
.withTag(ExtensionTags.METHOD_TAG.getKey(), pjp.getSignature().getName())
62+
.start();
63+
64+
try {
65+
try (Scope scope = tracer.activateSpan(span)) {
66+
decoratePreProceed(pjp, span);
67+
Object result = pjp.proceed();
68+
decoratePostProceed(pjp, span, result);
69+
return result;
70+
}
71+
} catch (Exception ex) {
72+
decorateOnError(pjp, span, ex);
73+
throw ex;
74+
} finally {
75+
span.finish();
76+
}
77+
}
78+
79+
protected void decoratePreProceed(ProceedingJoinPoint pjp, Span span) {
80+
for (MethodInterceptorSpanDecorator spanDecorator : decorators) {
81+
try {
82+
spanDecorator.onPreProceed(pjp, span);
83+
} catch (RuntimeException exDecorator) {
84+
log.error("Exception during decorating span", exDecorator);
85+
}
86+
}
87+
}
88+
89+
protected void decoratePostProceed(ProceedingJoinPoint pjp, Span span, Object result) {
90+
for (MethodInterceptorSpanDecorator spanDecorator : decorators) {
91+
try {
92+
spanDecorator.onPostProceed(pjp, result, span);
93+
} catch (RuntimeException exDecorator) {
94+
log.error("Exception during decorating span", exDecorator);
95+
}
96+
}
97+
}
98+
99+
protected void decorateOnError(ProceedingJoinPoint pjp, Span span, Exception ex) {
100+
for (MethodInterceptorSpanDecorator spanDecorator : decorators) {
101+
spanDecorator.onError(pjp, ex, span);
102+
}
103+
}
104+
105+
protected String getOperationName(ProceedingJoinPoint pjp) {
106+
return ((MethodSignature) pjp.getSignature()).getMethod().getName();
107+
}
108+
109+
protected String getComponent(ProceedingJoinPoint pjp) {
110+
return annotation.getSimpleName().toLowerCase();
111+
}
112+
113+
protected boolean shouldTrace(ProceedingJoinPoint pjp) {
114+
return true;
115+
}
116+
117+
protected Tracer getTracer() {
118+
return this.tracer;
119+
}
120+
121+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/**
2+
* Copyright 2017-2018 The OpenTracing Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5+
* in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License
10+
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11+
* or implied. See the License for the specific language governing permissions and limitations under
12+
* the License.
13+
*/
14+
package io.opentracing.contrib.spring.cloud.aop;
15+
16+
import io.opentracing.Span;
17+
import io.opentracing.contrib.spring.cloud.ExtensionTags;
18+
import io.opentracing.contrib.spring.cloud.SpanUtils;
19+
import org.aspectj.lang.ProceedingJoinPoint;
20+
import org.aspectj.lang.reflect.MethodSignature;
21+
22+
public interface MethodInterceptorSpanDecorator {
23+
24+
/**
25+
* Decorate span before invocation is done, e.g. before
26+
* {@link ProceedingJoinPoint#proceed()}
27+
* is called
28+
*
29+
* @param ProceedingJoinPoint pjp
30+
* @param Object result
31+
* @param span span
32+
*/
33+
void onPreProceed(ProceedingJoinPoint pjp, Span span);
34+
35+
/**
36+
* Decorate span after invocation is done, e.g. after
37+
* {@link ProceedingJoinPoint#proceed()}
38+
* is called
39+
*
40+
* @param ProceedingJoinPoint pjp
41+
* @param Object result
42+
* @param span span
43+
*/
44+
void onPostProceed(ProceedingJoinPoint pjp, Object result, Span span);
45+
46+
/**
47+
* Decorate span when exception is thrown during the invocation, e.g. during
48+
* {@link ProceedingJoinPoint#proceed()}
49+
* is processing.
50+
*
51+
* @param ProceedingJoinPoint pjp
52+
* @param ex exception
53+
* @param span span
54+
*/
55+
void onError(ProceedingJoinPoint pjp, Exception ex, Span span);
56+
57+
/**
58+
* This decorator adds set of standard tags to the span.
59+
*/
60+
class StandardTags implements MethodInterceptorSpanDecorator {
61+
62+
@Override
63+
public void onPreProceed(ProceedingJoinPoint pjp, Span span) {
64+
ExtensionTags.CLASS_TAG.set(span, pjp.getTarget().getClass().getSimpleName());
65+
ExtensionTags.METHOD_TAG.set(span, ((MethodSignature) pjp.getSignature()).getName());
66+
}
67+
68+
@Override
69+
public void onPostProceed(ProceedingJoinPoint pjp, Object result, Span span) {
70+
}
71+
72+
@Override
73+
public void onError(ProceedingJoinPoint pjp, Exception ex, Span span) {
74+
SpanUtils.captureException(span, ex);
75+
}
76+
}
77+
}

instrument-starters/opentracing-spring-cloud-core/src/main/java/io/opentracing/contrib/spring/cloud/scheduled/ScheduledAspect.java

Lines changed: 9 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,49 +18,30 @@
1818
import io.opentracing.Tracer;
1919
import io.opentracing.contrib.spring.cloud.ExtensionTags;
2020
import io.opentracing.contrib.spring.cloud.SpanUtils;
21+
import io.opentracing.contrib.spring.cloud.aop.BaseTracingAspect;
22+
import io.opentracing.contrib.spring.cloud.aop.MethodInterceptorSpanDecorator;
2123
import io.opentracing.tag.Tags;
24+
import java.util.List;
2225
import java.util.regex.Pattern;
2326
import org.aspectj.lang.ProceedingJoinPoint;
2427
import org.aspectj.lang.annotation.Around;
2528
import org.aspectj.lang.annotation.Aspect;
29+
import org.springframework.scheduling.annotation.Scheduled;
2630

2731
/**
2832
* @author Pavol Loffay
2933
*/
3034
@Aspect
31-
public class ScheduledAspect {
32-
33-
static final String COMPONENT_NAME = "scheduled";
35+
public class ScheduledAspect extends BaseTracingAspect {
3436

3537
private Tracer tracer;
36-
private Pattern skipPattern;
3738

38-
public ScheduledAspect(Tracer tracer, ScheduledTracingProperties scheduledTracingProperties) {
39-
this.tracer = tracer;
40-
this.skipPattern = Pattern.compile(scheduledTracingProperties.getSkipPattern());
39+
public ScheduledAspect(Tracer tracer, ScheduledTracingProperties scheduledTracingProperties, List<MethodInterceptorSpanDecorator> decorators) {
40+
super(tracer, decorators, Scheduled.class, Pattern.compile(scheduledTracingProperties.getSkipPattern()));
4141
}
4242

4343
@Around("execution (@org.springframework.scheduling.annotation.Scheduled * *.*(..))")
44-
public Object traceBackgroundThread(final ProceedingJoinPoint pjp) throws Throwable {
45-
if (skipPattern.matcher(pjp.getTarget().getClass().getName()).matches()) {
46-
return pjp.proceed();
47-
}
48-
49-
// operation name is method name
50-
Span span = tracer.buildSpan(pjp.getSignature().getName())
51-
.withTag(Tags.COMPONENT.getKey(), COMPONENT_NAME)
52-
.withTag(ExtensionTags.CLASS_TAG.getKey(), pjp.getTarget().getClass().getSimpleName())
53-
.withTag(ExtensionTags.METHOD_TAG.getKey(), pjp.getSignature().getName())
54-
.start();
55-
try {
56-
try (Scope scope = tracer.activateSpan(span)) {
57-
return pjp.proceed();
58-
}
59-
} catch (Exception ex) {
60-
SpanUtils.captureException(span, ex);
61-
throw ex;
62-
} finally {
63-
span.finish();
64-
}
44+
public Object trace(final ProceedingJoinPoint pjp) throws Throwable {
45+
return this.internalTrace(pjp);
6546
}
6647
}

0 commit comments

Comments
 (0)