create ScheduledTasks bean and application context config

This commit is contained in:
heathkd 2020-01-16 11:39:48 -05:00
parent 820103811e
commit 68c323ac56
7 changed files with 233 additions and 0 deletions

View File

@ -0,0 +1,5 @@
apply from: "${rootDir}/gradle/java.gradle"
dependencies {
testCompile group: 'org.springframework', name: 'spring-context', version: '5.2.3.RELEASE'
testCompile project(':dd-java-agent:instrumentation:trace-annotation')
}

View File

@ -0,0 +1,26 @@
// This file includes software developed at SignalFx
package datadog.trace.instrumentation.springscheduling;
import datadog.trace.agent.decorator.BaseDecorator;
public final class SpringSchedulingDecorator extends BaseDecorator {
public static final SpringSchedulingDecorator DECORATOR = new SpringSchedulingDecorator();
private SpringSchedulingDecorator() {}
@Override
protected String[] instrumentationNames() {
return new String[] {"spring-scheduling"};
}
@Override
protected String spanType() {
return null;
}
@Override
protected String component() {
return "spring-scheduling";
}
}

View File

@ -0,0 +1,75 @@
// This file includes software developed at SignalFx
package datadog.trace.instrumentation.springscheduling;
import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.*;
import com.google.auto.service.AutoService;
import datadog.trace.agent.tooling.Instrumenter;
import datadog.trace.api.Trace;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
@AutoService(Instrumenter.class)
public final class SpringSchedulingInstrumentation extends Instrumenter.Default {
public SpringSchedulingInstrumentation() {
super("spring-scheduling");
}
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return not(isInterface()).and(named("org.springframework.scheduling.config.Task"));
}
@Override
public String[] helperClassNames() {
return new String[] {
"datadog.trace.agent.decorator.BaseDecorator",
packageName + ".SpringSchedulingDecorator",
getClass().getName() + "$RunnableWrapper",
};
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
isConstructor().and(takesArgument(0, Runnable.class)),
SpringSchedulingInstrumentation.class.getName() + "$RepositoryFactorySupportAdvice");
}
public static class SpringSchedulingAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static void onConstruction(
@Advice.Argument(value = 0, readOnly = false) Runnable runnable) {
runnable = RunnableWrapper.wrapIfNeeded(runnable);
}
}
public static class RunnableWrapper implements Runnable {
private final Runnable runnable;
private RunnableWrapper(final Runnable runnable) {
this.runnable = runnable;
}
@Trace
@Override
public void run() {
runnable.run();
}
public static Runnable wrapIfNeeded(final Runnable task) {
// We wrap only lambdas' anonymous classes and if given object has not already been wrapped.
// Anonymous classes have '/' in class name which is not allowed in 'normal' classes.
if (task instanceof RunnableWrapper) {
return task;
}
return new RunnableWrapper(task);
}
}
}

View File

@ -0,0 +1,71 @@
import datadog.trace.agent.test.AgentTestRunner
import datadog.trace.agent.test.utils.ConfigUtils
import datadog.trace.instrumentation.api.Tags
import org.springframework.context.annotation.AnnotationConfigApplicationContext
class ReportTimeTest extends AgentTestRunner {
static {
ConfigUtils.updateConfig {
System.clearProperty("dd.trace.annotations")
}
}
def "test method executed"() {
setup:
def scheduledTask = new ScheduledTasks();
scheduledTask.reportCurrentTime();
expect:
assert scheduledTask.reportCurrentTimeExecuted == true;
}
def "trace fired"() {
setup:
def scheduledTask = new ScheduledTasks();
scheduledTask.reportCurrentTime();
expect:
assertTraces(1) {
trace(0, 1) {
span(0) {
serviceName "test"
resourceName "ScheduledTasks.reportCurrentTime"
operationName "trace.annotation"
parent()
errored false
tags {
// "$Tags.COMPONENT" "scheduled"
"$Tags.COMPONENT" "trace"
defaultTags()
}
}
}
}
}
def "test with context"() {
setup:
def context = new AnnotationConfigApplicationContext(ScheduledTasksConfig) // provide config as argument
def task = context.getBean(ScheduledTasks) // provide class we are trying to test
task.reportCurrentTime()
expect:
assertTraces(1) {
trace(0, 1) {
span(0) {
serviceName "test"
resourceName "ScheduledTasks.reportCurrentTime"
operationName "trace.annotation"
parent()
errored false
tags {
// "$Tags.COMPONENT" "scheduled"
"$Tags.COMPONENT" "trace"
defaultTags()
}
}
}
}
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright 2012-2015 the original author or 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
*
* https://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.
*/
import datadog.trace.api.DDTags;
import datadog.trace.api.Trace;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import static datadog.trace.instrumentation.api.AgentTracer.activeSpan;
@Component
public class ScheduledTasks {
private static final Logger log = LoggerFactory.getLogger(ScheduledTasks.class);
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
public static boolean reportCurrentTimeExecuted = false;
@Scheduled(fixedRate = 5000)
@Trace
public void reportCurrentTime() {
// log.info("The time is now {}", dateFormat.format(new Date()));
// test that the body of method has been executed
activeSpan().setTag(DDTags.SERVICE_NAME, "test");
reportCurrentTimeExecuted = true;
}
}

View File

@ -0,0 +1,10 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ScheduledTasksConfig {
@Bean
public ScheduledTasks scheduledTasks() {
return new ScheduledTasks();
}
}

View File

@ -130,6 +130,7 @@ include ':dd-java-agent:instrumentation:servlet:request-3'
include ':dd-java-agent:instrumentation:slf4j-mdc'
include ':dd-java-agent:instrumentation:sparkjava-2.3'
include ':dd-java-agent:instrumentation:spring-data-1.8'
include ':dd-java-agent:instrumentation:spring-scheduling'
include ':dd-java-agent:instrumentation:spring-webmvc-3.1'
include ':dd-java-agent:instrumentation:spring-webflux-5'
include ':dd-java-agent:instrumentation:spymemcached-2.12'