Skip to content
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
@@ -0,0 +1,38 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.exporter.otlp.internal;

import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.common.InternalTelemetryVersion;
import java.util.Locale;

/**
* Reads the desired SDK internal telemetry version from {@link ConfigProperties}.
*
* <p>This is the same as {@code io.opentelemetry.sdk.autoconfigure.InternalTelemetryConfiguration}.
* Any changes should be reflected there as well.
*/
final class InternalTelemetryConfiguration {

static InternalTelemetryVersion getVersion(ConfigProperties config) {
Copy link
Member

Choose a reason for hiding this comment

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

Hey I was thinking about internal telemetry and defaults more. Right now, we have SDK components which have different versions of internal telemetry according to their programmatic config API. For example, SdkTracerProvider / SdkLoggerProvider / SimpleSpanProcessor / SimpleLogRecordProcessor did not emit any telemetry prior to the new semantic conventions, and so they default to the latest. BatchSpanProcessor, BatchLogRecordProcessor, Otlp{Signal}{Protocol}Exporter all emit legacy by default.

That means that if otel.experimental.sdk.telemetry.version is omitted, or if otel.experimental.sdk.telemetry.version=legacy, the SDK ends up emitting split brain telemetry.

I think we need to address that here in and in #8045. My proposal:

  • Both system prop / env var config and declarative config should take measures to prevent ever emitting split brain internal telemetry
  • System prop / env var config defaults to legacy if otel.experimental.sdk.telemetry.version is unspecified.
  • Declarative config defaults to no internal telemetry if .instrumentation/development.java.otel_sdk.internal_telemetry_version is unspecified
  • Once the semconv for internal telemetry is stable, declarative config updates the default to the stable version
  • If the internal telemetry version resolves to legacy, internal telemetry is only emitted from components that emit legacy. I.e. internal telemetry is disabled for BatchSpanProcessor, BatchLogRecordProcessor, Otlp{Signal}{Protocol}Exporter.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Metric names are just names, I don't know if there is any actual negative user impact from having inconsistent naming conventions in legacy mode, most commonly they wouldn't notice the new metrics, or appreciate them existing vs not (and maybe it gives a carrot for users to update to latest? ;) ). Agree that it feels a bit weird but not sure it's better to hide the new metrics to avoid the split brain. Should be simple to implement if we'd like that though.

Declarative config defaults to no internal telemetry

To confirm, in the other PR we discussed it could be confusing if the default is different for the two config mechanisms but looks like we'd go for that. Does it mean we need to add InternalTelemetryVersion.DISABLED?

Copy link
Member

Choose a reason for hiding this comment

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

and maybe it gives a carrot for users to update to latest? ;)

See, I was thinking that omitting them from legacy would provide a carrot to update to latest 😂

Does it mean we need to add InternalTelemetryVersion.DISABLED?

I was imagining implementing this by calling setMeterProvider with a noop, to avoid adding InternalTelemetryVersion.DISABLED and having two ways to accomplish the same thing.

To confirm, in the other PR we discussed it could be confusing if the default is different for the two config mechanisms but looks like we'd go for that.

Yes and I agree that its confusing. The crux for me right now is whether or not we are allowed to migrate declarative config to change the default in the future when semconv stabilizes. I know you made the argument that its reasonable to do so with sufficient lead time and easy config knobs, but right now the precedent for opentelemetry-java and for the broader opentelemetry project is that such a change is breaking and only allowed in major versions. I think that declarative config is likely to be the dominant config mechanism in the long term, and so the top priority for me is making sure that it doesn't carry around the legacy internal telemetry baggage indefinitely. Can accomplish this by:

  1. Relaxing the restriction that changing the telemetry schema is breaking and only allowed in major version.
  2. Accepting inconsistent defaults between system props / env vars and declarative config, and having declarative config default to disabled for the time being.

Option 2 is a two way door. With option 1, the otel-java SIG needs to convince itself that this type of change is allowed, and we need to hope that the broader otel community doesn't come out with very explicit guidance to the contrary.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See, I was thinking that omitting them from legacy would provide a carrot to update to latest

