From 9e466863052d17fc443d767a1ac33b6a5f40992b Mon Sep 17 00:00:00 2001
From: Jack Berg <34418638+jack-berg@users.noreply.github.com>
Date: Mon, 18 May 2026 13:01:51 -0500
Subject: [PATCH 1/3] Copy zipkin shared internal code refs
---
.../all/NoSharedInternalCodeTest.java | 1 -
.../InstrumentationUtil.java | 10 +-
.../api/internal/InstrumentationUtilTest.java | 1 +
.../current_vs_latest/opentelemetry-api.txt | 5 +
.../internal/InstrumentationUtil.java | 8 +-
.../okhttp/internal/OkHttpGrpcSender.java | 2 +-
.../okhttp/internal/OkHttpHttpSender.java | 2 +-
.../AbstractOkHttpSuppressionTest.java | 2 +-
exporters/zipkin/build.gradle.kts | 1 -
.../exporter/zipkin/ZipkinSpanExporter.java | 10 +-
.../zipkin/ZipkinSpanExporterBuilder.java | 12 +-
.../exporter/zipkin/internal/ComponentId.java | 71 +++++++
.../internal/ExporterInstrumentation.java | 144 +++++++++++++
.../zipkin/internal/ExporterMetrics.java | 61 ++++++
.../internal/LegacyExporterMetrics.java | 199 ++++++++++++++++++
.../zipkin/internal/NoopExporterMetrics.java | 29 +++
.../exporter/zipkin/internal/RateLimiter.java | 68 ++++++
.../zipkin/internal/SemConvAttributes.java | 44 ++++
.../internal/SemConvExporterMetrics.java | 187 ++++++++++++++++
.../exporter/zipkin/internal/Signal.java | 41 ++++
.../zipkin/internal/StandardComponentId.java | 65 ++++++
.../zipkin/internal/ThrottlingLogger.java | 129 ++++++++++++
.../zipkin/ZipkinSpanExporterTest.java | 2 +-
23 files changed, 1071 insertions(+), 23 deletions(-)
rename api/all/src/main/java/io/opentelemetry/api/{internal => impl}/InstrumentationUtil.java (74%)
create mode 100644 exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ComponentId.java
create mode 100644 exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ExporterInstrumentation.java
create mode 100644 exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ExporterMetrics.java
create mode 100644 exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/LegacyExporterMetrics.java
create mode 100644 exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/NoopExporterMetrics.java
create mode 100644 exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/RateLimiter.java
create mode 100644 exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/SemConvAttributes.java
create mode 100644 exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/SemConvExporterMetrics.java
create mode 100644 exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/Signal.java
create mode 100644 exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/StandardComponentId.java
create mode 100644 exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ThrottlingLogger.java
diff --git a/all/src/test/java/io/opentelemetry/all/NoSharedInternalCodeTest.java b/all/src/test/java/io/opentelemetry/all/NoSharedInternalCodeTest.java
index c87fa540198..ec10e2eb172 100644
--- a/all/src/test/java/io/opentelemetry/all/NoSharedInternalCodeTest.java
+++ b/all/src/test/java/io/opentelemetry/all/NoSharedInternalCodeTest.java
@@ -36,7 +36,6 @@ class NoSharedInternalCodeTest {
"opentelemetry-exporter-logging",
"opentelemetry-exporter-logging-otlp",
"opentelemetry-exporter-prometheus",
- "opentelemetry-exporter-zipkin",
"opentelemetry-extension-trace-propagators",
"opentelemetry-opencensus-shim",
"opentelemetry-sdk-common",
diff --git a/api/all/src/main/java/io/opentelemetry/api/internal/InstrumentationUtil.java b/api/all/src/main/java/io/opentelemetry/api/impl/InstrumentationUtil.java
similarity index 74%
rename from api/all/src/main/java/io/opentelemetry/api/internal/InstrumentationUtil.java
rename to api/all/src/main/java/io/opentelemetry/api/impl/InstrumentationUtil.java
index 4f5c1e676bf..381e03fef3b 100644
--- a/api/all/src/main/java/io/opentelemetry/api/internal/InstrumentationUtil.java
+++ b/api/all/src/main/java/io/opentelemetry/api/impl/InstrumentationUtil.java
@@ -3,15 +3,19 @@
* SPDX-License-Identifier: Apache-2.0
*/
-package io.opentelemetry.api.internal;
+package io.opentelemetry.api.impl;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.ContextKey;
import java.util.Objects;
/**
- * This class is internal and is hence not for public use. Its APIs are unstable and can change at
- * any time.
+ * Utility for suppressing instrumentation cycles between exporters which leverage various client
+ * libraries in their implementations and the otel java agent which instruments those client
+ * libraries.
+ *
+ *
This class is not intended for use by application developers. Its API is stable and will not
+ * be changed or removed in a backwards-incompatible manner.
*/
public final class InstrumentationUtil {
private static final ContextKey SUPPRESS_INSTRUMENTATION_KEY =
diff --git a/api/all/src/test/java/io/opentelemetry/api/internal/InstrumentationUtilTest.java b/api/all/src/test/java/io/opentelemetry/api/internal/InstrumentationUtilTest.java
index 066c906d875..fe235644692 100644
--- a/api/all/src/test/java/io/opentelemetry/api/internal/InstrumentationUtilTest.java
+++ b/api/all/src/test/java/io/opentelemetry/api/internal/InstrumentationUtilTest.java
@@ -8,6 +8,7 @@
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import io.opentelemetry.api.impl.InstrumentationUtil;
import io.opentelemetry.context.Context;
import org.junit.jupiter.api.Test;
diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-api.txt b/docs/apidiffs/current_vs_latest/opentelemetry-api.txt
index 3fe1b53a43e..ee4d560df8c 100644
--- a/docs/apidiffs/current_vs_latest/opentelemetry-api.txt
+++ b/docs/apidiffs/current_vs_latest/opentelemetry-api.txt
@@ -1,4 +1,9 @@
Comparing source compatibility of opentelemetry-api-1.63.0-SNAPSHOT.jar against opentelemetry-api-1.62.0.jar
++++ NEW CLASS: PUBLIC(+) FINAL(+) io.opentelemetry.api.impl.InstrumentationUtil (not serializable)
+ +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a.
+ +++ NEW SUPERCLASS: java.lang.Object
+ +++ NEW METHOD: PUBLIC(+) STATIC(+) boolean shouldSuppressInstrumentation(io.opentelemetry.context.Context)
+ +++ NEW METHOD: PUBLIC(+) STATIC(+) void suppressInstrumentation(java.lang.Runnable)
*** MODIFIED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.api.logs.LogRecordBuilder (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.api.logs.LogRecordBuilder setAttribute(java.lang.String, io.opentelemetry.api.common.Value>)
diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/InstrumentationUtil.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/InstrumentationUtil.java
index 9a88fe85060..a40ea3a8664 100644
--- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/InstrumentationUtil.java
+++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/InstrumentationUtil.java
@@ -11,8 +11,8 @@
* This class is internal and is hence not for public use. Its APIs are unstable and can change at
* any time.
*
- * @deprecated use {@link io.opentelemetry.api.internal.InstrumentationUtil} instead. This class
- * should be removed once instrumentation does not refer to it anymore.
+ * @deprecated use {@link io.opentelemetry.api.impl.InstrumentationUtil} instead. This class should
+ * be removed once instrumentation does not refer to it anymore.
*/
@Deprecated
public final class InstrumentationUtil {
@@ -25,7 +25,7 @@ private InstrumentationUtil() {}
* calls.
*/
public static void suppressInstrumentation(Runnable runnable) {
- io.opentelemetry.api.internal.InstrumentationUtil.suppressInstrumentation(runnable);
+ io.opentelemetry.api.impl.InstrumentationUtil.suppressInstrumentation(runnable);
}
/**
@@ -35,6 +35,6 @@ public static void suppressInstrumentation(Runnable runnable) {
* instrumentation.
*/
public static boolean shouldSuppressInstrumentation(Context context) {
- return io.opentelemetry.api.internal.InstrumentationUtil.shouldSuppressInstrumentation(context);
+ return io.opentelemetry.api.impl.InstrumentationUtil.shouldSuppressInstrumentation(context);
}
}
diff --git a/exporters/sender/okhttp/src/main/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpGrpcSender.java b/exporters/sender/okhttp/src/main/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpGrpcSender.java
index 20374358317..fd5ac0f2f03 100644
--- a/exporters/sender/okhttp/src/main/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpGrpcSender.java
+++ b/exporters/sender/okhttp/src/main/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpGrpcSender.java
@@ -23,7 +23,7 @@
package io.opentelemetry.exporter.sender.okhttp.internal;
-import io.opentelemetry.api.internal.InstrumentationUtil;
+import io.opentelemetry.api.impl.InstrumentationUtil;
import io.opentelemetry.exporter.internal.RetryUtil;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.common.export.Compressor;
diff --git a/exporters/sender/okhttp/src/main/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSender.java b/exporters/sender/okhttp/src/main/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSender.java
index ad35eae4a60..f19bba6204c 100644
--- a/exporters/sender/okhttp/src/main/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSender.java
+++ b/exporters/sender/okhttp/src/main/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSender.java
@@ -5,7 +5,7 @@
package io.opentelemetry.exporter.sender.okhttp.internal;
-import io.opentelemetry.api.internal.InstrumentationUtil;
+import io.opentelemetry.api.impl.InstrumentationUtil;
import io.opentelemetry.exporter.internal.RetryUtil;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.common.export.Compressor;
diff --git a/exporters/sender/okhttp/src/test/java/io/opentelemetry/exporter/sender/okhttp/internal/AbstractOkHttpSuppressionTest.java b/exporters/sender/okhttp/src/test/java/io/opentelemetry/exporter/sender/okhttp/internal/AbstractOkHttpSuppressionTest.java
index 4787bb8a610..f143eb67965 100644
--- a/exporters/sender/okhttp/src/test/java/io/opentelemetry/exporter/sender/okhttp/internal/AbstractOkHttpSuppressionTest.java
+++ b/exporters/sender/okhttp/src/test/java/io/opentelemetry/exporter/sender/okhttp/internal/AbstractOkHttpSuppressionTest.java
@@ -7,7 +7,7 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
-import io.opentelemetry.api.internal.InstrumentationUtil;
+import io.opentelemetry.api.impl.InstrumentationUtil;
import io.opentelemetry.context.Context;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
diff --git a/exporters/zipkin/build.gradle.kts b/exporters/zipkin/build.gradle.kts
index bee1da945c4..79171a9b228 100644
--- a/exporters/zipkin/build.gradle.kts
+++ b/exporters/zipkin/build.gradle.kts
@@ -13,7 +13,6 @@ dependencies {
api("io.zipkin.reporter2:zipkin-reporter")
- implementation(project(":exporters:common"))
implementation(project(":sdk-extensions:autoconfigure-spi"))
compileOnly(project(":api:incubator"))
diff --git a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/ZipkinSpanExporter.java b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/ZipkinSpanExporter.java
index 34405dbbf14..d726a5d5655 100644
--- a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/ZipkinSpanExporter.java
+++ b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/ZipkinSpanExporter.java
@@ -5,14 +5,14 @@
package io.opentelemetry.exporter.zipkin;
-import io.opentelemetry.api.internal.InstrumentationUtil;
+import io.opentelemetry.api.impl.InstrumentationUtil;
import io.opentelemetry.api.metrics.MeterProvider;
-import io.opentelemetry.exporter.internal.metrics.ExporterInstrumentation;
+import io.opentelemetry.exporter.zipkin.internal.ComponentId;
+import io.opentelemetry.exporter.zipkin.internal.ExporterInstrumentation;
+import io.opentelemetry.exporter.zipkin.internal.StandardComponentId;
+import io.opentelemetry.exporter.zipkin.internal.ThrottlingLogger;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.common.InternalTelemetryVersion;
-import io.opentelemetry.sdk.common.internal.ComponentId;
-import io.opentelemetry.sdk.common.internal.StandardComponentId;
-import io.opentelemetry.sdk.common.internal.ThrottlingLogger;
import io.opentelemetry.sdk.trace.data.SpanData;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import java.io.IOException;
diff --git a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/ZipkinSpanExporterBuilder.java b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/ZipkinSpanExporterBuilder.java
index 68007dc442a..98dc68bbc66 100644
--- a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/ZipkinSpanExporterBuilder.java
+++ b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/ZipkinSpanExporterBuilder.java
@@ -5,7 +5,6 @@
package io.opentelemetry.exporter.zipkin;
-import static io.opentelemetry.api.internal.Utils.checkArgument;
import static java.util.Objects.requireNonNull;
import io.opentelemetry.api.GlobalOpenTelemetry;
@@ -151,9 +150,10 @@ public ZipkinSpanExporterBuilder setEndpoint(String endpoint) {
*/
public ZipkinSpanExporterBuilder setCompression(String compressionMethod) {
requireNonNull(compressionMethod, "compressionMethod");
- checkArgument(
- compressionMethod.equals("gzip") || compressionMethod.equals("none"),
- "Unsupported compression method. Supported compression methods include: gzip, none.");
+ if (!compressionMethod.equals("gzip") && !compressionMethod.equals("none")) {
+ throw new IllegalArgumentException(
+ "Unsupported compression method. Supported compression methods include: gzip, none.");
+ }
this.compressionEnabled = compressionMethod.equals("gzip");
return this;
}
@@ -166,7 +166,9 @@ public ZipkinSpanExporterBuilder setCompression(String compressionMethod) {
*/
public ZipkinSpanExporterBuilder setReadTimeout(long timeout, TimeUnit unit) {
requireNonNull(unit, "unit");
- checkArgument(timeout >= 0, "timeout must be non-negative");
+ if (timeout < 0) {
+ throw new IllegalArgumentException("timeout must be non-negative");
+ }
long timeoutMillis = timeout == 0 ? Long.MAX_VALUE : unit.toMillis(timeout);
this.readTimeoutMillis = (int) Math.min(timeoutMillis, Integer.MAX_VALUE);
return this;
diff --git a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ComponentId.java b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ComponentId.java
new file mode 100644
index 00000000000..052b5add211
--- /dev/null
+++ b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ComponentId.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.exporter.zipkin.internal;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import javax.annotation.Nullable;
+
+/**
+ * The component id used for SDK health metrics. This corresponds to the otel.component.name and
+ * otel.component.id semconv attributes.
+ *
+ * Copied from {@code io.opentelemetry.sdk.common.internal.ComponentId} to avoid shared internal
+ * code.
+ *
+ *
This class is internal and is hence not for public use. Its APIs are unstable and can change
+ * at any time.
+ */
+public abstract class ComponentId {
+
+ private ComponentId() {}
+
+ public abstract String getTypeName();
+
+ public abstract String getComponentName();
+
+ static class Lazy extends ComponentId {
+
+ private static final Map nextIdCounters = new ConcurrentHashMap<>();
+
+ private final String componentType;
+ @Nullable private volatile String componentName = null;
+
+ Lazy(String componentType) {
+ this.componentType = componentType;
+ }
+
+ @Override
+ public String getTypeName() {
+ return componentType;
+ }
+
+ @Override
+ public String getComponentName() {
+ if (componentName == null) {
+ synchronized (this) {
+ if (componentName == null) {
+ int id =
+ nextIdCounters
+ .computeIfAbsent(componentType, k -> new AtomicInteger(0))
+ .getAndIncrement();
+ componentName = componentType + "/" + id;
+ }
+ }
+ }
+ return componentName;
+ }
+ }
+
+ public static ComponentId generateLazy(String componentType) {
+ return new Lazy(componentType);
+ }
+
+ public static StandardComponentId generateLazy(StandardComponentId.ExporterType exporterType) {
+ return new StandardComponentId(exporterType);
+ }
+}
diff --git a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ExporterInstrumentation.java b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ExporterInstrumentation.java
new file mode 100644
index 00000000000..72fb1f0ac7e
--- /dev/null
+++ b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ExporterInstrumentation.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.exporter.zipkin.internal;
+
+import io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.api.common.AttributesBuilder;
+import io.opentelemetry.api.metrics.MeterProvider;
+import io.opentelemetry.sdk.common.InternalTelemetryVersion;
+import io.opentelemetry.sdk.common.export.GrpcStatusCode;
+import java.net.URI;
+import java.util.function.Supplier;
+import javax.annotation.Nullable;
+
+/**
+ * Copied from {@code io.opentelemetry.exporter.internal.ExporterInstrumentation} to avoid shared
+ * internal code.
+ *
+ * This class is internal and is hence not for public use. Its APIs are unstable and can change
+ * at any time.
+ */
+public class ExporterInstrumentation {
+
+ private final ExporterMetrics implementation;
+
+ public ExporterInstrumentation(
+ InternalTelemetryVersion schema,
+ Supplier meterProviderSupplier,
+ StandardComponentId componentId,
+ URI endpoint) {
+
+ Signal signal = componentId.getStandardType().signal();
+ switch (schema) {
+ case LEGACY:
+ implementation =
+ LegacyExporterMetrics.isSupportedType(componentId.getStandardType())
+ ? new LegacyExporterMetrics(meterProviderSupplier, componentId.getStandardType())
+ : NoopExporterMetrics.INSTANCE;
+ break;
+ case LATEST:
+ implementation =
+ signal == Signal.PROFILE
+ ? NoopExporterMetrics.INSTANCE
+ : new SemConvExporterMetrics(
+ meterProviderSupplier, signal, componentId, extractServerAttributes(endpoint));
+ break;
+ default:
+ throw new IllegalStateException("Unhandled case: " + schema);
+ }
+ }
+
+ // visible for testing
+ static Attributes extractServerAttributes(URI httpEndpoint) {
+ AttributesBuilder builder = Attributes.builder();
+ String host = httpEndpoint.getHost();
+ if (host != null) {
+ builder.put(SemConvAttributes.SERVER_ADDRESS, host);
+ }
+ int port = httpEndpoint.getPort();
+ if (port == -1) {
+ String scheme = httpEndpoint.getScheme();
+ if ("https".equals(scheme)) {
+ port = 443;
+ } else if ("http".equals(scheme)) {
+ port = 80;
+ }
+ }
+ if (port != -1) {
+ builder.put(SemConvAttributes.SERVER_PORT, port);
+ }
+ return builder.build();
+ }
+
+ public Recording startRecordingExport(int itemCount) {
+ return new Recording(implementation.startRecordingExport(itemCount));
+ }
+
+ /**
+ * This class is internal and is hence not for public use. Its APIs are unstable and can change at
+ * any time.
+ */
+ public static class Recording {
+
+ private final ExporterMetrics.Recording delegate;
+ @Nullable private Long httpStatusCode;
+ @Nullable private GrpcStatusCode grpcStatusCode;
+
+ private Recording(ExporterMetrics.Recording delegate) {
+ this.delegate = delegate;
+ }
+
+ public void setHttpStatusCode(long httpStatusCode) {
+ if (grpcStatusCode != null) {
+ throw new IllegalStateException(
+ "gRPC status code already set, can only set either gRPC or HTTP");
+ }
+ this.httpStatusCode = httpStatusCode;
+ }
+
+ public void setGrpcStatusCode(GrpcStatusCode grpcStatusCode) {
+ if (httpStatusCode != null) {
+ throw new IllegalStateException(
+ "HTTP status code already set, can only set either gRPC or HTTP");
+ }
+ this.grpcStatusCode = grpcStatusCode;
+ }
+
+ /** Callback to notify that the export was successful. */
+ public void finishSuccessful() {
+ delegate.finishSuccessful(buildRequestAttributes());
+ }
+
+ /**
+ * Callback to notify that the export has failed with the given {@link Throwable} as failure
+ * cause.
+ *
+ * @param failureCause the cause of the failure
+ */
+ public void finishFailed(Throwable failureCause) {
+ finishFailed(failureCause.getClass().getName());
+ }
+
+ /**
+ * Callback to notify that the export has failed.
+ *
+ * @param errorType a failure reason suitable for the error.type attribute
+ */
+ public void finishFailed(String errorType) {
+ delegate.finishFailed(errorType, buildRequestAttributes());
+ }
+
+ private Attributes buildRequestAttributes() {
+ if (httpStatusCode != null) {
+ return Attributes.of(SemConvAttributes.HTTP_RESPONSE_STATUS_CODE, httpStatusCode);
+ }
+ if (grpcStatusCode != null) {
+ return Attributes.of(SemConvAttributes.RPC_RESPONSE_STATUS_CODE, grpcStatusCode.name());
+ }
+ return Attributes.empty();
+ }
+ }
+}
diff --git a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ExporterMetrics.java b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ExporterMetrics.java
new file mode 100644
index 00000000000..7ef471fe126
--- /dev/null
+++ b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ExporterMetrics.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.exporter.zipkin.internal;
+
+import io.opentelemetry.api.common.Attributes;
+import javax.annotation.Nullable;
+
+/**
+ * Copied from {@code io.opentelemetry.exporter.internal.ExporterMetrics} to avoid shared internal
+ * code.
+ *
+ * This class is internal and is hence not for public use. Its APIs are unstable and can change
+ * at any time.
+ */
+public interface ExporterMetrics {
+
+ Recording startRecordingExport(int itemCount);
+
+ /**
+ * This class is internal and is hence not for public use. Its APIs are unstable and can change at
+ * any time.
+ */
+ abstract class Recording {
+
+ private boolean alreadyEnded = false;
+
+ protected Recording() {}
+
+ public final void finishSuccessful(Attributes requestAttributes) {
+ ensureEndedOnce();
+ doFinish(null, requestAttributes);
+ }
+
+ public final void finishFailed(String errorType, Attributes requestAttributes) {
+ ensureEndedOnce();
+ if (errorType == null || errorType.isEmpty()) {
+ throw new IllegalArgumentException("The export failed but no failure reason was provided");
+ }
+ doFinish(errorType, requestAttributes);
+ }
+
+ private void ensureEndedOnce() {
+ if (alreadyEnded) {
+ throw new IllegalStateException("Recording already ended");
+ }
+ alreadyEnded = true;
+ }
+
+ /**
+ * Invoked when the export has finished, either successfully or failed.
+ *
+ * @param errorType null if the export was successful, otherwise a failure reason suitable for
+ * the error.type attribute
+ * @param requestAttributes additional attributes to add to request metrics
+ */
+ protected abstract void doFinish(@Nullable String errorType, Attributes requestAttributes);
+ }
+}
diff --git a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/LegacyExporterMetrics.java b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/LegacyExporterMetrics.java
new file mode 100644
index 00000000000..501f94d9cb9
--- /dev/null
+++ b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/LegacyExporterMetrics.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.exporter.zipkin.internal;
+
+import static io.opentelemetry.api.common.AttributeKey.booleanKey;
+import static io.opentelemetry.api.common.AttributeKey.stringKey;
+
+import io.opentelemetry.api.common.AttributeKey;
+import io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.api.metrics.LongCounter;
+import io.opentelemetry.api.metrics.Meter;
+import io.opentelemetry.api.metrics.MeterProvider;
+import java.util.function.Supplier;
+import javax.annotation.Nullable;
+
+/**
+ * Implements health metrics for exporters which were defined prior to the standardization in
+ * semantic conventions.
+ *
+ *
Copied from {@code io.opentelemetry.exporter.internal.LegacyExporterMetrics} to avoid shared
+ * internal code.
+ *
+ *
This class is internal and is hence not for public use. Its APIs are unstable and can change
+ * at any time.
+ */
+public class LegacyExporterMetrics implements ExporterMetrics {
+
+ private static final AttributeKey ATTRIBUTE_KEY_TYPE = stringKey("type");
+ private static final AttributeKey ATTRIBUTE_KEY_SUCCESS = booleanKey("success");
+
+ private final Supplier meterProviderSupplier;
+ private final String exporterName;
+ private final String transportName;
+ private final Attributes seenAttrs;
+ private final Attributes successAttrs;
+ private final Attributes failedAttrs;
+
+ /** Access via {@link #seen()}. */
+ @Nullable private volatile LongCounter seen;
+
+ /** Access via {@link #exported()} . */
+ @Nullable private volatile LongCounter exported;
+
+ LegacyExporterMetrics(
+ Supplier meterProviderSupplier,
+ StandardComponentId.ExporterType exporterType) {
+ this.meterProviderSupplier = meterProviderSupplier;
+ this.exporterName = getExporterName(exporterType);
+ this.transportName = getTransportName(exporterType);
+ this.seenAttrs =
+ Attributes.builder().put(ATTRIBUTE_KEY_TYPE, getTypeString(exporterType.signal())).build();
+ this.successAttrs = this.seenAttrs.toBuilder().put(ATTRIBUTE_KEY_SUCCESS, true).build();
+ this.failedAttrs = this.seenAttrs.toBuilder().put(ATTRIBUTE_KEY_SUCCESS, false).build();
+ }
+
+ public static boolean isSupportedType(StandardComponentId.ExporterType exporterType) {
+ switch (exporterType) {
+ case OTLP_GRPC_SPAN_EXPORTER:
+ case OTLP_HTTP_SPAN_EXPORTER:
+ case OTLP_HTTP_JSON_SPAN_EXPORTER:
+ case ZIPKIN_HTTP_SPAN_EXPORTER:
+ case ZIPKIN_HTTP_JSON_SPAN_EXPORTER:
+ case OTLP_GRPC_LOG_EXPORTER:
+ case OTLP_HTTP_LOG_EXPORTER:
+ case OTLP_HTTP_JSON_LOG_EXPORTER:
+ case OTLP_GRPC_METRIC_EXPORTER:
+ case OTLP_HTTP_METRIC_EXPORTER:
+ case OTLP_HTTP_JSON_METRIC_EXPORTER:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private static String getTypeString(Signal signal) {
+ switch (signal) {
+ case SPAN:
+ return "span";
+ case LOG:
+ return "log";
+ case METRIC:
+ return "metric";
+ case PROFILE:
+ throw new IllegalArgumentException("Profiles are not supported");
+ }
+ throw new IllegalArgumentException("Unhandled signal type: " + signal);
+ }
+
+ private static String getExporterName(StandardComponentId.ExporterType exporterType) {
+ switch (exporterType) {
+ case OTLP_GRPC_SPAN_EXPORTER:
+ case OTLP_HTTP_SPAN_EXPORTER:
+ case OTLP_HTTP_JSON_SPAN_EXPORTER:
+ case OTLP_GRPC_LOG_EXPORTER:
+ case OTLP_HTTP_LOG_EXPORTER:
+ case OTLP_HTTP_JSON_LOG_EXPORTER:
+ case OTLP_GRPC_METRIC_EXPORTER:
+ case OTLP_HTTP_METRIC_EXPORTER:
+ case OTLP_HTTP_JSON_METRIC_EXPORTER:
+ return "otlp";
+ case ZIPKIN_HTTP_SPAN_EXPORTER:
+ case ZIPKIN_HTTP_JSON_SPAN_EXPORTER:
+ return "zipkin";
+ case OTLP_GRPC_PROFILES_EXPORTER:
+ throw new IllegalArgumentException("Profiles are not supported");
+ }
+ throw new IllegalArgumentException("Not a supported exporter type: " + exporterType);
+ }
+
+ private static String getTransportName(StandardComponentId.ExporterType exporterType) {
+ switch (exporterType) {
+ case OTLP_GRPC_SPAN_EXPORTER:
+ case OTLP_GRPC_LOG_EXPORTER:
+ case OTLP_GRPC_METRIC_EXPORTER:
+ return "grpc";
+ case OTLP_HTTP_SPAN_EXPORTER:
+ case OTLP_HTTP_LOG_EXPORTER:
+ case OTLP_HTTP_METRIC_EXPORTER:
+ case ZIPKIN_HTTP_SPAN_EXPORTER:
+ return "http";
+ case OTLP_HTTP_JSON_SPAN_EXPORTER:
+ case OTLP_HTTP_JSON_LOG_EXPORTER:
+ case OTLP_HTTP_JSON_METRIC_EXPORTER:
+ case ZIPKIN_HTTP_JSON_SPAN_EXPORTER:
+ return "http-json";
+ case OTLP_GRPC_PROFILES_EXPORTER:
+ throw new IllegalArgumentException("Profiles are not supported");
+ }
+ throw new IllegalArgumentException("Not a supported exporter type: " + exporterType);
+ }
+
+ /** Record number of records seen. */
+ private void addSeen(long value) {
+ seen().add(value, seenAttrs);
+ }
+
+ /** Record number of records which successfully exported. */
+ private void addSuccess(long value) {
+ exported().add(value, successAttrs);
+ }
+
+ /** Record number of records which failed to export. */
+ private void addFailed(long value) {
+ exported().add(value, failedAttrs);
+ }
+
+ private LongCounter seen() {
+ LongCounter seen = this.seen;
+ if (seen == null || SemConvExporterMetrics.isNoop(seen)) {
+ seen = meter().counterBuilder(exporterName + ".exporter.seen").build();
+ this.seen = seen;
+ }
+ return seen;
+ }
+
+ private LongCounter exported() {
+ LongCounter exported = this.exported;
+ if (exported == null || SemConvExporterMetrics.isNoop(exported)) {
+ exported = meter().counterBuilder(exporterName + ".exporter.exported").build();
+ this.exported = exported;
+ }
+ return exported;
+ }
+
+ private Meter meter() {
+ MeterProvider meterProvider = meterProviderSupplier.get();
+ if (meterProvider == null) {
+ meterProvider = MeterProvider.noop();
+ }
+ return meterProvider.get("io.opentelemetry.exporters." + exporterName + "-" + transportName);
+ }
+
+ @Override
+ public ExporterMetrics.Recording startRecordingExport(int itemCount) {
+ return new Recording(itemCount);
+ }
+
+ private class Recording extends ExporterMetrics.Recording {
+
+ private final int itemCount;
+
+ private Recording(int itemCount) {
+ this.itemCount = itemCount;
+ addSeen(itemCount);
+ }
+
+ @Override
+ protected void doFinish(@Nullable String errorType, Attributes requestAttributes) {
+ if (errorType != null) {
+ addFailed(itemCount);
+ } else {
+ addSuccess(itemCount);
+ }
+ }
+ }
+}
diff --git a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/NoopExporterMetrics.java b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/NoopExporterMetrics.java
new file mode 100644
index 00000000000..abea8c9c45a
--- /dev/null
+++ b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/NoopExporterMetrics.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.exporter.zipkin.internal;
+
+import io.opentelemetry.api.common.Attributes;
+import javax.annotation.Nullable;
+
+/**
+ * Copied from {@code io.opentelemetry.exporter.internal.NoopExporterMetrics} to avoid shared
+ * internal code.
+ */
+class NoopExporterMetrics implements ExporterMetrics {
+
+ static final NoopExporterMetrics INSTANCE = new NoopExporterMetrics();
+
+ @Override
+ public Recording startRecordingExport(int itemCount) {
+ return new NoopRecording();
+ }
+
+ private static class NoopRecording extends Recording {
+
+ @Override
+ protected void doFinish(@Nullable String errorType, Attributes requestAttributes) {}
+ }
+}
diff --git a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/RateLimiter.java b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/RateLimiter.java
new file mode 100644
index 00000000000..03230f9ede2
--- /dev/null
+++ b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/RateLimiter.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.exporter.zipkin.internal;
+
+import io.opentelemetry.sdk.common.Clock;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * This class was taken from Jaeger java client.
+ * https://github.com/jaegertracing/jaeger-client-java/blob/master/jaeger-core/src/main/java/io/jaegertracing/internal/samplers/RateLimitingSampler.java
+ *
+ * Variables have been renamed for clarity.
+ *
+ *
Copied from {@code io.opentelemetry.sdk.common.internal.RateLimiter} to avoid shared internal
+ * code.
+ *
+ *
This class is internal and is hence not for public use. Its APIs are unstable and can change
+ * at any time.
+ */
+public class RateLimiter {
+ private final Clock clock;
+ private final double creditsPerNanosecond;
+ private final long maxBalance; // max balance in nano ticks
+ private final AtomicLong currentBalance; // last op nano time less remaining balance
+
+ /**
+ * Create a new RateLimiter with the provided parameters.
+ *
+ * @param creditsPerSecond How many credits to accrue per second.
+ * @param maxBalance The maximum balance that the limiter can hold, which corresponds to the rate
+ * that is being limited to.
+ * @param clock An implementation of the {@link Clock} interface.
+ */
+ public RateLimiter(double creditsPerSecond, double maxBalance, Clock clock) {
+ this.clock = clock;
+ this.creditsPerNanosecond = creditsPerSecond / 1.0e9;
+ this.maxBalance = (long) (maxBalance / creditsPerNanosecond);
+ this.currentBalance = new AtomicLong(clock.nanoTime() - this.maxBalance);
+ }
+
+ /**
+ * Check to see if the provided cost can be spent within the current limits. Will deduct the cost
+ * from the current balance if it can be spent.
+ */
+ public boolean trySpend(double itemCost) {
+ long cost = (long) (itemCost / creditsPerNanosecond);
+ long currentNanos;
+ long currentBalanceNanos;
+ long availableBalanceAfterWithdrawal;
+ do {
+ currentBalanceNanos = this.currentBalance.get();
+ currentNanos = clock.nanoTime();
+ long currentAvailableBalance = currentNanos - currentBalanceNanos;
+ if (currentAvailableBalance > maxBalance) {
+ currentAvailableBalance = maxBalance;
+ }
+ availableBalanceAfterWithdrawal = currentAvailableBalance - cost;
+ if (availableBalanceAfterWithdrawal < 0) {
+ return false;
+ }
+ } while (!this.currentBalance.compareAndSet(
+ currentBalanceNanos, currentNanos - availableBalanceAfterWithdrawal));
+ return true;
+ }
+}
diff --git a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/SemConvAttributes.java b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/SemConvAttributes.java
new file mode 100644
index 00000000000..27ce2b4b058
--- /dev/null
+++ b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/SemConvAttributes.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.exporter.zipkin.internal;
+
+import io.opentelemetry.api.common.AttributeKey;
+
+/**
+ * Provides access to semantic convention attributes used within the SDK implementation. This avoids
+ * having to pull in semantic conventions as a dependency, which would easily collide and conflict
+ * with user-provided dependencies.
+ *
+ *
Copied from {@code io.opentelemetry.sdk.common.internal.SemConvAttributes} to avoid shared
+ * internal code.
+ *
+ *
This class is internal and is hence not for public use. Its APIs are unstable and can change
+ * at any time.
+ */
+public class SemConvAttributes {
+
+ private SemConvAttributes() {}
+
+ public static final AttributeKey OTEL_COMPONENT_TYPE =
+ AttributeKey.stringKey("otel.component.type");
+ public static final AttributeKey OTEL_COMPONENT_NAME =
+ AttributeKey.stringKey("otel.component.name");
+ public static final AttributeKey ERROR_TYPE = AttributeKey.stringKey("error.type");
+
+ public static final AttributeKey SERVER_ADDRESS =
+ AttributeKey.stringKey("server.address");
+ public static final AttributeKey SERVER_PORT = AttributeKey.longKey("server.port");
+
+ public static final AttributeKey RPC_RESPONSE_STATUS_CODE =
+ AttributeKey.stringKey("rpc.response.status_code");
+ public static final AttributeKey HTTP_RESPONSE_STATUS_CODE =
+ AttributeKey.longKey("http.response.status_code");
+
+ public static final AttributeKey OTEL_SPAN_PARENT_ORIGIN =
+ AttributeKey.stringKey("otel.span.parent.origin");
+ public static final AttributeKey OTEL_SPAN_SAMPLING_RESULT =
+ AttributeKey.stringKey("otel.span.sampling_result");
+}
diff --git a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/SemConvExporterMetrics.java b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/SemConvExporterMetrics.java
new file mode 100644
index 00000000000..18254fd21ec
--- /dev/null
+++ b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/SemConvExporterMetrics.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.exporter.zipkin.internal;
+
+import io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.api.common.AttributesBuilder;
+import io.opentelemetry.api.metrics.DoubleHistogram;
+import io.opentelemetry.api.metrics.LongCounter;
+import io.opentelemetry.api.metrics.LongUpDownCounter;
+import io.opentelemetry.api.metrics.Meter;
+import io.opentelemetry.api.metrics.MeterProvider;
+import io.opentelemetry.sdk.common.Clock;
+import java.util.Collections;
+import java.util.function.Supplier;
+import javax.annotation.Nullable;
+
+/**
+ * Copied from {@code io.opentelemetry.exporter.internal.SemConvExporterMetrics} to avoid shared
+ * internal code.
+ *
+ * This class is internal and is hence not for public use. Its APIs are unstable and can change
+ * at any time.
+ */
+public class SemConvExporterMetrics implements ExporterMetrics {
+
+ private static final Clock CLOCK = Clock.getDefault();
+
+ private final Supplier meterProviderSupplier;
+ private final Signal signal;
+ private final ComponentId componentId;
+ private final Attributes additionalAttributes;
+
+ @Nullable private volatile LongUpDownCounter inflight = null;
+ @Nullable private volatile LongCounter exported = null;
+ @Nullable private volatile DoubleHistogram duration = null;
+ @Nullable private volatile Attributes allAttributes = null;
+
+ public SemConvExporterMetrics(
+ Supplier meterProviderSupplier,
+ Signal signal,
+ ComponentId componentId,
+ Attributes additionalAttributes) {
+ this.meterProviderSupplier = meterProviderSupplier;
+ this.componentId = componentId;
+ this.signal = signal;
+ this.additionalAttributes = additionalAttributes;
+ }
+
+ @Override
+ public ExporterMetrics.Recording startRecordingExport(int itemCount) {
+ return new Recording(itemCount);
+ }
+
+ private Meter meter() {
+ MeterProvider meterProvider = meterProviderSupplier.get();
+ if (meterProvider == null) {
+ meterProvider = MeterProvider.noop();
+ }
+ return meterProvider.get("io.opentelemetry.exporters." + componentId.getTypeName());
+ }
+
+ private Attributes allAttributes() {
+ // attributes are initialized lazily to trigger lazy initialization of the componentId
+ Attributes allAttributes = this.allAttributes;
+ if (allAttributes == null) {
+ AttributesBuilder builder = Attributes.builder();
+ builder.put(SemConvAttributes.OTEL_COMPONENT_TYPE, componentId.getTypeName());
+ builder.put(SemConvAttributes.OTEL_COMPONENT_NAME, componentId.getComponentName());
+ builder.putAll(additionalAttributes);
+ allAttributes = builder.build();
+ this.allAttributes = allAttributes;
+ }
+ return allAttributes;
+ }
+
+ private LongUpDownCounter inflight() {
+ LongUpDownCounter inflight = this.inflight;
+ if (inflight == null || isNoop(inflight)) {
+ String unit = signal.getMetricUnit();
+ inflight =
+ meter()
+ .upDownCounterBuilder(signal.getExporterMetricNamespace() + ".inflight")
+ .setUnit("{" + unit + "}")
+ .setDescription(
+ "The number of "
+ + unit
+ + "s which were passed to the exporter, but that have not been exported yet (neither successful, nor failed)")
+ .build();
+ this.inflight = inflight;
+ }
+ return inflight;
+ }
+
+ private LongCounter exported() {
+ LongCounter exported = this.exported;
+ if (exported == null || isNoop(exported)) {
+ String unit = signal.getMetricUnit();
+ exported =
+ meter()
+ .counterBuilder(signal.getExporterMetricNamespace() + ".exported")
+ .setUnit("{" + unit + "}")
+ .setDescription(
+ "The number of "
+ + unit
+ + "s for which the export has finished, either successful or failed")
+ .build();
+ this.exported = exported;
+ }
+ return exported;
+ }
+
+ private DoubleHistogram duration() {
+ DoubleHistogram duration = this.duration;
+ if (duration == null || isNoop(duration)) {
+ duration =
+ meter()
+ .histogramBuilder("otel.sdk.exporter.operation.duration")
+ .setUnit("s")
+ .setDescription("The duration of exporting a batch of telemetry records")
+ .setExplicitBucketBoundariesAdvice(Collections.emptyList())
+ .build();
+ this.duration = duration;
+ }
+ return duration;
+ }
+
+ private void incrementInflight(long count) {
+ inflight().add(count, allAttributes());
+ }
+
+ private void decrementInflight(long count) {
+ inflight().add(-count, allAttributes());
+ }
+
+ private void incrementExported(long count, @Nullable String errorType) {
+ exported().add(count, getAttributesWithPotentialError(errorType, Attributes.empty()));
+ }
+
+ static boolean isNoop(Object instrument) {
+ // This is a poor way to identify a Noop implementation, but the API doesn't provide a better
+ // way. Perhaps we could add a common "Noop" interface to allow for an instanceof check?
+ return instrument.getClass().getSimpleName().startsWith("Noop");
+ }
+
+ private Attributes getAttributesWithPotentialError(
+ @Nullable String errorType, Attributes additionalAttributes) {
+ Attributes attributes = allAttributes();
+ boolean errorPresent = errorType != null && !errorType.isEmpty();
+ if (errorPresent || !additionalAttributes.isEmpty()) {
+ AttributesBuilder builder = attributes.toBuilder();
+ if (errorPresent) {
+ builder.put(SemConvAttributes.ERROR_TYPE, errorType);
+ }
+ attributes = builder.putAll(additionalAttributes).build();
+ }
+ return attributes;
+ }
+
+ private void recordDuration(
+ double seconds, @Nullable String errorType, Attributes requestAttributes) {
+ duration().record(seconds, getAttributesWithPotentialError(errorType, requestAttributes));
+ }
+
+ private class Recording extends ExporterMetrics.Recording {
+
+ private final int itemCount;
+
+ private final long startNanoTime;
+
+ private Recording(int itemCount) {
+ this.itemCount = itemCount;
+ startNanoTime = CLOCK.nanoTime();
+ incrementInflight(itemCount);
+ }
+
+ @Override
+ protected void doFinish(@Nullable String errorType, Attributes requestAttributes) {
+ decrementInflight(itemCount);
+ incrementExported(itemCount, errorType);
+ long durationNanos = CLOCK.nanoTime() - startNanoTime;
+ recordDuration(durationNanos / 1_000_000_000.0, errorType, requestAttributes);
+ }
+ }
+}
diff --git a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/Signal.java b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/Signal.java
new file mode 100644
index 00000000000..0fde7303854
--- /dev/null
+++ b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/Signal.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.exporter.zipkin.internal;
+
+import java.util.Locale;
+
+/**
+ * Copied from {@code io.opentelemetry.sdk.common.internal.Signal} to avoid shared internal code.
+ *
+ * This class is internal and is hence not for public use. Its APIs are unstable and can change
+ * at any time.
+ */
+public enum Signal {
+ SPAN("otel.sdk.exporter.span", "span"),
+ METRIC("otel.sdk.exporter.metric_data_point", "data_point"),
+ LOG("otel.sdk.exporter.log", "log_record"),
+ PROFILE("TBD", "TBD");
+
+ private final String exporterMetricNamespace;
+ private final String metricUnit;
+
+ Signal(String exporterMetricNamespace, String metricUnit) {
+ this.exporterMetricNamespace = exporterMetricNamespace;
+ this.metricUnit = metricUnit;
+ }
+
+ public String logFriendlyName() {
+ return name().toLowerCase(Locale.ENGLISH);
+ }
+
+ public String getExporterMetricNamespace() {
+ return exporterMetricNamespace;
+ }
+
+ public String getMetricUnit() {
+ return metricUnit;
+ }
+}
diff --git a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/StandardComponentId.java b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/StandardComponentId.java
new file mode 100644
index 00000000000..a748e5e6c65
--- /dev/null
+++ b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/StandardComponentId.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.exporter.zipkin.internal;
+
+/**
+ * A {@link ComponentId} where the component type is one of {@link ExporterType}.
+ *
+ *
Copied from {@code io.opentelemetry.sdk.common.internal.StandardComponentId} to avoid shared
+ * internal code.
+ *
+ *
This class is internal and is hence not for public use. Its APIs are unstable and can change
+ * at any time.
+ */
+public class StandardComponentId extends ComponentId.Lazy {
+
+ /**
+ * This class is internal and is hence not for public use. Its APIs are unstable and can change at
+ * any time.
+ */
+ public enum ExporterType {
+ OTLP_GRPC_SPAN_EXPORTER("otlp_grpc_span_exporter", Signal.SPAN),
+ OTLP_HTTP_SPAN_EXPORTER("otlp_http_span_exporter", Signal.SPAN),
+ OTLP_HTTP_JSON_SPAN_EXPORTER("otlp_http_json_span_exporter", Signal.SPAN),
+ OTLP_GRPC_LOG_EXPORTER("otlp_grpc_log_exporter", Signal.LOG),
+ OTLP_HTTP_LOG_EXPORTER("otlp_http_log_exporter", Signal.LOG),
+ OTLP_HTTP_JSON_LOG_EXPORTER("otlp_http_json_log_exporter", Signal.LOG),
+ OTLP_GRPC_METRIC_EXPORTER("otlp_grpc_metric_exporter", Signal.METRIC),
+ OTLP_HTTP_METRIC_EXPORTER("otlp_http_metric_exporter", Signal.METRIC),
+ OTLP_HTTP_JSON_METRIC_EXPORTER("otlp_http_json_metric_exporter", Signal.METRIC),
+ ZIPKIN_HTTP_SPAN_EXPORTER("zipkin_http_span_exporter", Signal.SPAN),
+ /**
+ * Has the same semconv attribute value as ZIPKIN_HTTP_SPAN_EXPORTER, but we still use a
+ * different enum value for now because they produce separate legacy metrics.
+ */
+ ZIPKIN_HTTP_JSON_SPAN_EXPORTER("zipkin_http_span_exporter", Signal.SPAN),
+
+ OTLP_GRPC_PROFILES_EXPORTER("TBD", Signal.PROFILE); // TODO: not yet standardized in semconv
+
+ final String value;
+ private final Signal signal;
+
+ ExporterType(String value, Signal signal) {
+ this.value = value;
+ this.signal = signal;
+ }
+
+ public Signal signal() {
+ return signal;
+ }
+ }
+
+ private final ExporterType standardType;
+
+ StandardComponentId(ExporterType standardType) {
+ super(standardType.value);
+ this.standardType = standardType;
+ }
+
+ public ExporterType getStandardType() {
+ return standardType;
+ }
+}
diff --git a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ThrottlingLogger.java b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ThrottlingLogger.java
new file mode 100644
index 00000000000..0640d1f3399
--- /dev/null
+++ b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ThrottlingLogger.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.exporter.zipkin.internal;
+
+import static java.util.concurrent.TimeUnit.MINUTES;
+
+import io.opentelemetry.sdk.common.Clock;
+import java.util.Locale;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.annotation.Nullable;
+
+/**
+ * Will limit the number of log messages emitted, so as not to spam when problems are happening.
+ *
+ *
Copied from {@code io.opentelemetry.sdk.common.internal.ThrottlingLogger} to avoid shared
+ * internal code.
+ *
+ *
This class is internal and is hence not for public use. Its APIs are unstable and can change
+ * at any time.
+ */
+public class ThrottlingLogger {
+ private static final double DEFAULT_RATE_LIMIT = 5;
+ private static final double DEFAULT_THROTTLED_RATE_LIMIT = 1;
+ private static final TimeUnit DEFAULT_RATE_TIME_UNIT = MINUTES;
+
+ private final Logger delegate;
+ private final AtomicBoolean throttled = new AtomicBoolean(false);
+ private final RateLimiter fastRateLimiter;
+ private final RateLimiter throttledRateLimiter;
+
+ private final double rateLimit;
+ private final double throttledRateLimit;
+ private final TimeUnit rateTimeUnit;
+
+ /** Create a new logger which will enforce a max number of messages per minute. */
+ public ThrottlingLogger(Logger delegate) {
+ this(delegate, Clock.getDefault());
+ }
+
+ /** Alternate way to create logger that allows setting custom intervals and units. * */
+ public ThrottlingLogger(
+ Logger delegate, double rateLimit, double throttledRateLimit, TimeUnit rateTimeUnit) {
+ this(delegate, Clock.getDefault(), rateLimit, throttledRateLimit, rateTimeUnit);
+ }
+
+ // visible for testing
+ ThrottlingLogger(Logger delegate, Clock clock) {
+ this(delegate, clock, DEFAULT_RATE_LIMIT, DEFAULT_THROTTLED_RATE_LIMIT, DEFAULT_RATE_TIME_UNIT);
+ }
+
+ ThrottlingLogger(
+ Logger delegate,
+ Clock clock,
+ double rateLimit,
+ double throttledRateLimit,
+ TimeUnit rateTimeUnit) {
+ this.delegate = delegate;
+ this.rateLimit = rateLimit;
+ this.throttledRateLimit = throttledRateLimit;
+ this.rateTimeUnit = rateTimeUnit;
+ this.fastRateLimiter =
+ new RateLimiter(this.rateLimit / this.rateTimeUnit.toSeconds(1), this.rateLimit, clock);
+ this.throttledRateLimiter =
+ new RateLimiter(
+ this.throttledRateLimit / this.rateTimeUnit.toSeconds(1),
+ this.throttledRateLimit,
+ clock);
+ }
+
+ /** Log a message at the given level. */
+ public void log(Level level, String message) {
+ log(level, message, null);
+ }
+
+ /** Log a message at the given level with a throwable. */
+ public void log(Level level, String message, @Nullable Throwable throwable) {
+ if (!isLoggable(level)) {
+ return;
+ }
+ if (throttled.get()) {
+ if (throttledRateLimiter.trySpend(1.0)) {
+ doLog(level, message, throwable);
+ }
+ return;
+ }
+
+ if (fastRateLimiter.trySpend(1.0)) {
+ doLog(level, message, throwable);
+ return;
+ }
+
+ if (throttled.compareAndSet(false, true)) {
+ // spend the balance in the throttled one, so that it starts at zero.
+ throttledRateLimiter.trySpend(throttledRateLimit);
+ String timeUnitString = rateTimeUnit.toString().toLowerCase(Locale.ROOT);
+ String throttleMessage =
+ String.format(
+ Locale.ROOT,
+ "Too many log messages detected. Will only log %.0f time(s) per %s from now on.",
+ throttledRateLimit,
+ timeUnitString.substring(0, timeUnitString.length() - 1));
+ delegate.log(level, throttleMessage);
+ doLog(level, message, throwable);
+ }
+ }
+
+ private void doLog(Level level, String message, @Nullable Throwable throwable) {
+ if (throwable != null) {
+ delegate.log(level, message, throwable);
+ } else {
+ delegate.log(level, message);
+ }
+ }
+
+ /**
+ * Returns whether the current wrapped logger is set to log at the given level.
+ *
+ * @return true if the logger set to log at the requested level.
+ */
+ public boolean isLoggable(Level level) {
+ return delegate.isLoggable(level);
+ }
+}
diff --git a/exporters/zipkin/src/test/java/io/opentelemetry/exporter/zipkin/ZipkinSpanExporterTest.java b/exporters/zipkin/src/test/java/io/opentelemetry/exporter/zipkin/ZipkinSpanExporterTest.java
index 463b81fc953..2227c8ff76a 100644
--- a/exporters/zipkin/src/test/java/io/opentelemetry/exporter/zipkin/ZipkinSpanExporterTest.java
+++ b/exporters/zipkin/src/test/java/io/opentelemetry/exporter/zipkin/ZipkinSpanExporterTest.java
@@ -15,7 +15,7 @@
import static org.mockito.Mockito.when;
import io.github.netmikey.logunit.api.LogCapturer;
-import io.opentelemetry.api.internal.InstrumentationUtil;
+import io.opentelemetry.api.impl.InstrumentationUtil;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.context.Context;
import io.opentelemetry.internal.testing.slf4j.SuppressLogger;
From 79194d34adcab20f80f7d835445360ac3d5d5041 Mon Sep 17 00:00:00 2001
From: Jack Berg <34418638+jack-berg@users.noreply.github.com>
Date: Mon, 18 May 2026 13:12:11 -0500
Subject: [PATCH 2/3] tree shaking
---
.../exporter/zipkin/internal/ComponentId.java | 4 --
.../internal/ExporterInstrumentation.java | 34 +--------
.../internal/LegacyExporterMetrics.java | 71 ++-----------------
.../zipkin/internal/SemConvAttributes.java | 10 ---
.../exporter/zipkin/internal/Signal.java | 11 +--
.../zipkin/internal/StandardComponentId.java | 13 +---
.../zipkin/internal/ThrottlingLogger.java | 27 ++-----
7 files changed, 13 insertions(+), 157 deletions(-)
diff --git a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ComponentId.java b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ComponentId.java
index 052b5add211..15d735df0cf 100644
--- a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ComponentId.java
+++ b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ComponentId.java
@@ -61,10 +61,6 @@ public String getComponentName() {
}
}
- public static ComponentId generateLazy(String componentType) {
- return new Lazy(componentType);
- }
-
public static StandardComponentId generateLazy(StandardComponentId.ExporterType exporterType) {
return new StandardComponentId(exporterType);
}
diff --git a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ExporterInstrumentation.java b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ExporterInstrumentation.java
index 72fb1f0ac7e..3812c34f153 100644
--- a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ExporterInstrumentation.java
+++ b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ExporterInstrumentation.java
@@ -9,10 +9,8 @@
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.sdk.common.InternalTelemetryVersion;
-import io.opentelemetry.sdk.common.export.GrpcStatusCode;
import java.net.URI;
import java.util.function.Supplier;
-import javax.annotation.Nullable;
/**
* Copied from {@code io.opentelemetry.exporter.internal.ExporterInstrumentation} to avoid shared
@@ -35,16 +33,14 @@ public ExporterInstrumentation(
switch (schema) {
case LEGACY:
implementation =
- LegacyExporterMetrics.isSupportedType(componentId.getStandardType())
+ LegacyExporterMetrics.isSupportedType()
? new LegacyExporterMetrics(meterProviderSupplier, componentId.getStandardType())
: NoopExporterMetrics.INSTANCE;
break;
case LATEST:
implementation =
- signal == Signal.PROFILE
- ? NoopExporterMetrics.INSTANCE
- : new SemConvExporterMetrics(
- meterProviderSupplier, signal, componentId, extractServerAttributes(endpoint));
+ new SemConvExporterMetrics(
+ meterProviderSupplier, signal, componentId, extractServerAttributes(endpoint));
break;
default:
throw new IllegalStateException("Unhandled case: " + schema);
@@ -84,29 +80,11 @@ public Recording startRecordingExport(int itemCount) {
public static class Recording {
private final ExporterMetrics.Recording delegate;
- @Nullable private Long httpStatusCode;
- @Nullable private GrpcStatusCode grpcStatusCode;
private Recording(ExporterMetrics.Recording delegate) {
this.delegate = delegate;
}
- public void setHttpStatusCode(long httpStatusCode) {
- if (grpcStatusCode != null) {
- throw new IllegalStateException(
- "gRPC status code already set, can only set either gRPC or HTTP");
- }
- this.httpStatusCode = httpStatusCode;
- }
-
- public void setGrpcStatusCode(GrpcStatusCode grpcStatusCode) {
- if (httpStatusCode != null) {
- throw new IllegalStateException(
- "HTTP status code already set, can only set either gRPC or HTTP");
- }
- this.grpcStatusCode = grpcStatusCode;
- }
-
/** Callback to notify that the export was successful. */
public void finishSuccessful() {
delegate.finishSuccessful(buildRequestAttributes());
@@ -132,12 +110,6 @@ public void finishFailed(String errorType) {
}
private Attributes buildRequestAttributes() {
- if (httpStatusCode != null) {
- return Attributes.of(SemConvAttributes.HTTP_RESPONSE_STATUS_CODE, httpStatusCode);
- }
- if (grpcStatusCode != null) {
- return Attributes.of(SemConvAttributes.RPC_RESPONSE_STATUS_CODE, grpcStatusCode.name());
- }
return Attributes.empty();
}
}
diff --git a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/LegacyExporterMetrics.java b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/LegacyExporterMetrics.java
index 501f94d9cb9..9eae9e1f843 100644
--- a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/LegacyExporterMetrics.java
+++ b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/LegacyExporterMetrics.java
@@ -48,86 +48,23 @@ public class LegacyExporterMetrics implements ExporterMetrics {
Supplier meterProviderSupplier,
StandardComponentId.ExporterType exporterType) {
this.meterProviderSupplier = meterProviderSupplier;
- this.exporterName = getExporterName(exporterType);
+ this.exporterName = "zipkin";
this.transportName = getTransportName(exporterType);
- this.seenAttrs =
- Attributes.builder().put(ATTRIBUTE_KEY_TYPE, getTypeString(exporterType.signal())).build();
+ this.seenAttrs = Attributes.builder().put(ATTRIBUTE_KEY_TYPE, "span").build();
this.successAttrs = this.seenAttrs.toBuilder().put(ATTRIBUTE_KEY_SUCCESS, true).build();
this.failedAttrs = this.seenAttrs.toBuilder().put(ATTRIBUTE_KEY_SUCCESS, false).build();
}
- public static boolean isSupportedType(StandardComponentId.ExporterType exporterType) {
- switch (exporterType) {
- case OTLP_GRPC_SPAN_EXPORTER:
- case OTLP_HTTP_SPAN_EXPORTER:
- case OTLP_HTTP_JSON_SPAN_EXPORTER:
- case ZIPKIN_HTTP_SPAN_EXPORTER:
- case ZIPKIN_HTTP_JSON_SPAN_EXPORTER:
- case OTLP_GRPC_LOG_EXPORTER:
- case OTLP_HTTP_LOG_EXPORTER:
- case OTLP_HTTP_JSON_LOG_EXPORTER:
- case OTLP_GRPC_METRIC_EXPORTER:
- case OTLP_HTTP_METRIC_EXPORTER:
- case OTLP_HTTP_JSON_METRIC_EXPORTER:
- return true;
- default:
- return false;
- }
- }
-
- private static String getTypeString(Signal signal) {
- switch (signal) {
- case SPAN:
- return "span";
- case LOG:
- return "log";
- case METRIC:
- return "metric";
- case PROFILE:
- throw new IllegalArgumentException("Profiles are not supported");
- }
- throw new IllegalArgumentException("Unhandled signal type: " + signal);
- }
-
- private static String getExporterName(StandardComponentId.ExporterType exporterType) {
- switch (exporterType) {
- case OTLP_GRPC_SPAN_EXPORTER:
- case OTLP_HTTP_SPAN_EXPORTER:
- case OTLP_HTTP_JSON_SPAN_EXPORTER:
- case OTLP_GRPC_LOG_EXPORTER:
- case OTLP_HTTP_LOG_EXPORTER:
- case OTLP_HTTP_JSON_LOG_EXPORTER:
- case OTLP_GRPC_METRIC_EXPORTER:
- case OTLP_HTTP_METRIC_EXPORTER:
- case OTLP_HTTP_JSON_METRIC_EXPORTER:
- return "otlp";
- case ZIPKIN_HTTP_SPAN_EXPORTER:
- case ZIPKIN_HTTP_JSON_SPAN_EXPORTER:
- return "zipkin";
- case OTLP_GRPC_PROFILES_EXPORTER:
- throw new IllegalArgumentException("Profiles are not supported");
- }
- throw new IllegalArgumentException("Not a supported exporter type: " + exporterType);
+ public static boolean isSupportedType() {
+ return true;
}
private static String getTransportName(StandardComponentId.ExporterType exporterType) {
switch (exporterType) {
- case OTLP_GRPC_SPAN_EXPORTER:
- case OTLP_GRPC_LOG_EXPORTER:
- case OTLP_GRPC_METRIC_EXPORTER:
- return "grpc";
- case OTLP_HTTP_SPAN_EXPORTER:
- case OTLP_HTTP_LOG_EXPORTER:
- case OTLP_HTTP_METRIC_EXPORTER:
case ZIPKIN_HTTP_SPAN_EXPORTER:
return "http";
- case OTLP_HTTP_JSON_SPAN_EXPORTER:
- case OTLP_HTTP_JSON_LOG_EXPORTER:
- case OTLP_HTTP_JSON_METRIC_EXPORTER:
case ZIPKIN_HTTP_JSON_SPAN_EXPORTER:
return "http-json";
- case OTLP_GRPC_PROFILES_EXPORTER:
- throw new IllegalArgumentException("Profiles are not supported");
}
throw new IllegalArgumentException("Not a supported exporter type: " + exporterType);
}
diff --git a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/SemConvAttributes.java b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/SemConvAttributes.java
index 27ce2b4b058..14a39c7c0a7 100644
--- a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/SemConvAttributes.java
+++ b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/SemConvAttributes.java
@@ -31,14 +31,4 @@ private SemConvAttributes() {}
public static final AttributeKey SERVER_ADDRESS =
AttributeKey.stringKey("server.address");
public static final AttributeKey SERVER_PORT = AttributeKey.longKey("server.port");
-
- public static final AttributeKey RPC_RESPONSE_STATUS_CODE =
- AttributeKey.stringKey("rpc.response.status_code");
- public static final AttributeKey HTTP_RESPONSE_STATUS_CODE =
- AttributeKey.longKey("http.response.status_code");
-
- public static final AttributeKey OTEL_SPAN_PARENT_ORIGIN =
- AttributeKey.stringKey("otel.span.parent.origin");
- public static final AttributeKey OTEL_SPAN_SAMPLING_RESULT =
- AttributeKey.stringKey("otel.span.sampling_result");
}
diff --git a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/Signal.java b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/Signal.java
index 0fde7303854..30736dead3d 100644
--- a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/Signal.java
+++ b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/Signal.java
@@ -5,8 +5,6 @@
package io.opentelemetry.exporter.zipkin.internal;
-import java.util.Locale;
-
/**
* Copied from {@code io.opentelemetry.sdk.common.internal.Signal} to avoid shared internal code.
*
@@ -14,10 +12,7 @@
* at any time.
*/
public enum Signal {
- SPAN("otel.sdk.exporter.span", "span"),
- METRIC("otel.sdk.exporter.metric_data_point", "data_point"),
- LOG("otel.sdk.exporter.log", "log_record"),
- PROFILE("TBD", "TBD");
+ SPAN("otel.sdk.exporter.span", "span");
private final String exporterMetricNamespace;
private final String metricUnit;
@@ -27,10 +22,6 @@ public enum Signal {
this.metricUnit = metricUnit;
}
- public String logFriendlyName() {
- return name().toLowerCase(Locale.ENGLISH);
- }
-
public String getExporterMetricNamespace() {
return exporterMetricNamespace;
}
diff --git a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/StandardComponentId.java b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/StandardComponentId.java
index a748e5e6c65..608a361e9b7 100644
--- a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/StandardComponentId.java
+++ b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/StandardComponentId.java
@@ -21,23 +21,12 @@ public class StandardComponentId extends ComponentId.Lazy {
* any time.
*/
public enum ExporterType {
- OTLP_GRPC_SPAN_EXPORTER("otlp_grpc_span_exporter", Signal.SPAN),
- OTLP_HTTP_SPAN_EXPORTER("otlp_http_span_exporter", Signal.SPAN),
- OTLP_HTTP_JSON_SPAN_EXPORTER("otlp_http_json_span_exporter", Signal.SPAN),
- OTLP_GRPC_LOG_EXPORTER("otlp_grpc_log_exporter", Signal.LOG),
- OTLP_HTTP_LOG_EXPORTER("otlp_http_log_exporter", Signal.LOG),
- OTLP_HTTP_JSON_LOG_EXPORTER("otlp_http_json_log_exporter", Signal.LOG),
- OTLP_GRPC_METRIC_EXPORTER("otlp_grpc_metric_exporter", Signal.METRIC),
- OTLP_HTTP_METRIC_EXPORTER("otlp_http_metric_exporter", Signal.METRIC),
- OTLP_HTTP_JSON_METRIC_EXPORTER("otlp_http_json_metric_exporter", Signal.METRIC),
ZIPKIN_HTTP_SPAN_EXPORTER("zipkin_http_span_exporter", Signal.SPAN),
/**
* Has the same semconv attribute value as ZIPKIN_HTTP_SPAN_EXPORTER, but we still use a
* different enum value for now because they produce separate legacy metrics.
*/
- ZIPKIN_HTTP_JSON_SPAN_EXPORTER("zipkin_http_span_exporter", Signal.SPAN),
-
- OTLP_GRPC_PROFILES_EXPORTER("TBD", Signal.PROFILE); // TODO: not yet standardized in semconv
+ ZIPKIN_HTTP_JSON_SPAN_EXPORTER("zipkin_http_span_exporter", Signal.SPAN);
final String value;
private final Signal signal;
diff --git a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ThrottlingLogger.java b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ThrottlingLogger.java
index 0640d1f3399..b5d8c808bc5 100644
--- a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ThrottlingLogger.java
+++ b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ThrottlingLogger.java
@@ -40,30 +40,11 @@ public class ThrottlingLogger {
/** Create a new logger which will enforce a max number of messages per minute. */
public ThrottlingLogger(Logger delegate) {
- this(delegate, Clock.getDefault());
- }
-
- /** Alternate way to create logger that allows setting custom intervals and units. * */
- public ThrottlingLogger(
- Logger delegate, double rateLimit, double throttledRateLimit, TimeUnit rateTimeUnit) {
- this(delegate, Clock.getDefault(), rateLimit, throttledRateLimit, rateTimeUnit);
- }
-
- // visible for testing
- ThrottlingLogger(Logger delegate, Clock clock) {
- this(delegate, clock, DEFAULT_RATE_LIMIT, DEFAULT_THROTTLED_RATE_LIMIT, DEFAULT_RATE_TIME_UNIT);
- }
-
- ThrottlingLogger(
- Logger delegate,
- Clock clock,
- double rateLimit,
- double throttledRateLimit,
- TimeUnit rateTimeUnit) {
+ Clock clock = Clock.getDefault();
this.delegate = delegate;
- this.rateLimit = rateLimit;
- this.throttledRateLimit = throttledRateLimit;
- this.rateTimeUnit = rateTimeUnit;
+ this.rateLimit = DEFAULT_RATE_LIMIT;
+ this.throttledRateLimit = DEFAULT_THROTTLED_RATE_LIMIT;
+ this.rateTimeUnit = DEFAULT_RATE_TIME_UNIT;
this.fastRateLimiter =
new RateLimiter(this.rateLimit / this.rateTimeUnit.toSeconds(1), this.rateLimit, clock);
this.throttledRateLimiter =
From 87d95e3507ccccefab02e735f87906fb89441a69 Mon Sep 17 00:00:00 2001
From: Jack Berg <34418638+jack-berg@users.noreply.github.com>
Date: Mon, 18 May 2026 13:17:03 -0500
Subject: [PATCH 3/3] Remove zipkin refs in common exporter metric utils
---
.../exporter/internal/metrics/LegacyExporterMetrics.java | 7 -------
.../exporter/zipkin/internal/ExporterInstrumentation.java | 2 +-
.../sdk/common/internal/StandardComponentId.java | 7 -------
3 files changed, 1 insertion(+), 15 deletions(-)
diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/metrics/LegacyExporterMetrics.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/metrics/LegacyExporterMetrics.java
index a68df15c2c9..235ab16fdaa 100644
--- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/metrics/LegacyExporterMetrics.java
+++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/metrics/LegacyExporterMetrics.java
@@ -60,8 +60,6 @@ public static boolean isSupportedType(StandardComponentId.ExporterType exporterT
case OTLP_GRPC_SPAN_EXPORTER:
case OTLP_HTTP_SPAN_EXPORTER:
case OTLP_HTTP_JSON_SPAN_EXPORTER:
- case ZIPKIN_HTTP_SPAN_EXPORTER:
- case ZIPKIN_HTTP_JSON_SPAN_EXPORTER:
case OTLP_GRPC_LOG_EXPORTER:
case OTLP_HTTP_LOG_EXPORTER:
case OTLP_HTTP_JSON_LOG_EXPORTER:
@@ -100,9 +98,6 @@ private static String getExporterName(StandardComponentId.ExporterType exporterT
case OTLP_HTTP_METRIC_EXPORTER:
case OTLP_HTTP_JSON_METRIC_EXPORTER:
return "otlp";
- case ZIPKIN_HTTP_SPAN_EXPORTER:
- case ZIPKIN_HTTP_JSON_SPAN_EXPORTER:
- return "zipkin";
case OTLP_GRPC_PROFILES_EXPORTER:
throw new IllegalArgumentException("Profiles are not supported");
}
@@ -118,12 +113,10 @@ private static String getTransportName(StandardComponentId.ExporterType exporter
case OTLP_HTTP_SPAN_EXPORTER:
case OTLP_HTTP_LOG_EXPORTER:
case OTLP_HTTP_METRIC_EXPORTER:
- case ZIPKIN_HTTP_SPAN_EXPORTER:
return "http";
case OTLP_HTTP_JSON_SPAN_EXPORTER:
case OTLP_HTTP_JSON_LOG_EXPORTER:
case OTLP_HTTP_JSON_METRIC_EXPORTER:
- case ZIPKIN_HTTP_JSON_SPAN_EXPORTER:
return "http-json";
case OTLP_GRPC_PROFILES_EXPORTER:
throw new IllegalArgumentException("Profiles are not supported");
diff --git a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ExporterInstrumentation.java b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ExporterInstrumentation.java
index 3812c34f153..fc2f2fb8919 100644
--- a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ExporterInstrumentation.java
+++ b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ExporterInstrumentation.java
@@ -109,7 +109,7 @@ public void finishFailed(String errorType) {
delegate.finishFailed(errorType, buildRequestAttributes());
}
- private Attributes buildRequestAttributes() {
+ private static Attributes buildRequestAttributes() {
return Attributes.empty();
}
}
diff --git a/sdk/common/src/main/java/io/opentelemetry/sdk/common/internal/StandardComponentId.java b/sdk/common/src/main/java/io/opentelemetry/sdk/common/internal/StandardComponentId.java
index 17cc94fe36f..c9716bdfc15 100644
--- a/sdk/common/src/main/java/io/opentelemetry/sdk/common/internal/StandardComponentId.java
+++ b/sdk/common/src/main/java/io/opentelemetry/sdk/common/internal/StandardComponentId.java
@@ -27,13 +27,6 @@ public enum ExporterType {
OTLP_GRPC_METRIC_EXPORTER("otlp_grpc_metric_exporter", Signal.METRIC),
OTLP_HTTP_METRIC_EXPORTER("otlp_http_metric_exporter", Signal.METRIC),
OTLP_HTTP_JSON_METRIC_EXPORTER("otlp_http_json_metric_exporter", Signal.METRIC),
- ZIPKIN_HTTP_SPAN_EXPORTER("zipkin_http_span_exporter", Signal.SPAN),
- /**
- * Has the same semconv attribute value as ZIPKIN_HTTP_SPAN_EXPORTER, but we still use a
- * different enum value for now because they produce separate legacy metrics.
- */
- ZIPKIN_HTTP_JSON_SPAN_EXPORTER("zipkin_http_span_exporter", Signal.SPAN),
-
OTLP_GRPC_PROFILES_EXPORTER("TBD", Signal.PROFILE); // TODO: not yet standardized in semconv
final String value;