Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[java] Improve parametric Java client #3740

Merged
merged 2 commits into from
Dec 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion utils/_context/_scenarios/parametric.py
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,7 @@ def java_library_factory():
container_name="java-test-client",
container_tag="java-test-client",
container_img=f"""
FROM maven:3.9.2-eclipse-temurin-17
FROM maven:3-eclipse-temurin-21
WORKDIR /client
RUN mkdir ./tracer
COPY {java_reldir}/src src
Expand Down
6 changes: 3 additions & 3 deletions utils/build/docker/java/parametric/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.2</version>
<version>3.4.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

Expand All @@ -19,9 +19,9 @@

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>17</java.version>
<java.version>21</java.version>
<opentracing.version>0.33.0</opentracing.version>
<opentelemetry.version>1.41.0</opentelemetry.version>
<opentelemetry.version>1.45.0</opentelemetry.version>
<!-- Latest version of public tracer APP to match latest pulled agent -->
<dd-trace-api.version>[1.0.0,)</dd-trace-api.version>
</properties>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package com.datadoghq.trace.controller;

import static java.util.stream.Collectors.joining;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;

final class ConfigHelper {
private static final String GET_METHOD_NAME = "get";
private static final String CONFIG_CLASS_NAME = "datadog.trace.api.Config";
private static final String INSTRUMENTER_CONFIG_CLASS_NAME = "datadog.trace.api.InstrumenterConfig";
private final Class<?> configClass;
private final Object config;
private final Class<?> instrumenterClass;
private final Object instrumenterConfig;

public ConfigHelper() {
try {
this.configClass = Class.forName(CONFIG_CLASS_NAME);
this.config = getStaticInstanceOf(this.configClass);
this.instrumenterClass = Class.forName(INSTRUMENTER_CONFIG_CLASS_NAME);
this.instrumenterConfig = getStaticInstanceOf(this.instrumenterClass);
} catch (ReflectiveOperationException e) {
throw new IllegalStateException("Failed to initialize config helper", e);
}
}

public String getConfigValue(String accessorName) {
Object value = getValue(this.configClass, this.config, accessorName);
return value == null ? null : value.toString();
}

public String getConfigCollectionValues(String accessorName, String delimiter) {
Object value = getValue(this.configClass, this.config, accessorName);
if (value instanceof Collection<?> collection) {
return collection.stream()
.map(Object::toString)
.collect(joining(delimiter));
} else {
return value == null ? null : value.toString();
}
}

public String getConfigMapValues(String accessorName, String delimiter, String pair) {
Object value = getValue(this.configClass, this.config, accessorName);
if (value instanceof Map<?, ?> map) {
StringBuilder builder = new StringBuilder();
map.forEach((k, v) ->
builder.append(k).append(pair).append(v).append(delimiter));
if (!builder.isEmpty()) {
builder.setLength(builder.length() - delimiter.length());
}
return builder.toString();
} else {
return value == null ? null : value.toString();
}
}

public String getInstrumenterConfigValue(String accessorName) {
Object value = getValue(this.instrumenterClass, this.instrumenterConfig, accessorName);
return value == null ? null : value.toString();
}

private Object getValue(Class<?> configClass, Object config, String accessorName) {
try {
Method method = configClass.getMethod(accessorName);
return method.invoke(config);
} catch (ReflectiveOperationException e) {
throw new IllegalStateException(
"Failed get config value from " + configClass + "." + accessorName + "()", e);
}
}

private static Object getStaticInstanceOf(Class<?> clazz) throws ReflectiveOperationException{
Method getConfigMethod = clazz.getMethod(GET_METHOD_NAME);
return getConfigMethod.invoke(null);
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
package com.datadoghq.trace.controller;

import static com.datadoghq.ApmTestClient.LOGGER;
import static java.util.Map.entry;

import com.datadoghq.trace.trace.dto.GetTraceConfigResult;
import com.datadoghq.trace.dto.GetTraceConfigResult;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import datadog.trace.api.TracePropagationStyle;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.nio.file.Files;
import java.nio.file.Path;

Expand All @@ -29,92 +25,35 @@ public class TraceController {
@GetMapping("config")
public GetTraceConfigResult config() {
LOGGER.info("Getting tracer config");
try
{
// Use reflection to get the static Config instance
Class configClass = Class.forName("datadog.trace.api.Config");
Method getConfigMethod = configClass.getMethod("get");

Class instrumenterConfigClass = Class.forName("datadog.trace.api.InstrumenterConfig");
Method getInstrumenterConfigMethod = instrumenterConfigClass.getMethod("get");

Object configObject = getConfigMethod.invoke(null);
Object instrumenterConfigObject = getInstrumenterConfigMethod.invoke(null);

Method getServiceName = configClass.getMethod("getServiceName");
Method getEnv = configClass.getMethod("getEnv");
Method getVersion = configClass.getMethod("getVersion");
Method getTraceSampleRate = configClass.getMethod("getTraceSampleRate");
Method isTraceEnabled = configClass.getMethod("isTraceEnabled");
Method isRuntimeMetricsEnabled = configClass.getMethod("isRuntimeMetricsEnabled");
Method getGlobalTags = configClass.getMethod("getGlobalTags");
Method getTracePropagationStylesToInject = configClass.getMethod("getTracePropagationStylesToInject");
Method isDebugEnabled = configClass.getMethod("isDebugEnabled");
Method getLogLevel = configClass.getMethod("getLogLevel");
Method getAgentUrl = configClass.getMethod("getAgentUrl");
Method getTraceRateLimit = configClass.getMethod("getTraceRateLimit");
Method getJmxFetchStatsdPort = configClass.getMethod("getJmxFetchStatsdPort");
Method getJmxFetchStatsdHost = configClass.getMethod("getJmxFetchStatsdHost");

Method isTraceOtelEnabled = instrumenterConfigClass.getMethod("isTraceOtelEnabled");

Map<String, String> configMap = new HashMap<>();
configMap.put("dd_service", getServiceName.invoke(configObject).toString());
configMap.put("dd_env", getEnv.invoke(configObject).toString());
configMap.put("dd_version", getVersion.invoke(configObject).toString());
configMap.put("dd_log_level", Optional.ofNullable(getLogLevel.invoke(configObject)).map(Object::toString).orElse(null));
configMap.put("dd_trace_enabled", isTraceEnabled.invoke(configObject).toString());
configMap.put("dd_runtime_metrics_enabled", isRuntimeMetricsEnabled.invoke(configObject).toString());
configMap.put("dd_trace_debug", isDebugEnabled.invoke(configObject).toString());
configMap.put("dd_trace_otel_enabled", isTraceOtelEnabled.invoke(instrumenterConfigObject).toString());
configMap.put("dd_trace_agent_url", getAgentUrl.invoke(configObject).toString());
// configMap.put("dd_trace_sample_ignore_parent", Config.get());

Object dogstatsdHost = getJmxFetchStatsdHost.invoke(configObject);
if (dogstatsdHost != null){
configMap.put("dd_dogstatsd_host", getJmxFetchStatsdHost.invoke(configObject).toString());
}

Object sampleRate = getTraceSampleRate.invoke(configObject);
if (sampleRate instanceof Double) {
configMap.put("dd_trace_sample_rate", String.valueOf((Double)sampleRate));
}

Object rateLimit = getTraceRateLimit.invoke(configObject);
if (rateLimit instanceof Integer) {
configMap.put("dd_trace_rate_limit", Integer.toString((int)rateLimit));
}

Object statsPort = getJmxFetchStatsdPort.invoke(configObject);
if (statsPort instanceof Integer) {
configMap.put("dd_dogstatsd_port", Integer.toString((int)statsPort));
}

Object globalTags = getGlobalTags.invoke(configObject);
if (globalTags != null) {
String result = ((Map<String, String>)globalTags).entrySet()
.stream()
.map(entry -> entry.getKey() + ":" + entry.getValue())
.collect(Collectors.joining(","));

configMap.put("dd_tags", result);
}

Object propagationStyles = getTracePropagationStylesToInject.invoke(configObject);
if (propagationStyles != null) {
String result = ((Set<TracePropagationStyle>)propagationStyles)
.stream()
.map(style -> style.toString())
.collect(Collectors.joining(","));

configMap.put("dd_trace_propagation_style", result);
}

configMap.values().removeIf(Objects::isNull);
return new GetTraceConfigResult(configMap);
try {
ConfigHelper helper = new ConfigHelper();
var configMapping = Map.ofEntries(
entry("dd_service", "getServiceName"),
entry("dd_env", "getEnv"),
entry("dd_version", "getVersion"),
entry("dd_log_level", "getLogLevel"),
entry("dd_trace_enabled", "isTraceEnabled"),
entry("dd_runtime_metrics_enabled", "isRuntimeMetricsEnabled"),
entry("dd_trace_debug", "isDebugEnabled"),
entry("dd_trace_agent_url", "getAgentUrl"),
entry("dd_dogstatsd_host", "getJmxFetchStatsdHost"),
entry("dd_dogstatsd_port", "getJmxFetchStatsdPort"),
entry("dd_trace_sample_rate", "getTraceSampleRate"),
entry("dd_trace_rate_limit", "getTraceRateLimit")
);
Map<String, String> config = new HashMap<>();
configMapping.forEach(
(key, accessor) -> config.put(key, helper.getConfigValue(accessor))
);
config.put("dd_trace_propagation_style", helper.getConfigCollectionValues("getTracePropagationStylesToInject", ","));
config.put("dd_tags", helper.getConfigMapValues("getGlobalTags", ",", ":"));
config.put("dd_trace_otel_enabled", helper.getInstrumenterConfigValue("isTraceOtelEnabled"));

config.values().removeIf(Objects::isNull);
return new GetTraceConfigResult(config);
} catch (Throwable t) {
LOGGER.error("Uncaught throwable", t);
return GetTraceConfigResult.error();
LOGGER.error("Uncaught throwable", t);
return GetTraceConfigResult.error();
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package com.datadoghq.trace.trace.dto;
package com.datadoghq.trace.dto;

import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.HashMap;
import java.util.Map;

public record GetTraceConfigResult(
Map<String, String> config) {
public record GetTraceConfigResult(Map<String, String> config) {
public static GetTraceConfigResult error(){
return new GetTraceConfigResult(new HashMap<>());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ public void flush() {
LOGGER.info("Flushing metrics");
try {
// Only flush trace stats when tracing was enabled
if (GlobalTracer.get() instanceof InternalTracer) {
((InternalTracer) GlobalTracer.get()).flushMetrics();
if (GlobalTracer.get() instanceof InternalTracer internalTracer) {
internalTracer.flushMetrics();
}
} catch (Exception e) {
LOGGER.warn("Failed to flush metrics", e);
Expand Down
Loading
Loading