Introduce base decorators
This commit is contained in:
parent
875d491638
commit
a98c22ac3a
|
@ -1,5 +1,6 @@
|
||||||
apply from: "${rootDir}/gradle/java.gradle"
|
apply from: "${rootDir}/gradle/java.gradle"
|
||||||
|
|
||||||
|
minimumBranchCoverage = 0.6
|
||||||
excludedClassesConverage += ['datadog.trace.agent.tooling.*']
|
excludedClassesConverage += ['datadog.trace.agent.tooling.*']
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
package datadog.trace.agent.decorator;
|
||||||
|
|
||||||
|
import static io.opentracing.log.Fields.ERROR_OBJECT;
|
||||||
|
|
||||||
|
import datadog.trace.api.Config;
|
||||||
|
import datadog.trace.api.DDTags;
|
||||||
|
import io.opentracing.Span;
|
||||||
|
import io.opentracing.tag.Tags;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
public abstract class BaseDecorator {
|
||||||
|
|
||||||
|
protected final boolean traceAnalyticsEnabled;
|
||||||
|
protected final float traceAnalyticsSampleRate;
|
||||||
|
|
||||||
|
protected BaseDecorator() {
|
||||||
|
traceAnalyticsEnabled =
|
||||||
|
Config.traceAnalyticsIntegrationEnabled(
|
||||||
|
new TreeSet<>(Arrays.asList(instrumentationNames())), traceAnalyticsDefault());
|
||||||
|
float rate = 1.0f;
|
||||||
|
for (final String name : instrumentationNames()) {
|
||||||
|
rate =
|
||||||
|
Config.getFloatSettingFromEnvironment(
|
||||||
|
"integration." + name + ".analytics.sample-rate", rate);
|
||||||
|
}
|
||||||
|
traceAnalyticsSampleRate = rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract String[] instrumentationNames();
|
||||||
|
|
||||||
|
protected abstract String spanType();
|
||||||
|
|
||||||
|
protected abstract String component();
|
||||||
|
|
||||||
|
protected boolean traceAnalyticsDefault() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Span afterStart(final Span span) {
|
||||||
|
assert span != null;
|
||||||
|
span.setTag(DDTags.SPAN_TYPE, spanType());
|
||||||
|
Tags.COMPONENT.set(span, component());
|
||||||
|
if (traceAnalyticsEnabled) {
|
||||||
|
span.setTag(DDTags.ANALYTICS_SAMPLE_RATE, traceAnalyticsSampleRate);
|
||||||
|
}
|
||||||
|
return span;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Span beforeFinish(final Span span) {
|
||||||
|
assert span != null;
|
||||||
|
return span;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Span onError(final Span span, final Throwable throwable) {
|
||||||
|
assert span != null;
|
||||||
|
if (throwable != null) {
|
||||||
|
Tags.ERROR.set(span, true);
|
||||||
|
span.log(Collections.singletonMap(ERROR_OBJECT, throwable));
|
||||||
|
}
|
||||||
|
return span;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package datadog.trace.agent.decorator;
|
||||||
|
|
||||||
|
import datadog.trace.api.DDTags;
|
||||||
|
import io.opentracing.Span;
|
||||||
|
import io.opentracing.tag.Tags;
|
||||||
|
|
||||||
|
public abstract class ClientDecorator extends BaseDecorator {
|
||||||
|
|
||||||
|
protected abstract String service();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Span afterStart(final Span span) {
|
||||||
|
assert span != null;
|
||||||
|
if (service() != null) {
|
||||||
|
span.setTag(DDTags.SERVICE_NAME, service());
|
||||||
|
}
|
||||||
|
Tags.SPAN_KIND.set(span, Tags.SPAN_KIND_CLIENT);
|
||||||
|
return super.afterStart(span);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
package datadog.trace.agent.decorator;
|
||||||
|
|
||||||
|
import datadog.trace.api.Config;
|
||||||
|
import datadog.trace.api.DDSpanTypes;
|
||||||
|
import datadog.trace.api.DDTags;
|
||||||
|
import io.opentracing.Span;
|
||||||
|
import io.opentracing.tag.Tags;
|
||||||
|
|
||||||
|
public abstract class HttpClientDecorator<REQUEST, RESPONSE> extends ClientDecorator {
|
||||||
|
|
||||||
|
protected abstract String method(REQUEST request);
|
||||||
|
|
||||||
|
protected abstract String url(REQUEST request);
|
||||||
|
|
||||||
|
protected abstract String hostname(REQUEST request);
|
||||||
|
|
||||||
|
protected abstract Integer port(REQUEST request);
|
||||||
|
|
||||||
|
protected abstract Integer status(RESPONSE response);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String spanType() {
|
||||||
|
return DDSpanTypes.HTTP_CLIENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Span onRequest(final Span span, final REQUEST request) {
|
||||||
|
assert span != null;
|
||||||
|
if (request != null) {
|
||||||
|
Tags.HTTP_METHOD.set(span, method(request));
|
||||||
|
Tags.HTTP_URL.set(span, url(request));
|
||||||
|
Tags.PEER_HOSTNAME.set(span, hostname(request));
|
||||||
|
Tags.PEER_PORT.set(span, port(request));
|
||||||
|
|
||||||
|
if (Config.get().isHttpClientSplitByDomain()) {
|
||||||
|
span.setTag(DDTags.SERVICE_NAME, hostname(request));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return span;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Span onResponse(final Span span, final RESPONSE response) {
|
||||||
|
assert span != null;
|
||||||
|
if (response != null) {
|
||||||
|
final Integer status = status(response);
|
||||||
|
if (status != null) {
|
||||||
|
Tags.HTTP_STATUS.set(span, status);
|
||||||
|
if (400 <= status && status < 500) {
|
||||||
|
Tags.ERROR.set(span, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return span;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
package datadog.trace.agent.decorator;
|
||||||
|
|
||||||
|
import datadog.trace.api.Config;
|
||||||
|
import datadog.trace.api.DDSpanTypes;
|
||||||
|
import io.opentracing.Span;
|
||||||
|
import io.opentracing.tag.Tags;
|
||||||
|
|
||||||
|
public abstract class HttpServerDecorator<REQUEST, RESPONSE> extends ServerDecorator {
|
||||||
|
|
||||||
|
protected abstract String method(REQUEST request);
|
||||||
|
|
||||||
|
protected abstract String url(REQUEST request);
|
||||||
|
|
||||||
|
protected abstract String hostname(REQUEST request);
|
||||||
|
|
||||||
|
protected abstract Integer port(REQUEST request);
|
||||||
|
|
||||||
|
protected abstract Integer status(RESPONSE response);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String spanType() {
|
||||||
|
return DDSpanTypes.HTTP_SERVER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean traceAnalyticsDefault() {
|
||||||
|
return Config.getBooleanSettingFromEnvironment(Config.TRACE_ANALYTICS_ENABLED, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Span onRequest(final Span span, final REQUEST request) {
|
||||||
|
assert span != null;
|
||||||
|
if (request != null) {
|
||||||
|
Tags.HTTP_METHOD.set(span, method(request));
|
||||||
|
Tags.HTTP_URL.set(span, url(request));
|
||||||
|
Tags.PEER_HOSTNAME.set(span, hostname(request));
|
||||||
|
Tags.PEER_PORT.set(span, port(request));
|
||||||
|
// TODO set resource name from URL.
|
||||||
|
}
|
||||||
|
return span;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Span onResponse(final Span span, final RESPONSE response) {
|
||||||
|
assert span != null;
|
||||||
|
if (response != null) {
|
||||||
|
final Integer status = status(response);
|
||||||
|
if (status != null) {
|
||||||
|
Tags.HTTP_STATUS.set(span, status);
|
||||||
|
if (status >= 500) {
|
||||||
|
Tags.ERROR.set(span, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return span;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public Span onError(final Span span, final Throwable throwable) {
|
||||||
|
// assert span != null;
|
||||||
|
// // FIXME
|
||||||
|
// final Object status = span.getTag("http.status");
|
||||||
|
// if (status == null || status.equals(200)) {
|
||||||
|
// // Ensure status set correctly
|
||||||
|
// span.setTag("http.status", 500);
|
||||||
|
// }
|
||||||
|
// return super.onError(span, throwable);
|
||||||
|
// }
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package datadog.trace.agent.decorator;
|
||||||
|
|
||||||
|
import io.opentracing.Span;
|
||||||
|
import io.opentracing.tag.Tags;
|
||||||
|
|
||||||
|
public abstract class ServerDecorator extends BaseDecorator {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Span afterStart(final Span span) {
|
||||||
|
assert span != null;
|
||||||
|
Tags.SPAN_KIND.set(span, Tags.SPAN_KIND_SERVER);
|
||||||
|
return super.afterStart(span);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,154 @@
|
||||||
|
package datadog.trace.agent.decorator
|
||||||
|
|
||||||
|
import datadog.trace.api.DDTags
|
||||||
|
import io.opentracing.Span
|
||||||
|
import io.opentracing.tag.Tags
|
||||||
|
import spock.lang.Shared
|
||||||
|
import spock.lang.Specification
|
||||||
|
|
||||||
|
import static datadog.trace.agent.test.utils.TraceUtils.withSystemProperty
|
||||||
|
import static io.opentracing.log.Fields.ERROR_OBJECT
|
||||||
|
|
||||||
|
class BaseDecoratorTest extends Specification {
|
||||||
|
|
||||||
|
@Shared
|
||||||
|
def decorator = newDecorator()
|
||||||
|
|
||||||
|
def span = Mock(Span)
|
||||||
|
|
||||||
|
def "test afterStart"() {
|
||||||
|
when:
|
||||||
|
decorator.afterStart(span)
|
||||||
|
|
||||||
|
then:
|
||||||
|
1 * span.setTag(DDTags.SPAN_TYPE, decorator.spanType())
|
||||||
|
1 * span.setTag(Tags.COMPONENT.key, "test-component")
|
||||||
|
_ * span.setTag(_, _) // Want to allow other calls from child implementations.
|
||||||
|
0 * _
|
||||||
|
}
|
||||||
|
|
||||||
|
def "test onError"() {
|
||||||
|
when:
|
||||||
|
decorator.onError(span, error)
|
||||||
|
|
||||||
|
then:
|
||||||
|
if (error) {
|
||||||
|
1 * span.setTag(Tags.ERROR.key, true)
|
||||||
|
1 * span.log([(ERROR_OBJECT): error])
|
||||||
|
}
|
||||||
|
0 * _
|
||||||
|
|
||||||
|
where:
|
||||||
|
error << [new Exception(), null]
|
||||||
|
}
|
||||||
|
|
||||||
|
def "test beforeFinish"() {
|
||||||
|
when:
|
||||||
|
decorator.beforeFinish(span)
|
||||||
|
|
||||||
|
then:
|
||||||
|
0 * _
|
||||||
|
}
|
||||||
|
|
||||||
|
def "test assert null span"() {
|
||||||
|
when:
|
||||||
|
decorator.afterStart(null)
|
||||||
|
|
||||||
|
then:
|
||||||
|
thrown(AssertionError)
|
||||||
|
|
||||||
|
when:
|
||||||
|
decorator.onError(null, null)
|
||||||
|
|
||||||
|
then:
|
||||||
|
thrown(AssertionError)
|
||||||
|
|
||||||
|
when:
|
||||||
|
decorator.beforeFinish(null)
|
||||||
|
|
||||||
|
then:
|
||||||
|
thrown(AssertionError)
|
||||||
|
}
|
||||||
|
|
||||||
|
def "test analytics rate default disabled"() {
|
||||||
|
when:
|
||||||
|
BaseDecorator dec = newDecorator(defaultEnabled)
|
||||||
|
|
||||||
|
then:
|
||||||
|
dec.traceAnalyticsEnabled == defaultEnabled
|
||||||
|
dec.traceAnalyticsSampleRate == sampleRate
|
||||||
|
|
||||||
|
where:
|
||||||
|
defaultEnabled | sampleRate
|
||||||
|
true | 1.0
|
||||||
|
false | 1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
def "test analytics rate enabled"() {
|
||||||
|
when:
|
||||||
|
BaseDecorator dec = withSystemProperty("dd.integration.${integName}.analytics.enabled", "true") {
|
||||||
|
withSystemProperty("dd.integration.${integName}.analytics.sample-rate", "$sampleRate") {
|
||||||
|
newDecorator(enabled)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
then:
|
||||||
|
dec.traceAnalyticsEnabled == expectedEnabled
|
||||||
|
dec.traceAnalyticsSampleRate == (Float) expectedRate
|
||||||
|
|
||||||
|
where:
|
||||||
|
enabled | integName | sampleRate | expectedEnabled | expectedRate
|
||||||
|
false | "" | "" | false | 1.0
|
||||||
|
true | "" | "" | true | 1.0
|
||||||
|
false | "test1" | 0.5 | true | 0.5
|
||||||
|
false | "test2" | 0.75 | true | 0.75
|
||||||
|
true | "test1" | 0.2 | true | 0.2
|
||||||
|
true | "test2" | 0.4 | true | 0.4
|
||||||
|
true | "test1" | "" | true | 1.0
|
||||||
|
true | "test2" | "" | true | 1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
def newDecorator() {
|
||||||
|
return newDecorator(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
def newDecorator(final Boolean analyticsEnabledDefault) {
|
||||||
|
return analyticsEnabledDefault ?
|
||||||
|
new BaseDecorator() {
|
||||||
|
@Override
|
||||||
|
protected String[] instrumentationNames() {
|
||||||
|
return ["test1", "test2"]
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String spanType() {
|
||||||
|
return "test-type"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String component() {
|
||||||
|
return "test-component"
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean traceAnalyticsDefault() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} :
|
||||||
|
new BaseDecorator() {
|
||||||
|
@Override
|
||||||
|
protected String[] instrumentationNames() {
|
||||||
|
return ["test1", "test2"]
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String spanType() {
|
||||||
|
return "test-type"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String component() {
|
||||||
|
return "test-component"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
package datadog.trace.agent.decorator
|
||||||
|
|
||||||
|
import datadog.trace.api.DDTags
|
||||||
|
import io.opentracing.Span
|
||||||
|
import io.opentracing.tag.Tags
|
||||||
|
|
||||||
|
class ClientDecoratorTest extends BaseDecoratorTest {
|
||||||
|
|
||||||
|
def span = Mock(Span)
|
||||||
|
|
||||||
|
def "test afterStart"() {
|
||||||
|
setup:
|
||||||
|
def decorator = newDecorator((String) serviceName)
|
||||||
|
|
||||||
|
when:
|
||||||
|
decorator.afterStart(span)
|
||||||
|
|
||||||
|
then:
|
||||||
|
if (serviceName != null) {
|
||||||
|
1 * span.setTag(DDTags.SERVICE_NAME, serviceName)
|
||||||
|
}
|
||||||
|
1 * span.setTag(Tags.COMPONENT.key, "test-component")
|
||||||
|
1 * span.setTag(Tags.SPAN_KIND.key, "client")
|
||||||
|
1 * span.setTag(DDTags.SPAN_TYPE, decorator.spanType())
|
||||||
|
1 * span.setTag(DDTags.ANALYTICS_SAMPLE_RATE, 1.0)
|
||||||
|
0 * _
|
||||||
|
|
||||||
|
where:
|
||||||
|
serviceName << ["test-service", "other-service", null]
|
||||||
|
}
|
||||||
|
|
||||||
|
def "test beforeFinish"() {
|
||||||
|
when:
|
||||||
|
newDecorator("test-service").beforeFinish(span)
|
||||||
|
|
||||||
|
then:
|
||||||
|
0 * _
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
def newDecorator() {
|
||||||
|
return newDecorator("test-service")
|
||||||
|
}
|
||||||
|
|
||||||
|
def newDecorator(String serviceName) {
|
||||||
|
return new ClientDecorator() {
|
||||||
|
@Override
|
||||||
|
protected String[] instrumentationNames() {
|
||||||
|
return ["test1", "test2"]
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String service() {
|
||||||
|
return serviceName
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String spanType() {
|
||||||
|
return "test-type"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String component() {
|
||||||
|
return "test-component"
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean traceAnalyticsDefault() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,136 @@
|
||||||
|
package datadog.trace.agent.decorator
|
||||||
|
|
||||||
|
import datadog.trace.api.Config
|
||||||
|
import datadog.trace.api.DDTags
|
||||||
|
import io.opentracing.Span
|
||||||
|
import io.opentracing.tag.Tags
|
||||||
|
|
||||||
|
import static datadog.trace.agent.test.utils.TraceUtils.withConfigOverride
|
||||||
|
|
||||||
|
class HttpClientDecoratorTest extends ClientDecoratorTest {
|
||||||
|
|
||||||
|
def span = Mock(Span)
|
||||||
|
|
||||||
|
def "test onRequest"() {
|
||||||
|
setup:
|
||||||
|
def decorator = newDecorator()
|
||||||
|
|
||||||
|
when:
|
||||||
|
withConfigOverride(Config.HTTP_CLIENT_HOST_SPLIT_BY_DOMAIN, "$renameService") {
|
||||||
|
decorator.onRequest(span, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
then:
|
||||||
|
if (req) {
|
||||||
|
1 * span.setTag(Tags.HTTP_METHOD.key, "test-method")
|
||||||
|
1 * span.setTag(Tags.HTTP_URL.key, "test-url")
|
||||||
|
1 * span.setTag(Tags.PEER_HOSTNAME.key, "test-host")
|
||||||
|
1 * span.setTag(Tags.PEER_PORT.key, 555)
|
||||||
|
if (renameService) {
|
||||||
|
1 * span.setTag(DDTags.SERVICE_NAME, "test-host")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0 * _
|
||||||
|
|
||||||
|
where:
|
||||||
|
renameService | req
|
||||||
|
false | null
|
||||||
|
true | null
|
||||||
|
false | [method: "test-method", url: "test-url", host: "test-host", port: 555]
|
||||||
|
true | [method: "test-method", url: "test-url", host: "test-host", port: 555]
|
||||||
|
}
|
||||||
|
|
||||||
|
def "test onResponse"() {
|
||||||
|
setup:
|
||||||
|
def decorator = newDecorator()
|
||||||
|
|
||||||
|
when:
|
||||||
|
decorator.onResponse(span, resp)
|
||||||
|
|
||||||
|
then:
|
||||||
|
if (status) {
|
||||||
|
1 * span.setTag(Tags.HTTP_STATUS.key, status)
|
||||||
|
}
|
||||||
|
if (error) {
|
||||||
|
1 * span.setTag(Tags.ERROR.key, true)
|
||||||
|
}
|
||||||
|
0 * _
|
||||||
|
|
||||||
|
where:
|
||||||
|
status | error | resp
|
||||||
|
200 | false | [status: 200]
|
||||||
|
399 | false | [status: 399]
|
||||||
|
400 | true | [status: 400]
|
||||||
|
499 | true | [status: 499]
|
||||||
|
500 | false | [status: 500]
|
||||||
|
600 | false | [status: 600]
|
||||||
|
null | false | [status: null]
|
||||||
|
null | false | null
|
||||||
|
}
|
||||||
|
|
||||||
|
def "test assert null span"() {
|
||||||
|
setup:
|
||||||
|
def decorator = newDecorator()
|
||||||
|
|
||||||
|
when:
|
||||||
|
decorator.onRequest(null, null)
|
||||||
|
|
||||||
|
then:
|
||||||
|
thrown(AssertionError)
|
||||||
|
|
||||||
|
when:
|
||||||
|
decorator.onResponse(null, null)
|
||||||
|
|
||||||
|
then:
|
||||||
|
thrown(AssertionError)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
def newDecorator(String serviceName = "test-service") {
|
||||||
|
return new HttpClientDecorator<Map, Map>() {
|
||||||
|
@Override
|
||||||
|
protected String[] instrumentationNames() {
|
||||||
|
return ["test1", "test2"]
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String service() {
|
||||||
|
return serviceName
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String component() {
|
||||||
|
return "test-component"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String method(Map m) {
|
||||||
|
return m.method
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String url(Map m) {
|
||||||
|
return m.url
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String hostname(Map m) {
|
||||||
|
return m.host
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Integer port(Map m) {
|
||||||
|
return m.port
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Integer status(Map m) {
|
||||||
|
return m.status
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean traceAnalyticsDefault() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,114 @@
|
||||||
|
package datadog.trace.agent.decorator
|
||||||
|
|
||||||
|
import io.opentracing.Span
|
||||||
|
import io.opentracing.tag.Tags
|
||||||
|
|
||||||
|
class HttpServerDecoratorTest extends ServerDecoratorTest {
|
||||||
|
|
||||||
|
def span = Mock(Span)
|
||||||
|
|
||||||
|
def "test onRequest"() {
|
||||||
|
setup:
|
||||||
|
def decorator = newDecorator()
|
||||||
|
|
||||||
|
when:
|
||||||
|
decorator.onRequest(span, req)
|
||||||
|
|
||||||
|
then:
|
||||||
|
if (req) {
|
||||||
|
1 * span.setTag(Tags.HTTP_METHOD.key, "test-method")
|
||||||
|
1 * span.setTag(Tags.HTTP_URL.key, "test-url")
|
||||||
|
1 * span.setTag(Tags.PEER_HOSTNAME.key, "test-host")
|
||||||
|
1 * span.setTag(Tags.PEER_PORT.key, 555)
|
||||||
|
}
|
||||||
|
0 * _
|
||||||
|
|
||||||
|
where:
|
||||||
|
req << [null, [method: "test-method", url: "test-url", host: "test-host", port: 555]]
|
||||||
|
}
|
||||||
|
|
||||||
|
def "test onResponse"() {
|
||||||
|
setup:
|
||||||
|
def decorator = newDecorator()
|
||||||
|
|
||||||
|
when:
|
||||||
|
decorator.onResponse(span, resp)
|
||||||
|
|
||||||
|
then:
|
||||||
|
if (status) {
|
||||||
|
1 * span.setTag(Tags.HTTP_STATUS.key, status)
|
||||||
|
}
|
||||||
|
if (error) {
|
||||||
|
1 * span.setTag(Tags.ERROR.key, true)
|
||||||
|
}
|
||||||
|
0 * _
|
||||||
|
|
||||||
|
where:
|
||||||
|
status | error | resp
|
||||||
|
200 | false | [status: 200]
|
||||||
|
399 | false | [status: 399]
|
||||||
|
400 | false | [status: 400]
|
||||||
|
499 | false | [status: 499]
|
||||||
|
500 | true | [status: 500]
|
||||||
|
600 | true | [status: 600]
|
||||||
|
null | false | [status: null]
|
||||||
|
null | false | null
|
||||||
|
}
|
||||||
|
|
||||||
|
def "test assert null span"() {
|
||||||
|
setup:
|
||||||
|
def decorator = newDecorator()
|
||||||
|
|
||||||
|
when:
|
||||||
|
decorator.onRequest(null, null)
|
||||||
|
|
||||||
|
then:
|
||||||
|
thrown(AssertionError)
|
||||||
|
|
||||||
|
when:
|
||||||
|
decorator.onResponse(null, null)
|
||||||
|
|
||||||
|
then:
|
||||||
|
thrown(AssertionError)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
def newDecorator() {
|
||||||
|
return new HttpServerDecorator<Map, Map>() {
|
||||||
|
@Override
|
||||||
|
protected String[] instrumentationNames() {
|
||||||
|
return ["test1", "test2"]
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String component() {
|
||||||
|
return "test-component"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String method(Map m) {
|
||||||
|
return m.method
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String url(Map m) {
|
||||||
|
return m.url
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String hostname(Map m) {
|
||||||
|
return m.host
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Integer port(Map m) {
|
||||||
|
return m.port
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Integer status(Map m) {
|
||||||
|
return m.status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
package datadog.trace.agent.decorator
|
||||||
|
|
||||||
|
import datadog.trace.api.DDTags
|
||||||
|
import io.opentracing.Span
|
||||||
|
import io.opentracing.tag.Tags
|
||||||
|
|
||||||
|
class ServerDecoratorTest extends BaseDecoratorTest {
|
||||||
|
|
||||||
|
def span = Mock(Span)
|
||||||
|
|
||||||
|
def "test afterStart"() {
|
||||||
|
def decorator = newDecorator()
|
||||||
|
when:
|
||||||
|
decorator.afterStart(span)
|
||||||
|
|
||||||
|
then:
|
||||||
|
1 * span.setTag(Tags.COMPONENT.key, "test-component")
|
||||||
|
1 * span.setTag(Tags.SPAN_KIND.key, "server")
|
||||||
|
1 * span.setTag(DDTags.SPAN_TYPE, decorator.spanType())
|
||||||
|
if (decorator.traceAnalyticsEnabled) {
|
||||||
|
1 * span.setTag(DDTags.ANALYTICS_SAMPLE_RATE, 1.0)
|
||||||
|
}
|
||||||
|
0 * _
|
||||||
|
}
|
||||||
|
|
||||||
|
def "test beforeFinish"() {
|
||||||
|
when:
|
||||||
|
newDecorator().beforeFinish(span)
|
||||||
|
|
||||||
|
then:
|
||||||
|
0 * _
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
def newDecorator() {
|
||||||
|
return new ServerDecorator() {
|
||||||
|
@Override
|
||||||
|
protected String[] instrumentationNames() {
|
||||||
|
return ["test1", "test2"]
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String spanType() {
|
||||||
|
return "test-type"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String component() {
|
||||||
|
return "test-component"
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean traceAnalyticsDefault() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,8 +4,8 @@ import dd.test.trace.annotation.SayTracedHello
|
||||||
|
|
||||||
import java.util.concurrent.Callable
|
import java.util.concurrent.Callable
|
||||||
|
|
||||||
import static TraceAnnotationsInstrumentation.DEFAULT_ANNOTATIONS
|
|
||||||
import static datadog.trace.agent.test.utils.TraceUtils.withSystemProperty
|
import static datadog.trace.agent.test.utils.TraceUtils.withSystemProperty
|
||||||
|
import static datadog.trace.instrumentation.trace_annotation.TraceAnnotationsInstrumentation.DEFAULT_ANNOTATIONS
|
||||||
|
|
||||||
class ConfiguredTraceAnnotationsTest extends AgentTestRunner {
|
class ConfiguredTraceAnnotationsTest extends AgentTestRunner {
|
||||||
|
|
||||||
|
@ -46,11 +46,10 @@ class ConfiguredTraceAnnotationsTest extends AgentTestRunner {
|
||||||
|
|
||||||
def "test configuration #value"() {
|
def "test configuration #value"() {
|
||||||
setup:
|
setup:
|
||||||
def config = null
|
def config = withSystemProperty("dd.trace.annotations", value) {
|
||||||
withSystemProperty("dd.trace.annotations", value) {
|
new TraceAnnotationsInstrumentation().additionalTraceAnnotations
|
||||||
def instrumentation = new TraceAnnotationsInstrumentation()
|
|
||||||
config = instrumentation.additionalTraceAnnotations
|
|
||||||
}
|
}
|
||||||
|
|
||||||
expect:
|
expect:
|
||||||
config == expected.toSet()
|
config == expected.toSet()
|
||||||
|
|
||||||
|
|
|
@ -332,7 +332,7 @@ public class Config {
|
||||||
public static Boolean getBooleanSettingFromEnvironment(
|
public static Boolean getBooleanSettingFromEnvironment(
|
||||||
final String name, final Boolean defaultValue) {
|
final String name, final Boolean defaultValue) {
|
||||||
final String value = getSettingFromEnvironment(name, null);
|
final String value = getSettingFromEnvironment(name, null);
|
||||||
return value == null ? defaultValue : Boolean.valueOf(value);
|
return value == null || value.trim().isEmpty() ? defaultValue : Boolean.valueOf(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -344,13 +344,23 @@ public class Config {
|
||||||
*/
|
*/
|
||||||
public static Float getFloatSettingFromEnvironment(final String name, final Float defaultValue) {
|
public static Float getFloatSettingFromEnvironment(final String name, final Float defaultValue) {
|
||||||
final String value = getSettingFromEnvironment(name, null);
|
final String value = getSettingFromEnvironment(name, null);
|
||||||
return value == null ? defaultValue : Float.valueOf(value);
|
try {
|
||||||
|
return value == null ? defaultValue : Float.valueOf(value);
|
||||||
|
} catch (final NumberFormatException e) {
|
||||||
|
log.warn("Invalid configuration for " + name, e);
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Integer getIntegerSettingFromEnvironment(
|
private static Integer getIntegerSettingFromEnvironment(
|
||||||
final String name, final Integer defaultValue) {
|
final String name, final Integer defaultValue) {
|
||||||
final String value = getSettingFromEnvironment(name, null);
|
final String value = getSettingFromEnvironment(name, null);
|
||||||
return value == null ? defaultValue : Integer.valueOf(value);
|
try {
|
||||||
|
return value == null ? defaultValue : Integer.valueOf(value);
|
||||||
|
} catch (final NumberFormatException e) {
|
||||||
|
log.warn("Invalid configuration for " + name, e);
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String propertyToEnvironmentName(final String name) {
|
private static String propertyToEnvironmentName(final String name) {
|
||||||
|
@ -360,25 +370,25 @@ public class Config {
|
||||||
private static Map<String, String> getPropertyMapValue(
|
private static Map<String, String> getPropertyMapValue(
|
||||||
final Properties properties, final String name, final Map<String, String> defaultValue) {
|
final Properties properties, final String name, final Map<String, String> defaultValue) {
|
||||||
final String value = properties.getProperty(name);
|
final String value = properties.getProperty(name);
|
||||||
return value == null ? defaultValue : parseMap(value, name);
|
return value == null || value.trim().isEmpty() ? defaultValue : parseMap(value, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<String> getPropertyListValue(
|
private static List<String> getPropertyListValue(
|
||||||
final Properties properties, final String name, final List<String> defaultValue) {
|
final Properties properties, final String name, final List<String> defaultValue) {
|
||||||
final String value = properties.getProperty(name);
|
final String value = properties.getProperty(name);
|
||||||
return value == null ? defaultValue : parseList(value);
|
return value == null || value.trim().isEmpty() ? defaultValue : parseList(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Boolean getPropertyBooleanValue(
|
private static Boolean getPropertyBooleanValue(
|
||||||
final Properties properties, final String name, final Boolean defaultValue) {
|
final Properties properties, final String name, final Boolean defaultValue) {
|
||||||
final String value = properties.getProperty(name);
|
final String value = properties.getProperty(name);
|
||||||
return value == null ? defaultValue : Boolean.valueOf(value);
|
return value == null || value.trim().isEmpty() ? defaultValue : Boolean.valueOf(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Integer getPropertyIntegerValue(
|
private static Integer getPropertyIntegerValue(
|
||||||
final Properties properties, final String name, final Integer defaultValue) {
|
final Properties properties, final String name, final Integer defaultValue) {
|
||||||
final String value = properties.getProperty(name);
|
final String value = properties.getProperty(name);
|
||||||
return value == null ? defaultValue : Integer.valueOf(value);
|
return value == null || value.trim().isEmpty() ? defaultValue : Integer.valueOf(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String, String> parseMap(final String str, final String settingName) {
|
private static Map<String, String> parseMap(final String str, final String settingName) {
|
||||||
|
|
|
@ -160,6 +160,36 @@ class ConfigTest extends Specification {
|
||||||
config.agentPort == 123
|
config.agentPort == 123
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def "default when configured incorrectly"() {
|
||||||
|
setup:
|
||||||
|
System.setProperty(PREFIX + SERVICE_NAME, " ")
|
||||||
|
System.setProperty(PREFIX + WRITER_TYPE, " ")
|
||||||
|
System.setProperty(PREFIX + AGENT_HOST, " ")
|
||||||
|
System.setProperty(PREFIX + TRACE_AGENT_PORT, " ")
|
||||||
|
System.setProperty(PREFIX + AGENT_PORT_LEGACY, "invalid")
|
||||||
|
System.setProperty(PREFIX + PRIORITY_SAMPLING, "3")
|
||||||
|
System.setProperty(PREFIX + TRACE_RESOLVER_ENABLED, " ")
|
||||||
|
System.setProperty(PREFIX + SERVICE_MAPPING, " ")
|
||||||
|
System.setProperty(PREFIX + HEADER_TAGS, "1")
|
||||||
|
System.setProperty(PREFIX + SPAN_TAGS, "invalid")
|
||||||
|
System.setProperty(PREFIX + HTTP_CLIENT_HOST_SPLIT_BY_DOMAIN, "invalid")
|
||||||
|
|
||||||
|
when:
|
||||||
|
def config = new Config()
|
||||||
|
|
||||||
|
then:
|
||||||
|
config.serviceName == " "
|
||||||
|
config.writerType == " "
|
||||||
|
config.agentHost == " "
|
||||||
|
config.agentPort == 8126
|
||||||
|
config.prioritySamplingEnabled == false
|
||||||
|
config.traceResolverEnabled == true
|
||||||
|
config.serviceMapping == [:]
|
||||||
|
config.mergedSpanTags == [:]
|
||||||
|
config.headerTags == [:]
|
||||||
|
config.httpClientSplitByDomain == false
|
||||||
|
}
|
||||||
|
|
||||||
def "sys props and env vars overrides for trace_agent_port and agent_port_legacy as expected"() {
|
def "sys props and env vars overrides for trace_agent_port and agent_port_legacy as expected"() {
|
||||||
setup:
|
setup:
|
||||||
if (overridePortEnvVar) {
|
if (overridePortEnvVar) {
|
||||||
|
@ -349,6 +379,33 @@ class ConfigTest extends Specification {
|
||||||
integrationNames = new TreeSet<>(names)
|
integrationNames = new TreeSet<>(names)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def "test getFloatSettingFromEnvironment(#name)"() {
|
||||||
|
setup:
|
||||||
|
environmentVariables.set("DD_ENV_ZERO_TEST", "0.0")
|
||||||
|
environmentVariables.set("DD_ENV_FLOAT_TEST", "1.0")
|
||||||
|
environmentVariables.set("DD_FLOAT_TEST", "0.2")
|
||||||
|
|
||||||
|
System.setProperty("dd.prop.zero.test", "0")
|
||||||
|
System.setProperty("dd.prop.float.test", "0.3")
|
||||||
|
System.setProperty("dd.float.test", "0.4")
|
||||||
|
System.setProperty("dd.negative.test", "-1")
|
||||||
|
|
||||||
|
expect:
|
||||||
|
Config.getFloatSettingFromEnvironment(name, defaultValue) == (float) expected
|
||||||
|
|
||||||
|
where:
|
||||||
|
name | expected
|
||||||
|
"env.zero.test" | 0.0
|
||||||
|
"prop.zero.test" | 0
|
||||||
|
"env.float.test" | 1.0
|
||||||
|
"prop.float.test" | 0.3
|
||||||
|
"float.test" | 0.4
|
||||||
|
"negative.test" | -1.0
|
||||||
|
"default.test" | 10.0
|
||||||
|
|
||||||
|
defaultValue = 10.0
|
||||||
|
}
|
||||||
|
|
||||||
def "verify mapping configs on tracer"() {
|
def "verify mapping configs on tracer"() {
|
||||||
setup:
|
setup:
|
||||||
System.setProperty(PREFIX + SERVICE_MAPPING, mapString)
|
System.setProperty(PREFIX + SERVICE_MAPPING, mapString)
|
||||||
|
@ -402,6 +459,7 @@ class ConfigTest extends Specification {
|
||||||
where:
|
where:
|
||||||
mapString | map
|
mapString | map
|
||||||
null | [:]
|
null | [:]
|
||||||
|
"" | [:]
|
||||||
}
|
}
|
||||||
|
|
||||||
def "verify empty value list configs on tracer"() {
|
def "verify empty value list configs on tracer"() {
|
||||||
|
|
Loading…
Reference in New Issue