You're right, that's a much better carrot - reworked so the autoconfiguration knob now does not enable new metrics (by not setting a MeterProvider) when set to legacy, and made the default explicitly legacy instead of null.

String version = config.getString("otel.experimental.sdk.telemetry.version");
if (version == null) {
return InternalTelemetryVersion.LEGACY;
}

switch (version.toLowerCase(Locale.ROOT)) {
case "legacy":
return InternalTelemetryVersion.LEGACY;
case "latest":
return InternalTelemetryVersion.LATEST;
default:
throw new ConfigurationException("Invalid sdk telemetry version: " + version);
}
}

private InternalTelemetryConfiguration() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import io.opentelemetry.exporter.internal.ExporterBuilderUtil;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.common.InternalTelemetryVersion;
import io.opentelemetry.sdk.common.export.MemoryMode;
import io.opentelemetry.sdk.common.export.RetryPolicy;
import java.io.File;
Expand Down Expand Up @@ -62,7 +63,8 @@ public static void configureOtlpExporterBuilder(
Consumer<byte[]> setTrustedCertificates,
BiConsumer<byte[], byte[]> setClientTls,
Consumer<RetryPolicy> setRetryPolicy,
Consumer<MemoryMode> setMemoryMode) {
Consumer<MemoryMode> setMemoryMode,
Consumer<InternalTelemetryVersion> setInternalTelemetryVersion) {
setComponentLoader.accept(config.getComponentLoader());

String protocol = getOtlpProtocol(dataType, config);
Expand Down Expand Up @@ -107,6 +109,9 @@ public static void configureOtlpExporterBuilder(
setTimeout.accept(timeout);
}

InternalTelemetryVersion telemetryVersion = InternalTelemetryConfiguration.getVersion(config);
setInternalTelemetryVersion.accept(telemetryVersion);

String certificatePath =
config.getString(
determinePropertyByType(config, "otel.exporter.otlp", dataType, "certificate"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ public LogRecordExporter createExporter(ConfigProperties config) {
builder::setTrustedCertificates,
builder::setClientTls,
builder::setRetryPolicy,
builder::setMemoryMode);
builder::setMemoryMode,
builder::setInternalTelemetryVersion);
builder.setMeterProvider(meterProviderRef::get);

return builder.build();
Expand All @@ -71,7 +72,8 @@ public LogRecordExporter createExporter(ConfigProperties config) {
builder::setTrustedCertificates,
builder::setClientTls,
builder::setRetryPolicy,
builder::setMemoryMode);
builder::setMemoryMode,
builder::setInternalTelemetryVersion);
builder.setMeterProvider(meterProviderRef::get);

return builder.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ public MetricExporter createExporter(ConfigProperties config) {
builder::setTrustedCertificates,
builder::setClientTls,
builder::setRetryPolicy,
builder::setMemoryMode);
builder::setMemoryMode,
builder::setInternalTelemetryVersion);
ExporterBuilderUtil.configureOtlpAggregationTemporality(
config, builder::setAggregationTemporalitySelector);
ExporterBuilderUtil.configureOtlpHistogramDefaultAggregation(
Expand All @@ -76,7 +77,8 @@ public MetricExporter createExporter(ConfigProperties config) {
builder::setTrustedCertificates,
builder::setClientTls,
builder::setRetryPolicy,
builder::setMemoryMode);
builder::setMemoryMode,
builder::setInternalTelemetryVersion);
ExporterBuilderUtil.configureOtlpAggregationTemporality(
config, builder::setAggregationTemporalitySelector);
ExporterBuilderUtil.configureOtlpHistogramDefaultAggregation(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ public SpanExporter createExporter(ConfigProperties config) {
builder::setTrustedCertificates,
builder::setClientTls,
builder::setRetryPolicy,
builder::setMemoryMode);
builder::setMemoryMode,
builder::setInternalTelemetryVersion);
builder.setMeterProvider(meterProviderRef::get);

