Skip to content

Commit

Permalink
Add @Traced plus MethodInterceptorSpanDecorator with a standard imple…
Browse files Browse the repository at this point in the history
…mentation and move shared logic from @Scheduled/@Traced to a base class (#302)
  • Loading branch information
ledor473 authored Jan 14, 2021
1 parent 82964f0 commit 76fc7de
Show file tree
Hide file tree
Showing 18 changed files with 923 additions and 36 deletions.
33 changes: 33 additions & 0 deletions instrument-starters/opentracing-spring-cloud-aop/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2017-2018 The OpenTracing Authors
Licensed 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>io.opentracing.contrib</groupId>
<artifactId>opentracing-spring-cloud-parent</artifactId>
<version>0.5.8-SNAPSHOT</version>
<relativePath>../../</relativePath>
</parent>

<artifactId>opentracing-spring-cloud-aop</artifactId>

<properties>
<main.basedir>${project.basedir}/../../</main.basedir>
</properties>


</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* Copyright 2017-2018 The OpenTracing Authors
*
* Licensed 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 io.opentracing.contrib.spring.cloud.aop;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Traced {

String component() default "traced";

String operationName() default "";

}
16 changes: 13 additions & 3 deletions instrument-starters/opentracing-spring-cloud-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@
</properties>

<dependencies>

<dependency>
<groupId>io.opentracing.contrib</groupId>
<artifactId>opentracing-spring-cloud-aop</artifactId>
</dependency>
<dependency>
<groupId>io.opentracing.contrib</groupId>
<artifactId>opentracing-spring-tracer-configuration-starter</artifactId>
Expand All @@ -54,6 +59,12 @@
<artifactId>spring-boot-starter-web</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.opentracing.contrib</groupId>
<artifactId>opentracing-spring-web-starter</artifactId>
<version>${version.io.opentracing.contrib-opentracing-spring-web}</version>
<optional>true</optional>
</dependency>

<dependency>
<groupId>io.opentracing</groupId>
Expand Down Expand Up @@ -85,9 +96,8 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.opentracing.contrib</groupId>
<artifactId>opentracing-spring-web-starter</artifactId>
<version>${version.io.opentracing.contrib-opentracing-spring-web}</version>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* Copyright 2017-2018 The OpenTracing Authors
*
* Licensed 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 io.opentracing.contrib.spring.cloud.aop;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("opentracing.spring.cloud.aop")
public class AopTracingProperties {

/**
* Enable tracing for {@link org.springframework.scheduling.annotation.Scheduled}
*/
private boolean enabled = true;

public boolean isEnabled() {
return enabled;
}

public void setEnabled(boolean enabled) {
this.enabled = enabled;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/**
* Copyright 2017-2018 The OpenTracing Authors
*
* Licensed 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 io.opentracing.contrib.spring.cloud.aop;

import io.opentracing.Scope;
import io.opentracing.Span;
import io.opentracing.Tracer;
import io.opentracing.contrib.spring.cloud.ExtensionTags;
import io.opentracing.tag.Tags;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class BaseTracingAspect {

private static final Logger log = LoggerFactory.getLogger(BaseTracingAspect.class);
private final Tracer tracer;
private final Class<? extends Annotation> annotation;
private final List<MethodInterceptorSpanDecorator> decorators;
private Pattern skipPattern;

public BaseTracingAspect(Tracer tracer, List<MethodInterceptorSpanDecorator> decorators,
Class<? extends Annotation> annotation, Pattern skipPattern) {
this.tracer = tracer;
this.decorators = decorators != null ? decorators : new ArrayList<>();
this.annotation = annotation;
this.skipPattern = skipPattern;
}

/**
* This method should be overridden to add the proper annotation and call {@link
* BaseTracingAspect#internalTrace(ProceedingJoinPoint)}
*/
public abstract Object trace(ProceedingJoinPoint pjp) throws Throwable;

protected Object internalTrace(ProceedingJoinPoint pjp) throws Throwable {
if (skipPattern.matcher(pjp.getTarget().getClass().getName()).matches()) {
return pjp.proceed();
}

// operation name is method name
Span span = tracer.buildSpan(getOperationName(pjp))
.withTag(Tags.COMPONENT.getKey(), getComponent(pjp))
.withTag(ExtensionTags.CLASS_TAG.getKey(), pjp.getTarget().getClass().getSimpleName())
.withTag(ExtensionTags.METHOD_TAG.getKey(), pjp.getSignature().getName())
.start();

try {
try (Scope scope = tracer.activateSpan(span)) {
decoratePreProceed(pjp, span);
Object result = pjp.proceed();
decoratePostProceed(pjp, span, result);
return result;
}
} catch (Exception ex) {
decorateOnError(pjp, span, ex);
throw ex;
} finally {
span.finish();
}
}

protected void decoratePreProceed(ProceedingJoinPoint pjp, Span span) {
for (MethodInterceptorSpanDecorator spanDecorator : decorators) {
try {
spanDecorator.onPreProceed(pjp, span);
} catch (RuntimeException exDecorator) {
log.error("Exception during decorating span", exDecorator);
}
}
}

protected void decoratePostProceed(ProceedingJoinPoint pjp, Span span, Object result) {
for (MethodInterceptorSpanDecorator spanDecorator : decorators) {
try {
spanDecorator.onPostProceed(pjp, result, span);
} catch (RuntimeException exDecorator) {
log.error("Exception during decorating span", exDecorator);
}
}
}

protected void decorateOnError(ProceedingJoinPoint pjp, Span span, Exception ex) {
for (MethodInterceptorSpanDecorator spanDecorator : decorators) {
spanDecorator.onError(pjp, ex, span);
}
}

protected String getOperationName(ProceedingJoinPoint pjp) {
return ((MethodSignature) pjp.getSignature()).getMethod().getName();
}

protected String getComponent(ProceedingJoinPoint pjp) {
return annotation.getSimpleName().toLowerCase();
}

protected boolean shouldTrace(ProceedingJoinPoint pjp) {
return true;
}

protected Tracer getTracer() {
return this.tracer;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/**
* Copyright 2017-2018 The OpenTracing Authors
*
* Licensed 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 io.opentracing.contrib.spring.cloud.aop;

import io.opentracing.Span;
import io.opentracing.contrib.spring.cloud.ExtensionTags;
import io.opentracing.contrib.spring.cloud.SpanUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;

public interface MethodInterceptorSpanDecorator {

/**
* Decorate span before invocation is done, e.g. before
* {@link ProceedingJoinPoint#proceed()}
* is called
*
* @param ProceedingJoinPoint pjp
* @param Object result
* @param span span
*/
void onPreProceed(ProceedingJoinPoint pjp, Span span);

/**
* Decorate span after invocation is done, e.g. after
* {@link ProceedingJoinPoint#proceed()}
* is called
*
* @param ProceedingJoinPoint pjp
* @param Object result
* @param span span
*/
void onPostProceed(ProceedingJoinPoint pjp, Object result, Span span);

/**
* Decorate span when exception is thrown during the invocation, e.g. during
* {@link ProceedingJoinPoint#proceed()}
* is processing.
*
* @param ProceedingJoinPoint pjp
* @param ex exception
* @param span span
*/
void onError(ProceedingJoinPoint pjp, Exception ex, Span span);

/**
* This decorator adds set of standard tags to the span.
*/
class StandardTags implements MethodInterceptorSpanDecorator {

@Override
public void onPreProceed(ProceedingJoinPoint pjp, Span span) {
ExtensionTags.CLASS_TAG.set(span, pjp.getTarget().getClass().getSimpleName());
ExtensionTags.METHOD_TAG.set(span, ((MethodSignature) pjp.getSignature()).getName());
}

@Override
public void onPostProceed(ProceedingJoinPoint pjp, Object result, Span span) {
}

@Override
public void onError(ProceedingJoinPoint pjp, Exception ex, Span span) {
SpanUtils.captureException(span, ex);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,49 +18,30 @@
import io.opentracing.Tracer;
import io.opentracing.contrib.spring.cloud.ExtensionTags;
import io.opentracing.contrib.spring.cloud.SpanUtils;
import io.opentracing.contrib.spring.cloud.aop.BaseTracingAspect;
import io.opentracing.contrib.spring.cloud.aop.MethodInterceptorSpanDecorator;
import io.opentracing.tag.Tags;
import java.util.List;
import java.util.regex.Pattern;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.scheduling.annotation.Scheduled;

/**
* @author Pavol Loffay
*/
@Aspect
public class ScheduledAspect {

static final String COMPONENT_NAME = "scheduled";
public class ScheduledAspect extends BaseTracingAspect {

private Tracer tracer;
private Pattern skipPattern;

public ScheduledAspect(Tracer tracer, ScheduledTracingProperties scheduledTracingProperties) {
this.tracer = tracer;
this.skipPattern = Pattern.compile(scheduledTracingProperties.getSkipPattern());
public ScheduledAspect(Tracer tracer, ScheduledTracingProperties scheduledTracingProperties, List<MethodInterceptorSpanDecorator> decorators) {
super(tracer, decorators, Scheduled.class, Pattern.compile(scheduledTracingProperties.getSkipPattern()));
}

@Around("execution (@org.springframework.scheduling.annotation.Scheduled * *.*(..))")
public Object traceBackgroundThread(final ProceedingJoinPoint pjp) throws Throwable {
if (skipPattern.matcher(pjp.getTarget().getClass().getName()).matches()) {
return pjp.proceed();
}

// operation name is method name
Span span = tracer.buildSpan(pjp.getSignature().getName())
.withTag(Tags.COMPONENT.getKey(), COMPONENT_NAME)
.withTag(ExtensionTags.CLASS_TAG.getKey(), pjp.getTarget().getClass().getSimpleName())
.withTag(ExtensionTags.METHOD_TAG.getKey(), pjp.getSignature().getName())
.start();
try {
try (Scope scope = tracer.activateSpan(span)) {
return pjp.proceed();
}
} catch (Exception ex) {
SpanUtils.captureException(span, ex);
throw ex;
} finally {
span.finish();
}
public Object trace(final ProceedingJoinPoint pjp) throws Throwable {
return this.internalTrace(pjp);
}
}
Loading

0 comments on commit 76fc7de

Please sign in to comment.