Skip to content

Implement span started and live health metrics #7430

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

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
Comparing source compatibility of opentelemetry-sdk-trace-1.53.0-SNAPSHOT.jar against opentelemetry-sdk-trace-1.52.0.jar
No changes.
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.trace.SdkTracerProviderBuilder (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.trace.SdkTracerProviderBuilder setInternalTelemetry(io.opentelemetry.sdk.common.InternalTelemetryVersion)
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.trace.SdkTracerProviderBuilder setInternalTelemetryOpenTelemetry(java.util.function.Supplier<io.opentelemetry.api.OpenTelemetry>)
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ public String toString(boolean includePrefixAndSuffix) {
joiner.add("executorService=" + executorService);
}
joiner.add("exporterType=" + exporterType.toString());
joiner.add("internalTelemetrySchemaVersion=" + internalTelemetryVersion);
joiner.add("internalTelemetryVersion=" + internalTelemetryVersion);
// Note: omit tlsConfigHelper because we can't log the configuration in any readable way
// Note: omit meterProviderSupplier because we can't log the configuration in any readable way
return joiner.toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ public String toString(boolean includePrefixAndSuffix) {
joiner.add("executorService=" + executorService);
}
joiner.add("exporterType=" + exporterType);
joiner.add("internalTelemetrySchemaVersion=" + internalTelemetryVersion);
joiner.add("internalTelemetryVersion=" + internalTelemetryVersion);
// Note: omit tlsConfigHelper because we can't log the configuration in any readable way
// Note: omit meterProviderSupplier because we can't log the configuration in any readable way
return joiner.toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ String toString(boolean includePrefixAndSuffix) {
joiner.add("endpoint=" + endpoint);
joiner.add("compressionEnabled=" + compressionEnabled);
joiner.add("readTimeoutMillis=" + readTimeoutMillis);
joiner.add("internalTelemetrySchemaVersion=" + internalTelemetryVersion);
joiner.add("internalTelemetryVersion=" + internalTelemetryVersion);
// Note: omit sender because we can't log the configuration in any readable way
// Note: omit encoder because we can't log the configuration in any readable way
// Note: omit localIpAddressSupplier because we can't log the configuration in any readable way
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ void stringRepresentation() {
try (ZipkinSpanExporter exporter = ZipkinSpanExporter.builder().build()) {
assertThat(exporter.toString())
.isEqualTo(
"ZipkinSpanExporter{endpoint=http://localhost:9411/api/v2/spans, compressionEnabled=true, readTimeoutMillis=10000, internalTelemetrySchemaVersion=LEGACY}");
"ZipkinSpanExporter{endpoint=http://localhost:9411/api/v2/spans, compressionEnabled=true, readTimeoutMillis=10000, internalTelemetryVersion=LEGACY}");
}
try (ZipkinSpanExporter exporter =
ZipkinSpanExporter.builder()
Expand All @@ -266,7 +266,7 @@ void stringRepresentation() {
.build()) {
assertThat(exporter.toString())
.isEqualTo(
"ZipkinSpanExporter{endpoint=http://zipkin:9411/api/v2/spans, compressionEnabled=false, readTimeoutMillis=15000, internalTelemetrySchemaVersion=LEGACY}");
"ZipkinSpanExporter{endpoint=http://zipkin:9411/api/v2/spans, compressionEnabled=false, readTimeoutMillis=15000, internalTelemetryVersion=LEGACY}");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ private SemConvAttributes() {}
AttributeKey.stringKey("otel.component.name");
public static final AttributeKey<String> ERROR_TYPE = AttributeKey.stringKey("error.type");

public static final AttributeKey<String> OTEL_SPAN_SAMPLING_RESULT =
AttributeKey.stringKey("otel.span.sampling_result");

// TODO: Add tests verifying correctness when included in the semconv-incubating release
public static final AttributeKey<String> OTEL_SPAN_PARENT_ORIGIN =
AttributeKey.stringKey("otel.span.parent.origin");

public static final AttributeKey<String> SERVER_ADDRESS =
AttributeKey.stringKey("server.address");
public static final AttributeKey<Long> SERVER_PORT = AttributeKey.longKey("server.port");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ void testAttributeKeys() {
.isEqualTo(OtelIncubatingAttributes.OTEL_COMPONENT_NAME);
assertThat(SemConvAttributes.OTEL_COMPONENT_TYPE)
.isEqualTo(OtelIncubatingAttributes.OTEL_COMPONENT_TYPE);
assertThat(SemConvAttributes.OTEL_SPAN_SAMPLING_RESULT)
.isEqualTo(OtelIncubatingAttributes.OTEL_SPAN_SAMPLING_RESULT);

assertThat(SemConvAttributes.ERROR_TYPE).isEqualTo(ErrorAttributes.ERROR_TYPE);

Expand Down
1 change: 1 addition & 0 deletions sdk/trace/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ dependencies {
testImplementation(project(":sdk:testing"))
testImplementation("com.google.guava:guava")
testImplementation("com.google.guava:guava-testlib")
testImplementation("io.opentelemetry.semconv:opentelemetry-semconv-incubating")

jmh(project(":sdk:metrics"))
jmh(project(":sdk:testing")) {
Expand Down
14 changes: 11 additions & 3 deletions sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkSpan.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import io.opentelemetry.sdk.trace.data.SpanData;
import io.opentelemetry.sdk.trace.data.StatusData;
import io.opentelemetry.sdk.trace.internal.ExtendedSpanProcessor;
import io.opentelemetry.sdk.trace.internal.SpanInstrumentation;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
Expand Down Expand Up @@ -99,6 +100,8 @@ final class SdkSpan implements ReadWriteSpan {
@GuardedBy("lock")
private long endEpochNanos;

private final SpanInstrumentation.Recording metricRecording;

private enum EndState {
NOT_ENDED,
ENDING,
Expand Down Expand Up @@ -132,7 +135,8 @@ private SdkSpan(
@Nullable AttributesMap attributes,
@Nullable List<LinkData> links,
int totalRecordedLinks,
long startEpochNanos) {
long startEpochNanos,
SpanInstrumentation.Recording metricRecording) {
this.context = context;
this.instrumentationScopeInfo = instrumentationScopeInfo;
this.parentSpanContext = parentSpanContext;
Expand All @@ -143,6 +147,7 @@ private SdkSpan(
this.spanProcessor = spanProcessor;
this.exceptionAttributeResolver = exceptionAttributeResolver;
this.resource = resource;
this.metricRecording = metricRecording;
this.hasEnded = EndState.NOT_ENDED;
this.clock = clock;
this.startEpochNanos = startEpochNanos;
Expand Down Expand Up @@ -180,7 +185,8 @@ static SdkSpan startSpan(
@Nullable AttributesMap attributes,
@Nullable List<LinkData> links,
int totalRecordedLinks,
long userStartEpochNanos) {
long userStartEpochNanos,
SpanInstrumentation.Recording metricsRecording) {
boolean createdAnchoredClock;
AnchoredClock clock;
if (parentSpan instanceof SdkSpan) {
Expand Down Expand Up @@ -219,7 +225,8 @@ static SdkSpan startSpan(
attributes,
links,
totalRecordedLinks,
startEpochNanos);
startEpochNanos,
metricsRecording);
// Call onStart here instead of calling in the constructor to make sure the span is completely
// initialized.
if (spanProcessor.isStartRequired()) {
Expand Down Expand Up @@ -557,6 +564,7 @@ private void endInternal(long endEpochNanos) {
spanEndingThread = Thread.currentThread();
hasEnded = EndState.ENDING;
}
metricRecording.recordSpanEnd();
if (spanProcessor instanceof ExtendedSpanProcessor) {
ExtendedSpanProcessor extendedSpanProcessor = (ExtendedSpanProcessor) spanProcessor;
if (extendedSpanProcessor.isOnEndingRequired()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import io.opentelemetry.sdk.internal.AttributeUtil;
import io.opentelemetry.sdk.internal.AttributesMap;
import io.opentelemetry.sdk.trace.data.LinkData;
import io.opentelemetry.sdk.trace.internal.SpanInstrumentation;
import io.opentelemetry.sdk.trace.samplers.SamplingDecision;
import io.opentelemetry.sdk.trace.samplers.SamplingResult;
import java.util.ArrayList;
Expand Down Expand Up @@ -204,7 +205,13 @@ public Span startSpan() {
/* remote= */ false,
tracerSharedState.isIdGeneratorSafeToSkipIdValidation());

SpanInstrumentation.Recording metricsRecording =
tracerSharedState.getSpanMetrics().recordSpanStart(samplingResult, parentSpanContext);
if (!isRecording(samplingDecision)) {
if (!metricsRecording.isNoop()) {
throw new IllegalStateException(
"instrumentation ending is not supported for non-recording spans.");
}
return Span.wrap(spanContext);
}
Attributes samplingAttributes = samplingResult.getAttributes();
Expand Down Expand Up @@ -232,7 +239,8 @@ public Span startSpan() {
recordedAttributes,
currentLinks,
totalNumberOfLinksAdded,
startEpochNanos);
startEpochNanos,
metricsRecording);
}

private AttributesMap attributes() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,20 @@

package io.opentelemetry.sdk.trace;

import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.api.trace.TracerBuilder;
import io.opentelemetry.api.trace.TracerProvider;
import io.opentelemetry.sdk.common.Clock;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
import io.opentelemetry.sdk.common.InternalTelemetryVersion;
import io.opentelemetry.sdk.internal.ComponentRegistry;
import io.opentelemetry.sdk.internal.ExceptionAttributeResolver;
import io.opentelemetry.sdk.internal.ScopeConfigurator;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.internal.SdkTracerProviderUtil;
import io.opentelemetry.sdk.trace.internal.SpanInstrumentation;
import io.opentelemetry.sdk.trace.internal.TracerConfig;
import io.opentelemetry.sdk.trace.samplers.Sampler;
import java.io.Closeable;
Expand Down Expand Up @@ -54,7 +57,9 @@ public static SdkTracerProviderBuilder builder() {
Sampler sampler,
List<SpanProcessor> spanProcessors,
ScopeConfigurator<TracerConfig> tracerConfigurator,
ExceptionAttributeResolver exceptionAttributeResolver) {
ExceptionAttributeResolver exceptionAttributeResolver,
InternalTelemetryVersion internalTelemetryVersion,
Supplier<MeterProvider> meterProviderSupplier) {
this.sharedState =
new TracerSharedState(
clock,
Expand All @@ -63,7 +68,8 @@ public static SdkTracerProviderBuilder builder() {
spanLimitsSupplier,
sampler,
spanProcessors,
exceptionAttributeResolver);
exceptionAttributeResolver,
SpanInstrumentation.create(internalTelemetryVersion, meterProviderSupplier));
this.tracerSdkComponentRegistry =
new ComponentRegistry<>(
instrumentationScopeInfo ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@

import static java.util.Objects.requireNonNull;

import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.sdk.common.Clock;
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
import io.opentelemetry.sdk.common.InternalTelemetryVersion;
import io.opentelemetry.sdk.internal.ExceptionAttributeResolver;
import io.opentelemetry.sdk.internal.ScopeConfigurator;
import io.opentelemetry.sdk.internal.ScopeConfiguratorBuilder;
Expand All @@ -34,6 +38,8 @@ public final class SdkTracerProviderBuilder {
private Resource resource = Resource.getDefault();
private Supplier<SpanLimits> spanLimitsSupplier = SpanLimits::getDefault;
private Sampler sampler = DEFAULT_SAMPLER;
private Supplier<MeterProvider> meterProviderSupplier = GlobalOpenTelemetry::getMeterProvider;
private InternalTelemetryVersion internalTelemetryVersion = InternalTelemetryVersion.LEGACY;
private ScopeConfiguratorBuilder<TracerConfig> tracerConfiguratorBuilder =
TracerConfig.configuratorBuilder();
private ExceptionAttributeResolver exceptionAttributeResolver =
Expand Down Expand Up @@ -176,6 +182,28 @@ public SdkTracerProviderBuilder addSpanProcessorFirst(SpanProcessor spanProcesso
return this;
}

/**
* Sets the {@link OpenTelemetry} supplier used to collect self-monitoring telemetry. If not set,
* uses {@link GlobalOpenTelemetry#get()}.
*/
public SdkTracerProviderBuilder setInternalTelemetryOpenTelemetry(
Supplier<OpenTelemetry> openTelemetrySupplier) {
requireNonNull(openTelemetrySupplier, "openTelemetrySupplier");
this.meterProviderSupplier = () -> openTelemetrySupplier.get().getMeterProvider();
return this;
}

/**
* Sets the {@link InternalTelemetryVersion} defining which self-monitoring metrics the tracers
* originating from this provider collect.
*/
public SdkTracerProviderBuilder setInternalTelemetry(
InternalTelemetryVersion internalTelemetryVersion) {
requireNonNull(internalTelemetryVersion, "internalTelemetryVersion");
this.internalTelemetryVersion = internalTelemetryVersion;
return this;
}

/**
* Set the tracer configurator, which computes {@link TracerConfig} for each {@link
* InstrumentationScopeInfo}.
Expand Down Expand Up @@ -246,7 +274,9 @@ public SdkTracerProvider build() {
sampler,
spanProcessors,
tracerConfiguratorBuilder.build(),
exceptionAttributeResolver);
exceptionAttributeResolver,
internalTelemetryVersion,
meterProviderSupplier);
}

SdkTracerProviderBuilder() {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.internal.ExceptionAttributeResolver;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.internal.SpanInstrumentation;
import io.opentelemetry.sdk.trace.samplers.Sampler;
import java.util.List;
import java.util.function.Supplier;
Expand All @@ -28,6 +29,7 @@ final class TracerSharedState {
private final Sampler sampler;
private final SpanProcessor activeSpanProcessor;
private final ExceptionAttributeResolver exceptionAttributeResolver;
private final SpanInstrumentation spanInstrumentation;

@Nullable private volatile CompletableResultCode shutdownResult = null;

Expand All @@ -38,7 +40,8 @@ final class TracerSharedState {
Supplier<SpanLimits> spanLimitsSupplier,
Sampler sampler,
List<SpanProcessor> spanProcessors,
ExceptionAttributeResolver exceptionAttributeResolver) {
ExceptionAttributeResolver exceptionAttributeResolver,
SpanInstrumentation spanInstrumentation) {
this.clock = clock;
this.idGenerator = idGenerator;
this.idGeneratorSafeToSkipIdValidation = idGenerator instanceof RandomIdGenerator;
Expand All @@ -47,6 +50,7 @@ final class TracerSharedState {
this.sampler = sampler;
this.activeSpanProcessor = SpanProcessor.composite(spanProcessors);
this.exceptionAttributeResolver = exceptionAttributeResolver;
this.spanInstrumentation = spanInstrumentation;
}

Clock getClock() {
Expand Down Expand Up @@ -84,6 +88,10 @@ SpanProcessor getActiveSpanProcessor() {
return activeSpanProcessor;
}

SpanInstrumentation getSpanMetrics() {
return spanInstrumentation;
}

/**
* Returns {@code true} if tracing has been shut down.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.sdk.trace.internal;

import io.opentelemetry.api.trace.SpanContext;
import io.opentelemetry.sdk.trace.samplers.SamplingResult;

class NoopSpanInstrumentation implements SpanInstrumentation {

static final NoopSpanInstrumentation INSTANCE = new NoopSpanInstrumentation();

static final SpanInstrumentation.Recording RECORDING_INSTANCE = new NoopRecording();

@Override
public SpanInstrumentation.Recording recordSpanStart(
SamplingResult samplingResult, SpanContext parentContext) {
return RECORDING_INSTANCE;
}

private static class NoopRecording implements SpanInstrumentation.Recording {

@Override
public boolean isNoop() {
return true;
}

@Override
public void recordSpanEnd() {}
}
}
Loading
Loading