return builder.build();
Expand All @@ -70,7 +71,8 @@ public SpanExporter createExporter(ConfigProperties config) {
builder::setTrustedCertificates,
builder::setClientTls,
builder::setRetryPolicy,
builder::setMemoryMode);
builder::setMemoryMode,
builder::setInternalTelemetryVersion);
builder.setMeterProvider(meterProviderRef::get);

return builder.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ private static String configureEndpoint(String dataType, Map<String, String> pro
value -> {},
(value1, value2) -> {},
value -> {},
value -> {},
value -> {});

return endpoint.get();
Expand Down
1 change: 1 addition & 0 deletions sdk-extensions/autoconfigure/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ testing {
environment("OTEL_EXPORTER_OTLP_TIMEOUT", "5000")
environment("OTEL_TEST_CONFIGURED", "true")
environment("OTEL_TEST_WRAPPED", "1")
environment("OTEL_EXPERIMENTAL_SDK_TELEMETRY_VERSION", "latest")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.sdk.autoconfigure;

import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.common.InternalTelemetryVersion;
import java.util.Locale;

/**
* Reads the desired SDK internal telemetry version from {@link ConfigProperties}.
*
* <p>This is the same as {@code
* io.opentelemetry.exporter.otlp.internal.InternalTelemetryConfiguration}. Any changes should be
* reflected there as well.
*/
final class InternalTelemetryConfiguration {
Copy link
Member

Choose a reason for hiding this comment

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

Too bad we need two copies of this code. Maybe each can have a note in the javadoc referencing the other to increase the chance of keeping changes in sync?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah added the references


static InternalTelemetryVersion getVersion(ConfigProperties config) {
String version = config.getString("otel.experimental.sdk.telemetry.version");
if (version == null) {
return InternalTelemetryVersion.LEGACY;
}

switch (version.toLowerCase(Locale.ROOT)) {
case "legacy":
return InternalTelemetryVersion.LEGACY;
case "latest":
return InternalTelemetryVersion.LATEST;
default:
throw new ConfigurationException("Invalid sdk telemetry version: " + version);
}
}

private InternalTelemetryConfiguration() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.common.InternalTelemetryVersion;
import io.opentelemetry.sdk.logs.LogLimits;
import io.opentelemetry.sdk.logs.LogLimitsBuilder;
import io.opentelemetry.sdk.logs.LogRecordProcessor;
Expand All @@ -18,6 +19,7 @@
import io.opentelemetry.sdk.logs.export.BatchLogRecordProcessorBuilder;
import io.opentelemetry.sdk.logs.export.LogRecordExporter;
import io.opentelemetry.sdk.logs.export.SimpleLogRecordProcessor;
import io.opentelemetry.sdk.logs.export.SimpleLogRecordProcessorBuilder;
import java.io.Closeable;
import java.time.Duration;
import java.util.ArrayList;
Expand All @@ -44,13 +46,17 @@ static void configureLoggerProvider(
List<Closeable> closeables) {

loggerProviderBuilder.setLogLimits(() -> configureLogLimits(config));
loggerProviderBuilder.setMeterProvider(() -> meterProvider);
InternalTelemetryVersion telemetryVersion = InternalTelemetryConfiguration.getVersion(config);
if (telemetryVersion != InternalTelemetryVersion.LEGACY) {
loggerProviderBuilder.setMeterProvider(() -> meterProvider);
}

Map<String, LogRecordExporter> exportersByName =
configureLogRecordExporters(config, spiHelper, logRecordExporterCustomizer, closeables);

List<LogRecordProcessor> processors =
configureLogRecordProcessors(config, exportersByName, meterProvider, closeables);
configureLogRecordProcessors(
config, exportersByName, telemetryVersion, meterProvider, closeables);
for (LogRecordProcessor processor : processors) {
LogRecordProcessor wrapped = logRecordProcessorCustomizer.apply(processor, config);
if (wrapped != processor) {
Expand All @@ -64,6 +70,7 @@ static void configureLoggerProvider(
static List<LogRecordProcessor> configureLogRecordProcessors(
ConfigProperties config,
Map<String, LogRecordExporter> exportersByName,
InternalTelemetryVersion telemetryVersion,
MeterProvider meterProvider,
List<Closeable> closeables) {
Map<String, LogRecordExporter> exportersByNameCopy = new HashMap<>(exportersByName);
Expand All @@ -72,10 +79,12 @@ static List<LogRecordProcessor> configureLogRecordProcessors(
for (String simpleProcessorExporterName : simpleProcessorExporterNames) {
LogRecordExporter exporter = exportersByNameCopy.remove(simpleProcessorExporterName);
if (exporter != null) {
LogRecordProcessor logRecordProcessor =
SimpleLogRecordProcessor.builder(exporter)
.setMeterProvider(() -> meterProvider)
.build();
SimpleLogRecordProcessorBuilder logRecordProcessorBuilder =
SimpleLogRecordProcessor.builder(exporter);
if (telemetryVersion != InternalTelemetryVersion.LEGACY) {
logRecordProcessorBuilder.setMeterProvider(() -> meterProvider);
}
LogRecordProcessor logRecordProcessor = logRecordProcessorBuilder.build();
closeables.add(logRecordProcessor);
logRecordProcessors.add(logRecordProcessor);
}
Expand All @@ -85,7 +94,8 @@ static List<LogRecordProcessor> configureLogRecordProcessors(
LogRecordExporter compositeLogRecordExporter =
LogRecordExporter.composite(exportersByNameCopy.values());
LogRecordProcessor logRecordProcessor =
configureBatchLogRecordProcessor(config, compositeLogRecordExporter, meterProvider);
configureBatchLogRecordProcessor(
config, compositeLogRecordExporter, telemetryVersion, meterProvider);
closeables.add(logRecordProcessor);
logRecordProcessors.add(logRecordProcessor);
}
Expand All @@ -95,7 +105,10 @@ static List<LogRecordProcessor> configureLogRecordProcessors(

// VisibleForTesting
static BatchLogRecordProcessor configureBatchLogRecordProcessor(
ConfigProperties config, LogRecordExporter exporter, MeterProvider meterProvider) {
ConfigProperties config,
LogRecordExporter exporter,
InternalTelemetryVersion telemetryVersion,
MeterProvider meterProvider) {
BatchLogRecordProcessorBuilder builder =
BatchLogRecordProcessor.builder(exporter).setMeterProvider(meterProvider);

Expand All @@ -119,6 +132,8 @@ static BatchLogRecordProcessor configureBatchLogRecordProcessor(
builder.setExporterTimeout(timeout);
}

builder.setInternalTelemetryVersion(telemetryVersion);

return builder.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSamplerProvider;
import io.opentelemetry.sdk.common.InternalTelemetryVersion;
import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder;
import io.opentelemetry.sdk.trace.SpanLimits;
import io.opentelemetry.sdk.trace.SpanLimitsBuilder;
import io.opentelemetry.sdk.trace.SpanProcessor;
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
import io.opentelemetry.sdk.trace.export.BatchSpanProcessorBuilder;
import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor;
import io.opentelemetry.sdk.trace.export.SimpleSpanProcessorBuilder;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import io.opentelemetry.sdk.trace.samplers.Sampler;
import java.io.Closeable;
Expand Down Expand Up @@ -49,7 +51,10 @@ static void configureTracerProvider(
List<Closeable> closeables) {

tracerProviderBuilder.setSpanLimits(configureSpanLimits(config));
tracerProviderBuilder.setMeterProvider(() -> meterProvider);
InternalTelemetryVersion telemetryVersion = InternalTelemetryConfiguration.getVersion(config);
if (telemetryVersion != InternalTelemetryVersion.LEGACY) {
tracerProviderBuilder.setMeterProvider(() -> meterProvider);
}

String sampler = config.getString("otel.traces.sampler", PARENTBASED_ALWAYS_ON);
tracerProviderBuilder.setSampler(
Expand All @@ -60,7 +65,8 @@ static void configureTracerProvider(
config, spiHelper, spanExporterCustomizer, closeables);

List<SpanProcessor> processors =
configureSpanProcessors(config, exportersByName, meterProvider, closeables);
configureSpanProcessors(
config, exportersByName, telemetryVersion, meterProvider, closeables);
for (SpanProcessor processor : processors) {
SpanProcessor wrapped = spanProcessorCustomizer.apply(processor, config);
if (wrapped != processor) {
Expand All @@ -73,6 +79,7 @@ static void configureTracerProvider(
static List<SpanProcessor> configureSpanProcessors(
ConfigProperties config,
Map<String, SpanExporter> exportersByName,
InternalTelemetryVersion telemetryVersion,
MeterProvider meterProvider,
List<Closeable> closeables) {
Map<String, SpanExporter> exportersByNameCopy = new HashMap<>(exportersByName);
Expand All @@ -81,8 +88,11 @@ static List<SpanProcessor> configureSpanProcessors(
for (String simpleProcessorExporterNames : simpleProcessorExporterNames) {
SpanExporter exporter = exportersByNameCopy.remove(simpleProcessorExporterNames);
if (exporter != null) {
SpanProcessor spanProcessor =
SimpleSpanProcessor.builder(exporter).setMeterProvider(() -> meterProvider).build();
SimpleSpanProcessorBuilder spanProcessorBuilder = SimpleSpanProcessor.builder(exporter);
if (telemetryVersion != InternalTelemetryVersion.LEGACY) {
spanProcessorBuilder.setMeterProvider(() -> meterProvider);
}
SpanProcessor spanProcessor = spanProcessorBuilder.build();
closeables.add(spanProcessor);
spanProcessors.add(spanProcessor);
}
Expand All @@ -91,7 +101,8 @@ static List<SpanProcessor> configureSpanProcessors(
if (!exportersByNameCopy.isEmpty()) {
SpanExporter compositeSpanExporter = SpanExporter.composite(exportersByNameCopy.values());
SpanProcessor spanProcessor =
configureBatchSpanProcessor(config, compositeSpanExporter, meterProvider);
configureBatchSpanProcessor(
config, compositeSpanExporter, telemetryVersion, meterProvider);
closeables.add(spanProcessor);
spanProcessors.add(spanProcessor);
}
Expand All @@ -101,7 +112,10 @@ static List<SpanProcessor> configureSpanProcessors(

// VisibleForTesting
static BatchSpanProcessor configureBatchSpanProcessor(
ConfigProperties config, SpanExporter exporter, MeterProvider meterProvider) {
ConfigProperties config,
SpanExporter exporter,
InternalTelemetryVersion telemetryVersion,
MeterProvider meterProvider) {
BatchSpanProcessorBuilder builder =
BatchSpanProcessor.builder(exporter).setMeterProvider(() -> meterProvider);

Expand All @@ -125,6 +139,8 @@ static BatchSpanProcessor configureBatchSpanProcessor(
builder.setExporterTimeout(timeout);
}

builder.setInternalTelemetryVersion(telemetryVersion);

return builder.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.common.InternalTelemetryVersion;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder;
import io.opentelemetry.sdk.trace.SpanLimits;
Expand Down Expand Up @@ -100,7 +101,7 @@ void configureTracerProvider() {
void configureBatchSpanProcessor_empty() {
try (BatchSpanProcessor processor =
TracerProviderConfiguration.configureBatchSpanProcessor(
EMPTY, mockSpanExporter, MeterProvider.noop())) {
EMPTY, mockSpanExporter, InternalTelemetryVersion.LEGACY, MeterProvider.noop())) {
assertThat(processor)
.extracting("worker")
.satisfies(
Expand Down Expand Up @@ -133,6 +134,7 @@ void configureBatchSpanProcessor_configured() {
TracerProviderConfiguration.configureBatchSpanProcessor(
DefaultConfigProperties.createFromMap(properties),
mockSpanExporter,
InternalTelemetryVersion.LEGACY,
MeterProvider.noop())) {
assertThat(processor)
.extracting("worker")
Expand Down
Loading
Loading