Use JMXFetch as a library
MODIFY
dd-java-agent-ittests/src/test/groovy/datadog/trace/agent/integration/classloading/ShadowPackageRenamingTest.groovy
dd-java-agent-ittests/src/test/groovy/datadog/trace/agent/integration/classloading/ShadowPackageRenamingTest.groovy
@@ -56,13 +56,13 @@ class ShadowPackageRenamingTest extends Specification {
def "agent jar contains no bootstrap classes"() {
setup:
final ClassPath agentClasspath = ClassPath.from(IntegrationTestUtils.getAgentClassLoader())
+ final ClassPath jmxFetchClasspath = ClassPath.from(IntegrationTestUtils.getJmxFetchClassLoader())
final ClassPath bootstrapClasspath = ClassPath.from(IntegrationTestUtils.getBootstrapProxy())
final Set<String> bootstrapClasses = new HashSet<>()
final String[] bootstrapPrefixes = IntegrationTestUtils.getBootstrapPackagePrefixes()
final String[] agentPrefixes = IntegrationTestUtils.getAgentPackagePrefixes()
final List<String> badBootstrapPrefixes = []
- final List<String> badAgentPrefixes = []
for (ClassPath.ClassInfo info : bootstrapClasspath.getAllClasses()) {
bootstrapClasses.add(info.getName())
// make sure all bootstrap classes can be loaded from system
@@ -79,10 +79,11 @@ class ShadowPackageRenamingTest extends Specification {
}
}
- final List<ClassPath.ClassInfo> duplicateClassFile = new ArrayList<>()
+ final List<ClassPath.ClassInfo> agentDuplicateClassFile = new ArrayList<>()
+ final List<String> badAgentPrefixes = []
for (ClassPath.ClassInfo classInfo : agentClasspath.getAllClasses()) {
if (bootstrapClasses.contains(classInfo.getName())) {
- duplicateClassFile.add(classInfo)
+ agentDuplicateClassFile.add(classInfo)
}
boolean goodPrefix = false
for (int i = 0; i < agentPrefixes.length; ++i) {
@@ -96,9 +97,28 @@ class ShadowPackageRenamingTest extends Specification {
}
}
+ final List<ClassPath.ClassInfo> jmxFetchDuplicateClassFile = new ArrayList<>()
+ final List<String> badJmxFetchPrefixes = []
+ for (ClassPath.ClassInfo classInfo : jmxFetchClasspath.getAllClasses()) {
+ if (bootstrapClasses.contains(classInfo.getName())) {
+ jmxFetchDuplicateClassFile.add(classInfo)
+ }
+ boolean goodPrefix = true
+ for (int i = 0; i < bootstrapPrefixes.length; ++i) {
+ if (classInfo.getName().startsWith(bootstrapPrefixes[i])) {
+ goodPrefix = false
+ break
+ }
+ }
+ if (!goodPrefix) {
+ badJmxFetchPrefixes.add(classInfo.getName())
+ }
+ }
+
expect:
- duplicateClassFile == []
+ agentDuplicateClassFile == []
badBootstrapPrefixes == []
badAgentPrefixes == []
+ badJmxFetchPrefixes == []
}
}

MODIFY
dd-java-agent-ittests/src/test/java/datadog/trace/agent/test/IntegrationTestUtils.java
dd-java-agent-ittests/src/test/java/datadog/trace/agent/test/IntegrationTestUtils.java
@@ -49,6 +49,25 @@ public class IntegrationTestUtils {
}
}
+ /** Returns the classloader the jmxfetch is running on. */
+ public static ClassLoader getJmxFetchClassLoader() {
+ Field classloaderField = null;
+ try {
+ Class<?> tracingAgentClass =
+ tracingAgentClass =
+ ClassLoader.getSystemClassLoader().loadClass("datadog.trace.agent.TracingAgent");
+ classloaderField = tracingAgentClass.getDeclaredField("JMXFETCH_CLASSLOADER");
+ classloaderField.setAccessible(true);
+ return (ClassLoader) classloaderField.get(null);
+ } catch (final Exception e) {
+ throw new IllegalStateException(e);
+ } finally {
+ if (null != classloaderField) {
+ classloaderField.setAccessible(false);
+ }
+ }
+ }
+
/** Returns the URL to the jar the agent appended to the bootstrap classpath * */
public static ClassLoader getBootstrapProxy() throws Exception {
final ClassLoader agentClassLoader = getAgentClassLoader();

ADD
dd-java-agent/agent-jmxfetch/agent-jmxfetch.gradle
+plugins {
+ id "com.github.johnrengelman.shadow"
+}
+apply from: "${rootDir}/gradle/java.gradle"
+
+repositories {
+ maven {
+ url "https://dl.bintray.com/datadog/datadog-maven"
+ }
+}
+
+dependencies {
+ compile 'com.heliosapm.jmxlocal:jmxlocal:1.0'
+ compile 'com.datadoghq:jmxfetch:0.21.0'
+ compile deps.slf4j
+ compile project(':dd-trace-api')
+}
+
+configurations {
+ // exclude bootstrap dependencies from shadowJar
+ runtime.exclude module: deps.opentracing
+ runtime.exclude module: deps.slf4j
+ runtime.exclude group: 'org.slf4j'
+ runtime.exclude group: 'io.opentracing'
+}
+
+shadowJar {
+ dependencies {
+ exclude(project(':dd-java-agent:agent-bootstrap'))
+ exclude(project(':dd-trace-api'))
+ }
+}
+
+jar {
+ classifier = 'unbundled'
+}

ADD
dd-java-agent/agent-jmxfetch/src/main/java/datadog/trace/agent/jmxfetch/JMXFetch.java
+package datadog.trace.agent.jmxfetch;
+
+import com.google.common.collect.ImmutableList;
+import datadog.trace.api.Config;
+import java.util.List;
+import lombok.extern.slf4j.Slf4j;
+import org.datadog.jmxfetch.App;
+import org.datadog.jmxfetch.AppConfig;
+
+@Slf4j
+public class JMXFetch {
+
+ public static final int DEFAULT_STATSD_PORT = 8125;
+ public static final ImmutableList<String> DEFAULT_CONFIGS =
+ ImmutableList.of("jmxfetch-config.yaml");
+
+ private static final int SLEEP_AFTER_JMXFETCH_EXITS = 5000;
+
+ public static final void run() {
+
+ final List<String> metricsConfigs = Config.get().getJmxFetchMetricsConfigs();
+ final Integer checkPeriod = Config.get().getJmxFetchCheckPeriod();
+ final Integer refreshBeansPeriod = Config.get().getJmxFetchRefreshBeansPeriod();
+ final String reporter = getReporter();
+ final String logLocation = getLogLocation();
+ final String logLevel = getLogLevel();
+
+ log.error(
+ "JMXFetch config: {} {} {} {} {} {}",
+ metricsConfigs,
+ checkPeriod,
+ refreshBeansPeriod,
+ reporter,
+ logLocation,
+ logLevel);
+ final AppConfig config =
+ AppConfig.create(
+ DEFAULT_CONFIGS,
+ metricsConfigs,
+ checkPeriod,
+ refreshBeansPeriod,
+ reporter,
+ logLocation,
+ logLevel);
+
+ final Thread thread =
+ new Thread(
+ new Runnable() {
+ @Override
+ public void run() {
+ while (true) {
+ try {
+ final int result = App.run(config);
+ log.error("jmx collector exited with result: " + result);
+ } catch (final Exception e) {
+ log.error("Exception in jmx collector thread", e);
+ }
+ try {
+ Thread.sleep(SLEEP_AFTER_JMXFETCH_EXITS);
+ } catch (final InterruptedException e) {
+ // It looks like JMXFetch itself eats up InterruptedException, so we will do
+ // same here for consistency
+ log.error("JMXFetch was interupted, ignoring", e);
+ }
+ }
+ }
+ });
+ thread.setName("dd-jmx-collector");
+ thread.setDaemon(true);
+ thread.start();
+ }
+
+ private static String getReporter() {
+ String reporter = Config.get().getJmxFetchReporter();
+ if (reporter == null) {
+ reporter = "statsd:" + Config.get().getAgentHost() + ":" + DEFAULT_STATSD_PORT;
+ }
+ return reporter;
+ }
+
+ private static String getLogLocation() {
+ return System.getProperty("org.slf4j.simpleLogger.logFile", "System.err");
+ }
+
+ private static String getLogLevel() {
+ return System.getProperty("org.slf4j.simpleLogger.defaultLogLevel", "info").toUpperCase();
+ }
+}

ADD
dd-java-agent/agent-jmxfetch/src/main/resources/jmxfetch-config.yaml
+init_config:
+ is_jmx: true
+
+instances:
+- jmx_url: service:jmx:local:///
+ conf:
+ # Intentionally left empty for now

MODIFY
dd-java-agent/dd-java-agent.gradle
dd-java-agent/dd-java-agent.gradle
@@ -52,7 +52,7 @@ def includeShadowJar(subproject, jarname) {
includeShadowJar(project(':dd-java-agent:agent-bootstrap'), 'agent-bootstrap.jar.zip')
includeShadowJar(project(':dd-java-agent:instrumentation'), 'agent-tooling-and-instrumentation.jar.zip')
-
+includeShadowJar(project(':dd-java-agent:agent-jmxfetch'), 'agent-jmxfetch.jar.zip')
jar {
classifier = 'unbundled'

MODIFY
dd-java-agent/src/main/java/datadog/trace/agent/TracingAgent.java
dd-java-agent/src/main/java/datadog/trace/agent/TracingAgent.java
@@ -31,7 +31,9 @@ import java.util.jar.JarFile;
/** Entry point for initializing the agent. */
public class TracingAgent {
+ private static boolean inited = false;
private static ClassLoader AGENT_CLASSLOADER = null;
+ private static ClassLoader JMXFETCH_CLASSLOADER = null;
public static void premain(final String agentArgs, final Instrumentation inst) throws Exception {
startAgent(agentArgs, inst);
@@ -44,12 +46,15 @@ public class TracingAgent {
private static synchronized void startAgent(final String agentArgs, final Instrumentation inst)
throws Exception {
- if (null == AGENT_CLASSLOADER) {
+ if (!inited) {
final File toolingJar =
extractToTmpFile(
TracingAgent.class.getClassLoader(),
"agent-tooling-and-instrumentation.jar.zip",
"agent-tooling-and-instrumentation.jar");
+ final File jmxFetchJar =
+ extractToTmpFile(
+ TracingAgent.class.getClassLoader(), "agent-jmxfetch.jar.zip", "agent-jmxfetch.jar");
final File bootstrapJar =
extractToTmpFile(
TracingAgent.class.getClassLoader(),
@@ -59,6 +64,7 @@ public class TracingAgent {
// bootstrap jar must be appended before agent classloader is created.
inst.appendToBootstrapClassLoaderSearch(new JarFile(bootstrapJar));
final ClassLoader agentClassLoader = createDatadogClassLoader(bootstrapJar, toolingJar);
+ final ClassLoader jmxFetchClassLoader = createDatadogClassLoader(bootstrapJar, jmxFetchJar);
final ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
try {
@@ -81,10 +87,22 @@ public class TracingAgent {
logVersionInfoMethod.invoke(null);
}
+ Thread.currentThread().setContextClassLoader(jmxFetchClassLoader);
+ { // install jmxfetch tracer
+ // We would like jmxfetch to be loaded after APM agent to avoid needing to retransform
+ // classes
+ final Class<?> jmxFetchAgentClass =
+ jmxFetchClassLoader.loadClass("datadog.trace.agent.jmxfetch.JMXFetch");
+ final Method jmxFetchInstallerMethod = jmxFetchAgentClass.getMethod("run");
+ jmxFetchInstallerMethod.invoke(null);
+ }
+
AGENT_CLASSLOADER = agentClassLoader;
+ JMXFETCH_CLASSLOADER = jmxFetchClassLoader;
} finally {
Thread.currentThread().setContextClassLoader(contextLoader);
}
+ inited = true;
}
}

MODIFY
dd-trace-api/src/main/java/datadog/trace/api/Config.java
dd-trace-api/src/main/java/datadog/trace/api/Config.java
package datadog.trace.api;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Properties;
import lombok.Getter;
@@ -26,14 +28,18 @@ public class Config {
private static final Config INSTANCE = new Config();
public static final String SERVICE_NAME = "service.name";
- public static final String SERVICE_MAPPING = "service.mapping";
public static final String WRITER_TYPE = "writer.type";
public static final String AGENT_HOST = "agent.host";
public static final String AGENT_PORT = "agent.port";
public static final String PRIORITY_SAMPLING = "priority.sampling";
public static final String TRACE_RESOLVER_ENABLED = "trace.resolver.enabled";
+ public static final String SERVICE_MAPPING = "service.mapping";
public static final String SPAN_TAGS = "trace.span.tags";
public static final String HEADER_TAGS = "trace.header.tags";
+ public static final String JMX_FETCH_METRICS_CONFIGS = "jmxfetch.metrics-configs";
+ public static final String JMX_FETCH_CHECK_PERIOD = "jmxfetch.check-period";
+ public static final String JMX_FETCH_REFRESH_BEANS_PERIOD = "jmxfetch.refresh-beans-period";
+ public static final String JMX_FETCH_REPORTER = "jmxfetch.reporter";
public static final String DEFAULT_SERVICE_NAME = "unnamed-java-app";
@@ -44,8 +50,8 @@ public class Config {
public static final String DEFAULT_AGENT_HOST = "localhost";
public static final int DEFAULT_AGENT_PORT = 8126;
- private static final String DEFAULT_PRIORITY_SAMPLING_ENABLED = "false";
- private static final String DEFAULT_TRACE_RESOLVER_ENABLED = "true";
+ private static final boolean DEFAULT_PRIORITY_SAMPLING_ENABLED = false;
+ private static final boolean DEFAULT_TRACE_RESOLVER_ENABLED = true;
@Getter private final String serviceName;
@Getter private final String writerType;
@@ -56,6 +62,10 @@ public class Config {
@Getter private final Map<String, String> serviceMapping;
@Getter private final Map<String, String> spanTags;
@Getter private final Map<String, String> headerTags;
+ @Getter private final List<String> jmxFetchMetricsConfigs;
+ @Getter private final Integer jmxFetchCheckPeriod;
+ @Getter private final Integer jmxFetchRefreshBeansPeriod;
+ @Getter private final String jmxFetchReporter;
// Read order: System Properties -> Env Variables, [-> default value]
// Visible for testing
@@ -63,18 +73,19 @@ public class Config {
serviceName = getSettingFromEnvironment(SERVICE_NAME, DEFAULT_SERVICE_NAME);
writerType = getSettingFromEnvironment(WRITER_TYPE, DEFAULT_AGENT_WRITER_TYPE);
agentHost = getSettingFromEnvironment(AGENT_HOST, DEFAULT_AGENT_HOST);
- agentPort =
- Integer.valueOf(
- getSettingFromEnvironment(AGENT_PORT, Integer.toString(DEFAULT_AGENT_PORT)));
+ agentPort = getIntegerSettingFromEnvironment(AGENT_PORT, DEFAULT_AGENT_PORT);
prioritySamplingEnabled =
- Boolean.valueOf(
- getSettingFromEnvironment(PRIORITY_SAMPLING, DEFAULT_PRIORITY_SAMPLING_ENABLED));
+ getBooleanSettingFromEnvironment(PRIORITY_SAMPLING, DEFAULT_PRIORITY_SAMPLING_ENABLED);
traceResolverEnabled =
- Boolean.valueOf(
- getSettingFromEnvironment(TRACE_RESOLVER_ENABLED, DEFAULT_TRACE_RESOLVER_ENABLED));
+ getBooleanSettingFromEnvironment(TRACE_RESOLVER_ENABLED, DEFAULT_TRACE_RESOLVER_ENABLED);
serviceMapping = getMapSettingFromEnvironment(SERVICE_MAPPING, null);
spanTags = getMapSettingFromEnvironment(SPAN_TAGS, null);
headerTags = getMapSettingFromEnvironment(HEADER_TAGS, null);
+ jmxFetchMetricsConfigs = getListSettingFromEnvironment(JMX_FETCH_METRICS_CONFIGS, null);
+ jmxFetchCheckPeriod = getIntegerSettingFromEnvironment(JMX_FETCH_CHECK_PERIOD, null);
+ jmxFetchRefreshBeansPeriod =
+ getIntegerSettingFromEnvironment(JMX_FETCH_REFRESH_BEANS_PERIOD, null);
+ jmxFetchReporter = getSettingFromEnvironment(JMX_FETCH_REPORTER, null);
}
// Read order: Properties -> Parent
@@ -82,19 +93,22 @@ public class Config {
serviceName = properties.getProperty(SERVICE_NAME, parent.serviceName);
writerType = properties.getProperty(WRITER_TYPE, parent.writerType);
agentHost = properties.getProperty(AGENT_HOST, parent.agentHost);
- agentPort =
- Integer.valueOf(properties.getProperty(AGENT_PORT, Integer.toString(parent.agentPort)));
+ agentPort = getPropertyIntegerValue(properties, AGENT_PORT, parent.agentPort);
prioritySamplingEnabled =
- Boolean.valueOf(
- properties.getProperty(
- PRIORITY_SAMPLING, Boolean.toString(parent.prioritySamplingEnabled)));
+ getPropertyBooleanValue(properties, PRIORITY_SAMPLING, parent.prioritySamplingEnabled);
traceResolverEnabled =
- Boolean.valueOf(
- properties.getProperty(
- TRACE_RESOLVER_ENABLED, Boolean.toString(parent.traceResolverEnabled)));
+ getPropertyBooleanValue(properties, TRACE_RESOLVER_ENABLED, parent.traceResolverEnabled);
serviceMapping = getPropertyMapValue(properties, SERVICE_MAPPING, parent.serviceMapping);
spanTags = getPropertyMapValue(properties, SPAN_TAGS, parent.spanTags);
headerTags = getPropertyMapValue(properties, HEADER_TAGS, parent.headerTags);
+ jmxFetchMetricsConfigs =
+ getPropertyListValue(properties, JMX_FETCH_METRICS_CONFIGS, parent.jmxFetchMetricsConfigs);
+ jmxFetchCheckPeriod =
+ getPropertyIntegerValue(properties, JMX_FETCH_CHECK_PERIOD, parent.jmxFetchCheckPeriod);
+ jmxFetchRefreshBeansPeriod =
+ getPropertyIntegerValue(
+ properties, JMX_FETCH_REFRESH_BEANS_PERIOD, parent.jmxFetchRefreshBeansPeriod);
+ jmxFetchReporter = properties.getProperty(JMX_FETCH_REPORTER, parent.jmxFetchReporter);
}
private static String getSettingFromEnvironment(final String name, final String defaultValue) {
@@ -110,6 +124,23 @@ public class Config {
return parseMap(getSettingFromEnvironment(name, defaultValue), PREFIX + name);
}
+ private static List<String> getListSettingFromEnvironment(
+ final String name, final String defaultValue) {
+ return parseList(getSettingFromEnvironment(name, defaultValue));
+ }
+
+ private static Boolean getBooleanSettingFromEnvironment(
+ final String name, final Boolean defaultValue) {
+ final String value = getSettingFromEnvironment(name, null);
+ return value == null ? defaultValue : Boolean.valueOf(value);
+ }
+
+ private static Integer getIntegerSettingFromEnvironment(
+ final String name, final Integer defaultValue) {
+ final String value = getSettingFromEnvironment(name, null);
+ return value == null ? defaultValue : Integer.valueOf(value);
+ }
+
private static String propertyToEnvironmentName(final String name) {
return name.toUpperCase().replace(".", "_");
}
@@ -120,6 +151,24 @@ public class Config {
return value == null ? defaultValue : parseMap(value, name);
}
+ private static List<String> getPropertyListValue(
+ final Properties properties, final String name, final List<String> defaultValue) {
+ final String value = properties.getProperty(name);
+ return value == null ? defaultValue : parseList(value);
+ }
+
+ private static Boolean getPropertyBooleanValue(
+ final Properties properties, final String name, final Boolean defaultValue) {
+ final String value = properties.getProperty(name);
+ return value == null ? defaultValue : Boolean.valueOf(value);
+ }
+
+ private static Integer getPropertyIntegerValue(
+ final Properties properties, final String name, final Integer defaultValue) {
+ final String value = properties.getProperty(name);
+ return value == null ? defaultValue : Integer.valueOf(value);
+ }
+
private static Map<String, String> parseMap(final String str, final String settingName) {
if (str == null || str.trim().isEmpty()) {
return Collections.emptyMap();
@@ -148,6 +197,15 @@ public class Config {
return Collections.unmodifiableMap(map);
}
+ private static List<String> parseList(final String str) {
+ if (str == null || str.trim().isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ final String[] tokens = str.split(",", -1);
+ return Collections.unmodifiableList(Arrays.asList(tokens));
+ }
+
public static Config get() {
return INSTANCE;
}

MODIFY
dd-trace-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy
dd-trace-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy
@@ -13,6 +13,12 @@ import static Config.SERVICE_MAPPING
import static Config.SERVICE_NAME
import static Config.SPAN_TAGS
import static Config.WRITER_TYPE
+import static datadog.trace.api.Config.JMX_FETCH_CHECK_PERIOD
+import static datadog.trace.api.Config.JMX_FETCH_METRICS_CONFIGS
+import static datadog.trace.api.Config.JMX_FETCH_REFRESH_BEANS_PERIOD
+import static datadog.trace.api.Config.JMX_FETCH_REPORTER
+import static datadog.trace.api.Config.PRIORITY_SAMPLING
+import static datadog.trace.api.Config.TRACE_RESOLVER_ENABLED
class ConfigTest extends Specification {
@Rule
@@ -32,12 +38,18 @@ class ConfigTest extends Specification {
then:
config.serviceName == "unnamed-java-app"
- config.serviceMapping == [:]
config.writerType == "DDAgentWriter"
- config.prioritySamplingEnabled == false
config.agentHost == "localhost"
config.agentPort == 8126
+ config.prioritySamplingEnabled == false
+ config.traceResolverEnabled == true
+ config.serviceMapping == [:]
config.spanTags == [:]
+ config.headerTags == [:]
+ config.jmxFetchMetricsConfigs == []
+ config.jmxFetchCheckPeriod == null
+ config.jmxFetchRefreshBeansPeriod == null
+ config.jmxFetchReporter == null
config.toString().contains("unnamed-java-app")
}
@@ -45,6 +57,17 @@ class ConfigTest extends Specification {
setup:
System.setProperty(PREFIX + SERVICE_NAME, "something else")
System.setProperty(PREFIX + WRITER_TYPE, "LoggingWriter")
+ System.setProperty(PREFIX + AGENT_HOST, "somehost")
+ System.setProperty(PREFIX + AGENT_PORT, "123")
+ System.setProperty(PREFIX + PRIORITY_SAMPLING, "true")
+ System.setProperty(PREFIX + TRACE_RESOLVER_ENABLED, "false")
+ System.setProperty(PREFIX + SERVICE_MAPPING, "a:1")
+ System.setProperty(PREFIX + SPAN_TAGS, "b:2")
+ System.setProperty(PREFIX + HEADER_TAGS, "c:3")
+ System.setProperty(PREFIX + JMX_FETCH_METRICS_CONFIGS, "/foo.yaml,/bar.yaml")
+ System.setProperty(PREFIX + JMX_FETCH_CHECK_PERIOD, "100")
+ System.setProperty(PREFIX + JMX_FETCH_REFRESH_BEANS_PERIOD, "200")
+ System.setProperty(PREFIX + JMX_FETCH_REPORTER, "reporter")
when:
def config = new Config()
@@ -52,6 +75,17 @@ class ConfigTest extends Specification {
then:
config.serviceName == "something else"
config.writerType == "LoggingWriter"
+ config.agentHost == "somehost"
+ config.agentPort == 123
+ config.prioritySamplingEnabled == true
+ config.traceResolverEnabled == false
+ config.serviceMapping == [a: "1"]
+ config.spanTags == [b: "2"]
+ config.headerTags == [c: "3"]
+ config.jmxFetchMetricsConfigs == ["/foo.yaml", "/bar.yaml"]
+ config.jmxFetchCheckPeriod == 100
+ config.jmxFetchRefreshBeansPeriod == 200
+ config.jmxFetchReporter == "reporter"
}
def "specify overrides via env vars"() {
@@ -90,22 +124,40 @@ class ConfigTest extends Specification {
def "sys props override properties"() {
setup:
Properties properties = new Properties()
- properties.setProperty(SERVICE_NAME, "what we actually want")
- properties.setProperty(WRITER_TYPE, "DDAgentWriter")
- properties.setProperty(AGENT_HOST, "somewhere")
- properties.setProperty(AGENT_PORT, "9999")
+ properties.setProperty(SERVICE_NAME, "something else")
+ properties.setProperty(WRITER_TYPE, "LoggingWriter")
+ properties.setProperty(AGENT_HOST, "somehost")
+ properties.setProperty(AGENT_PORT, "123")
+ properties.setProperty(PRIORITY_SAMPLING, "true")
+ properties.setProperty(TRACE_RESOLVER_ENABLED, "false")
+ properties.setProperty(SERVICE_MAPPING, "a:1")
+ properties.setProperty(SPAN_TAGS, "b:2")
+ properties.setProperty(HEADER_TAGS, "c:3")
+ properties.setProperty(JMX_FETCH_METRICS_CONFIGS, "/foo.yaml,/bar.yaml")
+ properties.setProperty(JMX_FETCH_CHECK_PERIOD, "100")
+ properties.setProperty(JMX_FETCH_REFRESH_BEANS_PERIOD, "200")
+ properties.setProperty(JMX_FETCH_REPORTER, "reporter")
when:
def config = Config.get(properties)
then:
- config.serviceName == "what we actually want"
- config.writerType == "DDAgentWriter"
- config.agentHost == "somewhere"
- config.agentPort == 9999
+ config.serviceName == "something else"
+ config.writerType == "LoggingWriter"
+ config.agentHost == "somehost"
+ config.agentPort == 123
+ config.prioritySamplingEnabled == true
+ config.traceResolverEnabled == false
+ config.serviceMapping == [a: "1"]
+ config.spanTags == [b: "2"]
+ config.headerTags == [c: "3"]
+ config.jmxFetchMetricsConfigs == ["/foo.yaml", "/bar.yaml"]
+ config.jmxFetchCheckPeriod == 100
+ config.jmxFetchRefreshBeansPeriod == 200
+ config.jmxFetchReporter == "reporter"
}
- def "sys props override null properties"() {
+ def "override null properties"() {
when:
def config = Config.get(null)
@@ -114,7 +166,7 @@ class ConfigTest extends Specification {
config.writerType == "DDAgentWriter"
}
- def "sys props override empty properties"() {
+ def "override empty properties"() {
setup:
Properties properties = new Properties()
@@ -126,6 +178,19 @@ class ConfigTest extends Specification {
config.writerType == "DDAgentWriter"
}
+ def "override non empty properties"() {
+ setup:
+ Properties properties = new Properties()
+ properties.setProperty("foo", "bar")
+
+ when:
+ def config = Config.get(properties)
+
+ then:
+ config.serviceName == "unnamed-java-app"
+ config.writerType == "DDAgentWriter"
+ }
+
def "verify mapping configs on tracer"() {
setup:
System.setProperty(PREFIX + SERVICE_MAPPING, mapString)
@@ -180,4 +245,19 @@ class ConfigTest extends Specification {
mapString | map
null | [:]
}
+
+ def "verify empty value list configs on tracer"() {
+ setup:
+ System.setProperty(PREFIX + JMX_FETCH_METRICS_CONFIGS, listString)
+
+ when:
+ def config = new Config()
+
+ then:
+ config.jmxFetchMetricsConfigs == list
+
+ where:
+ listString | list
+ "" | []
+ }
}

MODIFY
settings.gradle
settings.gradle
@@ -4,6 +4,7 @@ include ':dd-trace-ot'
include ':dd-java-agent'
include ':dd-java-agent:agent-bootstrap'
include ':dd-java-agent:agent-tooling'
+include ':dd-java-agent:agent-jmxfetch'
include ':dd-java-agent:testing'
include ':dd-java-agent-ittests'
include ':dd-trace-api'

Use JMXFetch as a library