Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@ import java.net.URLClassLoader
abstract class MuzzleAction : WorkAction<MuzzleWorkParameters> {
companion object {
private val lock = Any()
private var bootCL: ClassLoader? = null
private var toolCL: ClassLoader? = null
@Volatile
private var lastBootCL: ClassLoader? = null
@Volatile
private var lastToolCL: ClassLoader? = null
@Volatile
private var lastBuildStamp: Long = 0
@Volatile
private var lastBuildPathCount: Int = 0

fun createClassLoader(cp: FileCollection, parent: ClassLoader = ClassLoader.getSystemClassLoader()): ClassLoader {
val urls = cp.map { it.toURI().toURL() }.toTypedArray()
Expand All @@ -22,12 +26,21 @@ abstract class MuzzleAction : WorkAction<MuzzleWorkParameters> {

override fun execute() {
val buildStamp = parameters.buildStartedTime.get()
if (bootCL == null || toolCL == null || lastBuildStamp < buildStamp) {
val buildPathCount = parameters.bootstrapClassPath.count() + parameters.toolingClassPath.count()
var bootCL : ClassLoader? = lastBootCL
var toolCL : ClassLoader? = lastToolCL
// cache boot and tool classloaders for each run; rebuild if either class-path is extended mid-build
if (bootCL == null || toolCL == null || lastBuildStamp < buildStamp || lastBuildPathCount < buildPathCount) {
synchronized(lock) {
if (bootCL == null || toolCL == null || lastBuildStamp < buildStamp) {
bootCL = lastBootCL
toolCL = lastToolCL
if (bootCL == null || toolCL == null || lastBuildStamp < buildStamp || lastBuildPathCount < buildPathCount) {
bootCL = createClassLoader(parameters.bootstrapClassPath)
toolCL = createClassLoader(parameters.toolingClassPath, bootCL!!)
lastBootCL = bootCL
lastToolCL = toolCL
lastBuildStamp = buildStamp
lastBuildPathCount = buildPathCount
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package datadog.opentelemetry.shim;
package datadog.trace.bootstrap.otel.common;

import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString;
import java.util.Objects;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package datadog.opentelemetry.shim.metrics;
package datadog.trace.bootstrap.otel.metrics;

import datadog.opentelemetry.shim.metrics.data.OtelMetricStorage;
import datadog.trace.bootstrap.otel.metrics.data.OtelMetricStorage;

/** Ensure all instruments implement the same equivalency. */
abstract class OtelInstrument {
final OtelMetricStorage storage;
public abstract class OtelInstrument {
protected final OtelMetricStorage storage;

OtelInstrument(OtelMetricStorage storage) {
protected OtelInstrument(OtelMetricStorage storage) {
this.storage = storage;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package datadog.opentelemetry.shim.metrics;
package datadog.trace.bootstrap.otel.metrics;

import javax.annotation.Nullable;

final class OtelInstrumentBuilder {
public final class OtelInstrumentBuilder {
private final String instrumentName;
private final OtelInstrumentType instrumentType;
private final boolean longValues;
Expand All @@ -17,7 +17,8 @@ final class OtelInstrumentBuilder {
* @param instrumentType the type of the instrument
* @return new instrument builder
*/
static OtelInstrumentBuilder ofLongs(String instrumentName, OtelInstrumentType instrumentType) {
public static OtelInstrumentBuilder ofLongs(
String instrumentName, OtelInstrumentType instrumentType) {
return new OtelInstrumentBuilder(instrumentName, instrumentType, true);
}

Expand All @@ -28,7 +29,7 @@ static OtelInstrumentBuilder ofLongs(String instrumentName, OtelInstrumentType i
* @param instrumentType the type of the instrument
* @return new instrument builder
*/
static OtelInstrumentBuilder ofLongs(
public static OtelInstrumentBuilder ofLongs(
OtelInstrumentBuilder builder, OtelInstrumentType instrumentType) {
return new OtelInstrumentBuilder(builder.instrumentName, instrumentType, true);
}
Expand All @@ -40,7 +41,8 @@ static OtelInstrumentBuilder ofLongs(
* @param instrumentType the type of the instrument
* @return new instrument builder
*/
static OtelInstrumentBuilder ofDoubles(String instrumentName, OtelInstrumentType instrumentType) {
public static OtelInstrumentBuilder ofDoubles(
String instrumentName, OtelInstrumentType instrumentType) {
return new OtelInstrumentBuilder(instrumentName, instrumentType, false);
}

Expand All @@ -51,7 +53,7 @@ static OtelInstrumentBuilder ofDoubles(String instrumentName, OtelInstrumentType
* @param instrumentType the type of the instrument
* @return new instrument builder
*/
static OtelInstrumentBuilder ofDoubles(
public static OtelInstrumentBuilder ofDoubles(
OtelInstrumentBuilder builder, OtelInstrumentType instrumentType) {
return new OtelInstrumentBuilder(builder.instrumentName, instrumentType, false);
}
Expand All @@ -63,20 +65,20 @@ private OtelInstrumentBuilder(
this.longValues = longValues;
}

void setDescription(String description) {
public void setDescription(String description) {
this.description = description;
}

void setUnit(String unit) {
public void setUnit(String unit) {
this.unit = unit;
}

OtelInstrumentDescriptor descriptor() {
public OtelInstrumentDescriptor descriptor() {
return new OtelInstrumentDescriptor(
instrumentName, instrumentType, longValues, description, unit);
}

OtelInstrumentDescriptor observableDescriptor() {
public OtelInstrumentDescriptor observableDescriptor() {
return new OtelInstrumentDescriptor(
instrumentName, observableType(instrumentType), longValues, description, unit);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package datadog.opentelemetry.shim.metrics;
package datadog.trace.bootstrap.otel.metrics;

import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString;
import java.util.Locale;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package datadog.opentelemetry.shim.metrics;
package datadog.trace.bootstrap.otel.metrics;

public enum OtelInstrumentType {
// same order as io.opentelemetry.sdk.metrics.InstrumentType
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package datadog.opentelemetry.shim.metrics.data;
package datadog.trace.bootstrap.otel.metrics.data;

/** Common behaviour shared across all aggregators. */
abstract class OtelAggregator {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package datadog.opentelemetry.shim.metrics.data;
package datadog.trace.bootstrap.otel.metrics.data;

public final class OtelDoublePoint extends OtelPoint {
public final double value;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package datadog.opentelemetry.shim.metrics.data;
package datadog.trace.bootstrap.otel.metrics.data;

import java.util.concurrent.atomic.DoubleAdder;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package datadog.opentelemetry.shim.metrics.data;
package datadog.trace.bootstrap.otel.metrics.data;

final class OtelDoubleValue extends OtelAggregator {
private volatile double value;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package datadog.opentelemetry.shim.metrics.data;
package datadog.trace.bootstrap.otel.metrics.data;

import java.util.List;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package datadog.opentelemetry.shim.metrics.data;
package datadog.trace.bootstrap.otel.metrics.data;

import datadog.metrics.api.Histogram;
import java.util.List;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package datadog.opentelemetry.shim.metrics.data;
package datadog.trace.bootstrap.otel.metrics.data;

public final class OtelLongPoint extends OtelPoint {
public final long value;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package datadog.opentelemetry.shim.metrics.data;
package datadog.trace.bootstrap.otel.metrics.data;

import java.util.concurrent.atomic.LongAdder;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package datadog.opentelemetry.shim.metrics.data;
package datadog.trace.bootstrap.otel.metrics.data;

final class OtelLongValue extends OtelAggregator {
private volatile long value;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package datadog.trace.bootstrap.otel.metrics.data;

import datadog.trace.bootstrap.otel.common.OtelInstrumentationScope;
import datadog.trace.bootstrap.otel.metrics.OtelInstrumentDescriptor;
import datadog.trace.bootstrap.otel.metrics.export.OtelMetricsVisitor;
import datadog.trace.bootstrap.otel.metrics.export.OtelScopedMetricsVisitor;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

/** Tracks metric storage and observable callbacks by instrumentation scope. */
public final class OtelMetricRegistry {
public static final OtelMetricRegistry INSTANCE = new OtelMetricRegistry();

private final Map<OtelInstrumentationScope, Map<OtelInstrumentDescriptor, OtelMetricStorage>>
scopedStorage = new ConcurrentHashMap<>();

private final Map<OtelInstrumentationScope, List<OtelObservable>> scopedObservables =
new ConcurrentHashMap<>();

public OtelMetricStorage registerStorage(
OtelInstrumentationScope instrumentationScope,
OtelInstrumentDescriptor descriptor,
Function<OtelInstrumentDescriptor, OtelMetricStorage> storageFactory) {
return scopedStorage
.computeIfAbsent(instrumentationScope, unused -> new ConcurrentHashMap<>())
.computeIfAbsent(descriptor, storageFactory);
}

public void registerObservable(
OtelInstrumentationScope instrumentationScope, OtelObservable observable) {
List<OtelObservable> observables =
scopedObservables.computeIfAbsent(instrumentationScope, unused -> new ArrayList<>());
synchronized (observables) {
observables.add(observable);
}
}

public boolean unregisterObservable(
OtelInstrumentationScope instrumentationScope, OtelObservable observable) {
List<OtelObservable> observables = scopedObservables.get(instrumentationScope);
if (observables == null) {
return false;
}
synchronized (observables) {
return observables.remove(observable);
}
}

public void collectMetrics(OtelMetricsVisitor visitor) {
scopedStorage.forEach(
(scope, storage) ->
collectScopedMetrics(scope, storage, visitor.visitScopedMetrics(scope)));
}

private void collectScopedMetrics(
OtelInstrumentationScope instrumentationScope,
Map<OtelInstrumentDescriptor, OtelMetricStorage> storage,
OtelScopedMetricsVisitor visitor) {
List<OtelObservable> observables = scopedObservables.get(instrumentationScope);
if (observables != null) {
// take local snapshot of current observables
List<OtelObservable> observablesCopy;
synchronized (observables) {
observablesCopy = new ArrayList<>(observables);
}
// must observe measurements outside of lock
observablesCopy.forEach(OtelObservable::observeMeasurements);
}
storage.forEach((descriptor, s) -> s.collectMetric(visitor.visitMetric(descriptor)));
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package datadog.opentelemetry.shim.metrics.data;
package datadog.trace.bootstrap.otel.metrics.data;

import datadog.opentelemetry.shim.metrics.OtelInstrumentDescriptor;
import datadog.opentelemetry.shim.metrics.OtelInstrumentType;
import datadog.opentelemetry.shim.metrics.export.OtelInstrumentVisitor;
import datadog.trace.api.Config;
import datadog.trace.api.config.OtlpConfig;
import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString;
import datadog.trace.bootstrap.otel.metrics.OtelInstrumentDescriptor;
import datadog.trace.bootstrap.otel.metrics.OtelInstrumentType;
import datadog.trace.bootstrap.otel.metrics.export.OtelMetricVisitor;
import datadog.trace.relocate.api.RatelimitedLogger;
import io.opentelemetry.api.common.Attributes;
import java.util.List;
Expand Down Expand Up @@ -35,7 +35,7 @@ public final class OtelMetricStorage {

private final OtelInstrumentDescriptor descriptor;
private final boolean resetOnCollect;
private final Function<Attributes, OtelAggregator> aggregatorSupplier;
private final Function<Object, OtelAggregator> aggregatorSupplier;
private volatile Recording currentRecording;

// only used with DELTA temporality
Expand Down Expand Up @@ -98,7 +98,7 @@ public OtelInstrumentDescriptor getDescriptor() {
return descriptor;
}

public void recordLong(long value, Attributes attributes) {
public void recordLong(long value, Object attributes) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❔ question: ‏I guess the type was erased to not have OTel attributes into agent bootstrap.
How is that working with the CARDINALITY_OVERFLOW constant then?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct:

To achieve a single metric registry we cannot use the specific Attributes class in the generic type of the map or certain method argument types. This is because the Attributes type for drop-in will be different to the Attributes type provided on the application class-path. We use Object since there is no other common type.

At collection time we'll use the appropriate function to map either Attributes type to the right OTLP content.

CARDINALITY_OVERFLOW is a shared internal constant, so both drop-in and the instrumentation will end up using the same key for that case.

if (resetOnCollect) {
Recording recording = acquireRecordingForWrite();
try {
Expand All @@ -112,7 +112,7 @@ public void recordLong(long value, Attributes attributes) {
}
}

public void recordDouble(double value, Attributes attributes) {
public void recordDouble(double value, Object attributes) {
if (Double.isNaN(value)) {
LOGGER.debug(
"Instrument {} has recorded measurement Not-a-Number (NaN) value with attributes {}. Dropping measurement.",
Expand All @@ -133,8 +133,7 @@ public void recordDouble(double value, Attributes attributes) {
}
}

private OtelAggregator aggregator(
Map<Attributes, OtelAggregator> aggregators, Attributes attributes) {
private OtelAggregator aggregator(Map<Object, OtelAggregator> aggregators, Object attributes) {
Objects.requireNonNull(attributes, "attributes");
OtelAggregator aggregator = aggregators.get(attributes);
if (null != aggregator) {
Expand All @@ -150,7 +149,7 @@ private OtelAggregator aggregator(
return aggregators.computeIfAbsent(attributes, aggregatorSupplier);
}

public void collect(OtelInstrumentVisitor visitor) {
public void collectMetric(OtelMetricVisitor visitor) {
if (resetOnCollect) {
doCollectAndReset(visitor);
} else {
Expand All @@ -159,7 +158,7 @@ public void collect(OtelInstrumentVisitor visitor) {
}

/** Collect data for CUMULATIVE temporality, keeping aggregators for future writes. */
private void doCollect(OtelInstrumentVisitor visitor) {
private void doCollect(OtelMetricVisitor visitor) {
// no need to hold writers back if we are not resetting metrics on collect
currentRecording.aggregators.forEach(
(attributes, aggregator) -> {
Expand All @@ -174,7 +173,7 @@ private void doCollect(OtelInstrumentVisitor visitor) {
*
* <p>Each collect request toggles between two groups of aggregators: current / previous.
*/
private void doCollectAndReset(OtelInstrumentVisitor visitor) {
private void doCollectAndReset(OtelMetricVisitor visitor) {

// capture _current_ recording for collection, its aggregators will be reset at the end
final Recording recording = currentRecording;
Expand All @@ -188,7 +187,7 @@ private void doCollectAndReset(OtelInstrumentVisitor visitor) {
Thread.yield(); // other threads are still writing to this recording
}

Map<Attributes, OtelAggregator> aggregators = recording.aggregators;
Map<Object, OtelAggregator> aggregators = recording.aggregators;

// avoid churn: only remove empty aggregators if we're over cardinality
if (aggregators.size() >= CARDINALITY_LIMIT) {
Expand Down Expand Up @@ -233,7 +232,7 @@ private void releaseRecordingAfterWrite(Recording recording) {
private static final int WRITER = 2;

static final class Recording {
final Map<Attributes, OtelAggregator> aggregators;
final Map<Object, OtelAggregator> aggregators;

transient volatile int activity;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package datadog.trace.bootstrap.otel.metrics.data;

public abstract class OtelObservable {
protected abstract void observeMeasurements();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package datadog.trace.bootstrap.otel.metrics.data;

public abstract class OtelPoint {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package datadog.trace.bootstrap.otel.metrics.export;

import datadog.trace.bootstrap.otel.metrics.data.OtelPoint;

/** A visitor to visit a metric in an instrumentation scope. */
public interface OtelMetricVisitor {
/** Visits a data point in the metric. */
void visitPoint(Object attributes, OtelPoint point);
}
Loading
Loading