Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package datadog.opentelemetry.shim.metrics;

import io.opentelemetry.api.metrics.BatchCallback;
import io.opentelemetry.api.metrics.DoubleGaugeBuilder;
import io.opentelemetry.api.metrics.DoubleHistogramBuilder;
import io.opentelemetry.api.metrics.LongCounterBuilder;
import io.opentelemetry.api.metrics.LongUpDownCounterBuilder;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.ObservableMeasurement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

// https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/1.47.0/io/opentelemetry/api/metrics/Meter.html
public class OtelMeter implements Meter {
private static final Logger LOGGER = LoggerFactory.getLogger(OtelMeter.class);

private final String instrumentationScopeName;
private final String schemaUrl;
private final String instrumentationVersion;

public OtelMeter(
String instrumentationScopeName, String schemaUrl, String instrumentationVersion) {
this.instrumentationScopeName = instrumentationScopeName;
this.schemaUrl = schemaUrl;
this.instrumentationVersion = instrumentationVersion;
}

public boolean match(
String instrumentationScopeName, String instrumentationVersion, String schemaUrl) {
return instrumentationScopeName.equals(this.instrumentationScopeName)
&& schemaUrl.equals(this.schemaUrl)
&& instrumentationVersion.equals(this.instrumentationVersion);
}

@Override
public LongCounterBuilder counterBuilder(String instrumentName) {
LOGGER.info("CounterBuilder is not yet supported");
return null;
}

@Override
public LongUpDownCounterBuilder upDownCounterBuilder(String instrumentName) {
LOGGER.info("upDownCounterBuilder is not yet supported");
return null;
}

@Override
public DoubleHistogramBuilder histogramBuilder(String instrumentName) {
LOGGER.info("histogramBuilder is not yet supported");
return null;
}

@Override
public DoubleGaugeBuilder gaugeBuilder(String instrumentName) {
LOGGER.info("gaugeBuilder is not yet supported");
return null;
}

@Override
public BatchCallback batchCallback(
Runnable callback,
ObservableMeasurement observableMeasurement,
ObservableMeasurement... additionalMeasurements) {
LOGGER.info("batchCallback is not yet supported");
return Meter.super.batchCallback(callback, observableMeasurement, additionalMeasurements);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package datadog.opentelemetry.shim.metrics;

import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.MeterBuilder;
import javax.annotation.ParametersAreNonnullByDefault;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class OtelMeterBuilder implements MeterBuilder {
private static final Logger LOGGER = LoggerFactory.getLogger(OtelMeterBuilder.class);
private final String instrumentationScopeName;
private String schemaUrl;
private String instrumentationVersion;

public OtelMeterBuilder(String instrumentationScopeName) {
this.instrumentationScopeName = instrumentationScopeName;
}

@Override
@ParametersAreNonnullByDefault
public MeterBuilder setSchemaUrl(String schemaUrl) {
this.schemaUrl = schemaUrl;
return this;
}

@Override
@ParametersAreNonnullByDefault
public MeterBuilder setInstrumentationVersion(String instrumentationVersion) {
this.instrumentationVersion = instrumentationVersion;
return this;
}

@Override
public Meter build() {
return new OtelMeter(instrumentationScopeName, instrumentationVersion, schemaUrl);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package datadog.opentelemetry.shim.metrics;

import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.MeterBuilder;
import io.opentelemetry.api.metrics.MeterProvider;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.ParametersAreNonnullByDefault;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class OtelMeterProvider implements MeterProvider {
private static final Logger LOGGER = LoggerFactory.getLogger(OtelMeterProvider.class);
private static final String DEFAULT_METER_NAME = "";
public static final MeterProvider INSTANCE = new OtelMeterProvider();
/** Meter instances, indexed by instrumentation scope name. */
private final Map<String, List<Meter>> scopedMeters = new ConcurrentHashMap<>();

@Override
@ParametersAreNonnullByDefault
public Meter get(String instrumentationScopeName) {
return get(instrumentationScopeName, null);
}

public Meter get(String instrumentationScopeName, String instrumentationVersion) {
return get(instrumentationScopeName, instrumentationVersion, null);
}

public Meter get(
String instrumentationScopeName, String instrumentationVersion, String urlSchema) {
List<Meter> meters = this.scopedMeters.get(instrumentationScopeName);
if (meters != null) {
for (Meter meter : meters) {
if ((meter instanceof OtelMeter)
&& ((OtelMeter) meter)
.match(instrumentationScopeName, instrumentationVersion, urlSchema)) {
return meter;
}
}
}
Meter meter =
meterBuilder(instrumentationScopeName)
.setInstrumentationVersion(instrumentationVersion)
.setSchemaUrl(urlSchema)
.build();
this.scopedMeters.put(instrumentationScopeName, new ArrayList<>());
this.scopedMeters.get(instrumentationScopeName).add(meter);

return meter;
}

@Override
public MeterBuilder meterBuilder(String instrumentationScopeName) {
if (instrumentationScopeName.trim().isEmpty()) {
LOGGER.debug("Meter requested without instrumentation scope name.");
instrumentationScopeName = DEFAULT_METER_NAME;
}
return new OtelMeterBuilder(instrumentationScopeName);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
def openTelemetryVersion = '1.47.0'

muzzle {
pass {
module = 'opentelemetry-api'
group = 'io.opentelemetry'
versions = "[$openTelemetryVersion,)"
}
}

apply from: "$rootDir/gradle/java.gradle"

addTestSuiteForDir('latestDepTest', 'test')

dependencies {
compileOnly group: 'io.opentelemetry', name: 'opentelemetry-api', version: openTelemetryVersion
compileOnly group: 'com.google.auto.value', name: 'auto-value-annotations', version: '1.6.6'

implementation project(':dd-java-agent:agent-otel:otel-shim')
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package datadog.trace.instrumentation.opentelemetry147;

import static datadog.trace.agent.tooling.bytebuddy.matcher.HierarchyMatchers.implementsInterface;
import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.returns;
import static net.bytebuddy.matcher.ElementMatchers.takesNoArguments;

import com.google.auto.service.AutoService;
import datadog.opentelemetry.shim.metrics.OtelMeterProvider;
import datadog.trace.agent.tooling.Instrumenter;
import datadog.trace.agent.tooling.InstrumenterModule;
import io.opentelemetry.api.metrics.MeterProvider;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;

@AutoService(InstrumenterModule.class)
public class OpenTelemetryInstrumentation extends InstrumenterModule.Tracing
implements Instrumenter.CanShortcutTypeMatching, Instrumenter.HasMethodAdvice {

public OpenTelemetryInstrumentation() {
super("opentelemetry.metrics", "opentelemetry-147");
}

@Override
protected boolean defaultEnabled() {
// Not activated yet to prevent NPE
// return InstrumenterConfig.get().isMetricsOtelEnabled();
return false;
}

@Override
public String hierarchyMarkerType() {
return "io.opentelemetry.api.OpenTelemetry";
}

@Override
public ElementMatcher<TypeDescription> hierarchyMatcher() {
return implementsInterface(named(hierarchyMarkerType()));
}

@Override
public String[] knownMatchingTypes() {
return new String[] {
"io.opentelemetry.api.DefaultOpenTelemetry",
"io.opentelemetry.api.GlobalOpenTelemetry$ObfuscatedOpenTelemetry"
};
}

@Override
public boolean onlyMatchKnownTypes() {
return isShortcutMatchingEnabled(false);
}

@Override
public String[] helperClassNames() {
return new String[] {
"datadog.opentelemetry.shim.metrics.OtelMeter",
"datadog.opentelemetry.shim.metrics.OtelMeterBuilder",
"datadog.opentelemetry.shim.metrics.OtelMeterProvider",
};
}

@Override
public void methodAdvice(MethodTransformer transformer) {
// MeterProvider OpenTelemetry.getMeterProvider()
transformer.applyAdvice(
isMethod()
.and(named("getMeterProvider"))
.and(takesNoArguments())
.and(returns(named("io.opentelemetry.api.metrics.MeterProvider"))),
OpenTelemetryInstrumentation.class.getName() + "$MeterProviderAdvice");
}

public static class MeterProviderAdvice {
@Advice.OnMethodExit(suppress = Throwable.class)
public static void returnProvider(@Advice.Return(readOnly = false) MeterProvider result) {
result = OtelMeterProvider.INSTANCE;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import static datadog.trace.api.ConfigDefaults.DEFAULT_INTEGRATIONS_ENABLED;
import static datadog.trace.api.ConfigDefaults.DEFAULT_LLM_OBS_ENABLED;
import static datadog.trace.api.ConfigDefaults.DEFAULT_MEASURE_METHODS;
import static datadog.trace.api.ConfigDefaults.DEFAULT_METRICS_OTEL_ENABLED;
import static datadog.trace.api.ConfigDefaults.DEFAULT_RESOLVER_RESET_INTERVAL;
import static datadog.trace.api.ConfigDefaults.DEFAULT_RUM_ENABLED;
import static datadog.trace.api.ConfigDefaults.DEFAULT_RUNTIME_CONTEXT_FIELD_INJECTION;
Expand All @@ -29,6 +30,7 @@
import static datadog.trace.api.config.GeneralConfig.TRIAGE_REPORT_TRIGGER;
import static datadog.trace.api.config.IastConfig.IAST_ENABLED;
import static datadog.trace.api.config.LlmObsConfig.LLMOBS_ENABLED;
import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_ENABLED;
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DIRECT_ALLOCATION_ENABLED;
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DIRECT_ALLOCATION_ENABLED_DEFAULT;
import static datadog.trace.api.config.ProfilingConfig.PROFILING_ENABLED;
Expand Down Expand Up @@ -126,6 +128,7 @@ public class InstrumenterConfig {
private final boolean codeOriginEnabled;
private final boolean traceEnabled;
private final boolean traceOtelEnabled;
private final boolean metricsOtelEnabled;
private final ProfilingEnablement profilingEnabled;
private final boolean ciVisibilityEnabled;
private final ProductActivation appSecActivation;
Expand Down Expand Up @@ -219,6 +222,8 @@ private InstrumenterConfig() {
CODE_ORIGIN_FOR_SPANS_ENABLED, DEFAULT_CODE_ORIGIN_FOR_SPANS_ENABLED);
traceEnabled = configProvider.getBoolean(TRACE_ENABLED, DEFAULT_TRACE_ENABLED);
traceOtelEnabled = configProvider.getBoolean(TRACE_OTEL_ENABLED, DEFAULT_TRACE_OTEL_ENABLED);
metricsOtelEnabled =
configProvider.getBoolean(METRICS_OTEL_ENABLED, DEFAULT_METRICS_OTEL_ENABLED);

profilingEnabled =
ProfilingEnablement.of(
Expand Down Expand Up @@ -383,6 +388,10 @@ public boolean isTraceOtelEnabled() {
return traceOtelEnabled;
}

public boolean isMetricsOtelEnabled() {
return metricsOtelEnabled;
}

public boolean isProfilingEnabled() {
return profilingEnabled.isActive();
}
Expand Down Expand Up @@ -636,6 +645,8 @@ public String toString() {
+ traceEnabled
+ ", traceOtelEnabled="
+ traceOtelEnabled
+ ", metricsOtelEnabled="
+ metricsOtelEnabled
+ ", profilingEnabled="
+ profilingEnabled
+ ", ciVisibilityEnabled="
Expand Down
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,7 @@ include(
":dd-java-agent:instrumentation:opensearch",
":dd-java-agent:instrumentation:opentelemetry:opentelemetry-0.3",
":dd-java-agent:instrumentation:opentelemetry:opentelemetry-1.4",
":dd-java-agent:instrumentation:opentelemetry:opentelemetry-1.47",
":dd-java-agent:instrumentation:opentelemetry:opentelemetry-annotations-1.20",
":dd-java-agent:instrumentation:opentelemetry:opentelemetry-annotations-1.26",
":dd-java-agent:instrumentation:opentracing:api-0.31",
Expand Down