Improve single responsibility of ZipkinSpanExporter. (#4675)
* improve single responsibility of ZipkinSpanExporter by factoring out OtelToZipkinSpanTransformer. * add javadoc * make utility constructor private * make new class final and jApiCmp * add javadocs * enhance javadoc * make package private * hide logger * spotless * jApiCmp * create transformer with supplier * jApiCmp * rename all Function vars to "transformer" * remove dead code * remove Function interface from OtelToZipkinSpanTransformer * create factory method and rename test util * rename attributesMap -> attributes * rebase after metrics merge * add javadoc * remove static shared ip address * Hey look it's a period. * allow the builder to control the ip address supplier, not the entire transformer. * hide instance behind getter * remove unused * rebase * hide OtelToZipkinSpanTransformer from public usage * jApiCmp * add default to javadocs
This commit is contained in:
parent
6eea0389af
commit
734b13e9c5
|
@ -1,2 +1,4 @@
|
|||
Comparing source compatibility of against
|
||||
No changes.
|
||||
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.exporter.zipkin.ZipkinSpanExporterBuilder (not serializable)
|
||||
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
|
||||
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.exporter.zipkin.ZipkinSpanExporterBuilder setLocalIpAddressSupplier(java.util.function.Supplier)
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.exporter.zipkin;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.util.Enumeration;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
class LocalInetAddressSupplier implements Supplier<InetAddress> {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(LocalInetAddressSupplier.class.getName());
|
||||
private static final LocalInetAddressSupplier INSTANCE =
|
||||
new LocalInetAddressSupplier(findLocalIp());
|
||||
@Nullable private final InetAddress inetAddress;
|
||||
|
||||
private LocalInetAddressSupplier(@Nullable InetAddress inetAddress) {
|
||||
this.inetAddress = inetAddress;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public InetAddress get() {
|
||||
return inetAddress;
|
||||
}
|
||||
|
||||
/** Logic borrowed from brave.internal.Platform.produceLocalEndpoint */
|
||||
@Nullable
|
||||
private static InetAddress findLocalIp() {
|
||||
try {
|
||||
Enumeration<NetworkInterface> nics = NetworkInterface.getNetworkInterfaces();
|
||||
while (nics.hasMoreElements()) {
|
||||
NetworkInterface nic = nics.nextElement();
|
||||
Enumeration<InetAddress> addresses = nic.getInetAddresses();
|
||||
while (addresses.hasMoreElements()) {
|
||||
InetAddress address = addresses.nextElement();
|
||||
if (address.isSiteLocalAddress()) {
|
||||
return address;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// don't crash the caller if there was a problem reading nics.
|
||||
logger.log(Level.FINE, "error reading nics", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static LocalInetAddressSupplier getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.exporter.zipkin;
|
||||
|
||||
import static io.opentelemetry.api.common.AttributeKey.stringKey;
|
||||
import static java.util.concurrent.TimeUnit.NANOSECONDS;
|
||||
|
||||
import io.opentelemetry.api.common.AttributeKey;
|
||||
import io.opentelemetry.api.common.AttributeType;
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.api.trace.StatusCode;
|
||||
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
|
||||
import io.opentelemetry.sdk.resources.Resource;
|
||||
import io.opentelemetry.sdk.trace.data.EventData;
|
||||
import io.opentelemetry.sdk.trace.data.SpanData;
|
||||
import io.opentelemetry.sdk.trace.data.StatusData;
|
||||
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
|
||||
import java.net.InetAddress;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
import javax.annotation.Nullable;
|
||||
import zipkin2.Endpoint;
|
||||
import zipkin2.Span;
|
||||
|
||||
/**
|
||||
* This class is responsible for transforming an OpenTelemetry SpanData instance into an instance of
|
||||
* a Zipkin Span. It is based, in part, on code from
|
||||
* https://github.com/census-instrumentation/opencensus-java/tree/c960b19889de5e4a7b25f90919d28b066590d4f0/exporters/trace/zipkin
|
||||
*/
|
||||
final class OtelToZipkinSpanTransformer {
|
||||
|
||||
static final String KEY_INSTRUMENTATION_SCOPE_NAME = "otel.scope.name";
|
||||
static final String KEY_INSTRUMENTATION_SCOPE_VERSION = "otel.scope.version";
|
||||
static final String KEY_INSTRUMENTATION_LIBRARY_NAME = "otel.library.name";
|
||||
static final String KEY_INSTRUMENTATION_LIBRARY_VERSION = "otel.library.version";
|
||||
static final String OTEL_DROPPED_ATTRIBUTES_COUNT = "otel.dropped_attributes_count";
|
||||
static final String OTEL_DROPPED_EVENTS_COUNT = "otel.dropped_events_count";
|
||||
static final String OTEL_STATUS_CODE = "otel.status_code";
|
||||
static final AttributeKey<String> STATUS_ERROR = stringKey("error");
|
||||
private final Supplier<InetAddress> ipAddressSupplier;
|
||||
|
||||
/**
|
||||
* Creates an instance of an OtelToZipkinSpanTransformer with the given Supplier that can produce
|
||||
* an InetAddress, which may be null. This value from this Supplier will be used when creating the
|
||||
* local zipkin Endpoint for each Span. The default implementation uses
|
||||
* LocalInetAddressSupplier.getInstance().
|
||||
*
|
||||
* @param ipAddressSupplier - A Supplier of an InetAddress.
|
||||
*/
|
||||
static OtelToZipkinSpanTransformer create(Supplier<InetAddress> ipAddressSupplier) {
|
||||
return new OtelToZipkinSpanTransformer(ipAddressSupplier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of an OtelToZipkinSpanTransformer with the given Supplier that can produce
|
||||
* an InetAddress. Supplier may return null. This value from this Supplier will be used when
|
||||
* creating the local zipkin Endpoint for each Span.
|
||||
*
|
||||
* @param ipAddressSupplier - A Supplier of an InetAddress, which can be null
|
||||
*/
|
||||
private OtelToZipkinSpanTransformer(Supplier<InetAddress> ipAddressSupplier) {
|
||||
this.ipAddressSupplier = ipAddressSupplier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of a Zipkin Span from an OpenTelemetry SpanData instance.
|
||||
*
|
||||
* @param spanData an OpenTelemetry spanData instance
|
||||
* @return a new Zipkin Span
|
||||
*/
|
||||
Span generateSpan(SpanData spanData) {
|
||||
Endpoint endpoint = getEndpoint(spanData);
|
||||
|
||||
long startTimestamp = toEpochMicros(spanData.getStartEpochNanos());
|
||||
long endTimestamp = toEpochMicros(spanData.getEndEpochNanos());
|
||||
|
||||
Span.Builder spanBuilder =
|
||||
Span.newBuilder()
|
||||
.traceId(spanData.getTraceId())
|
||||
.id(spanData.getSpanId())
|
||||
.kind(toSpanKind(spanData))
|
||||
.name(spanData.getName())
|
||||
.timestamp(toEpochMicros(spanData.getStartEpochNanos()))
|
||||
.duration(Math.max(1, endTimestamp - startTimestamp))
|
||||
.localEndpoint(endpoint);
|
||||
|
||||
if (spanData.getParentSpanContext().isValid()) {
|
||||
spanBuilder.parentId(spanData.getParentSpanId());
|
||||
}
|
||||
|
||||
Attributes spanAttributes = spanData.getAttributes();
|
||||
spanAttributes.forEach(
|
||||
(key, value) -> spanBuilder.putTag(key.getKey(), valueToString(key, value)));
|
||||
int droppedAttributes = spanData.getTotalAttributeCount() - spanAttributes.size();
|
||||
if (droppedAttributes > 0) {
|
||||
spanBuilder.putTag(OTEL_DROPPED_ATTRIBUTES_COUNT, String.valueOf(droppedAttributes));
|
||||
}
|
||||
|
||||
StatusData status = spanData.getStatus();
|
||||
|
||||
// include status code & error.
|
||||
if (status.getStatusCode() != StatusCode.UNSET) {
|
||||
spanBuilder.putTag(OTEL_STATUS_CODE, status.getStatusCode().toString());
|
||||
|
||||
// add the error tag, if it isn't already in the source span.
|
||||
if (status.getStatusCode() == StatusCode.ERROR && spanAttributes.get(STATUS_ERROR) == null) {
|
||||
spanBuilder.putTag(STATUS_ERROR.getKey(), nullToEmpty(status.getDescription()));
|
||||
}
|
||||
}
|
||||
|
||||
InstrumentationScopeInfo instrumentationScopeInfo = spanData.getInstrumentationScopeInfo();
|
||||
|
||||
if (!instrumentationScopeInfo.getName().isEmpty()) {
|
||||
spanBuilder.putTag(KEY_INSTRUMENTATION_SCOPE_NAME, instrumentationScopeInfo.getName());
|
||||
// Include instrumentation library name for backwards compatibility
|
||||
spanBuilder.putTag(KEY_INSTRUMENTATION_LIBRARY_NAME, instrumentationScopeInfo.getName());
|
||||
}
|
||||
if (instrumentationScopeInfo.getVersion() != null) {
|
||||
spanBuilder.putTag(KEY_INSTRUMENTATION_SCOPE_VERSION, instrumentationScopeInfo.getVersion());
|
||||
// Include instrumentation library name for backwards compatibility
|
||||
spanBuilder.putTag(
|
||||
KEY_INSTRUMENTATION_LIBRARY_VERSION, instrumentationScopeInfo.getVersion());
|
||||
}
|
||||
|
||||
for (EventData annotation : spanData.getEvents()) {
|
||||
spanBuilder.addAnnotation(toEpochMicros(annotation.getEpochNanos()), annotation.getName());
|
||||
}
|
||||
int droppedEvents = spanData.getTotalRecordedEvents() - spanData.getEvents().size();
|
||||
if (droppedEvents > 0) {
|
||||
spanBuilder.putTag(OTEL_DROPPED_EVENTS_COUNT, String.valueOf(droppedEvents));
|
||||
}
|
||||
|
||||
return spanBuilder.build();
|
||||
}
|
||||
|
||||
private static String nullToEmpty(String value) {
|
||||
return value != null ? value : "";
|
||||
}
|
||||
|
||||
private Endpoint getEndpoint(SpanData spanData) {
|
||||
Attributes resourceAttributes = spanData.getResource().getAttributes();
|
||||
|
||||
Endpoint.Builder endpoint = Endpoint.newBuilder();
|
||||
endpoint.ip(ipAddressSupplier.get());
|
||||
|
||||
// use the service.name from the Resource, if it's been set.
|
||||
String serviceNameValue = resourceAttributes.get(ResourceAttributes.SERVICE_NAME);
|
||||
if (serviceNameValue == null) {
|
||||
serviceNameValue = Resource.getDefault().getAttribute(ResourceAttributes.SERVICE_NAME);
|
||||
}
|
||||
// In practice should never be null unless the default Resource spec is changed.
|
||||
if (serviceNameValue != null) {
|
||||
endpoint.serviceName(serviceNameValue);
|
||||
}
|
||||
return endpoint.build();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Span.Kind toSpanKind(SpanData spanData) {
|
||||
switch (spanData.getKind()) {
|
||||
case SERVER:
|
||||
return Span.Kind.SERVER;
|
||||
case CLIENT:
|
||||
return Span.Kind.CLIENT;
|
||||
case PRODUCER:
|
||||
return Span.Kind.PRODUCER;
|
||||
case CONSUMER:
|
||||
return Span.Kind.CONSUMER;
|
||||
case INTERNAL:
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static long toEpochMicros(long epochNanos) {
|
||||
return NANOSECONDS.toMicros(epochNanos);
|
||||
}
|
||||
|
||||
private static String valueToString(AttributeKey<?> key, Object attributeValue) {
|
||||
AttributeType type = key.getType();
|
||||
switch (type) {
|
||||
case STRING:
|
||||
case BOOLEAN:
|
||||
case LONG:
|
||||
case DOUBLE:
|
||||
return String.valueOf(attributeValue);
|
||||
case STRING_ARRAY:
|
||||
case BOOLEAN_ARRAY:
|
||||
case LONG_ARRAY:
|
||||
case DOUBLE_ARRAY:
|
||||
return commaSeparated((List<?>) attributeValue);
|
||||
}
|
||||
throw new IllegalStateException("Unknown attribute type: " + type);
|
||||
}
|
||||
|
||||
private static String commaSeparated(List<?> values) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (Object value : values) {
|
||||
if (builder.length() != 0) {
|
||||
builder.append(',');
|
||||
}
|
||||
builder.append(value);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
|
@ -5,36 +5,19 @@
|
|||
|
||||
package io.opentelemetry.exporter.zipkin;
|
||||
|
||||
import static io.opentelemetry.api.common.AttributeKey.stringKey;
|
||||
import static java.util.concurrent.TimeUnit.NANOSECONDS;
|
||||
|
||||
import io.opentelemetry.api.common.AttributeKey;
|
||||
import io.opentelemetry.api.common.AttributeType;
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.api.metrics.MeterProvider;
|
||||
import io.opentelemetry.api.trace.StatusCode;
|
||||
import io.opentelemetry.exporter.internal.ExporterMetrics;
|
||||
import io.opentelemetry.sdk.common.CompletableResultCode;
|
||||
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
|
||||
import io.opentelemetry.sdk.internal.ThrottlingLogger;
|
||||
import io.opentelemetry.sdk.resources.Resource;
|
||||
import io.opentelemetry.sdk.trace.data.EventData;
|
||||
import io.opentelemetry.sdk.trace.data.SpanData;
|
||||
import io.opentelemetry.sdk.trace.data.StatusData;
|
||||
import io.opentelemetry.sdk.trace.export.SpanExporter;
|
||||
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.annotation.Nullable;
|
||||
import zipkin2.Callback;
|
||||
import zipkin2.Endpoint;
|
||||
import zipkin2.Span;
|
||||
import zipkin2.codec.BytesEncoder;
|
||||
import zipkin2.codec.Encoding;
|
||||
|
@ -51,185 +34,25 @@ public final class ZipkinSpanExporter implements SpanExporter {
|
|||
|
||||
public static final String DEFAULT_ENDPOINT = "http://localhost:9411/api/v2/spans";
|
||||
|
||||
static final String OTEL_DROPPED_ATTRIBUTES_COUNT = "otel.dropped_attributes_count";
|
||||
static final String OTEL_DROPPED_EVENTS_COUNT = "otel.dropped_events_count";
|
||||
static final String OTEL_STATUS_CODE = "otel.status_code";
|
||||
static final AttributeKey<String> STATUS_ERROR = stringKey("error");
|
||||
|
||||
static final String KEY_INSTRUMENTATION_SCOPE_NAME = "otel.scope.name";
|
||||
static final String KEY_INSTRUMENTATION_SCOPE_VERSION = "otel.scope.version";
|
||||
static final String KEY_INSTRUMENTATION_LIBRARY_NAME = "otel.library.name";
|
||||
static final String KEY_INSTRUMENTATION_LIBRARY_VERSION = "otel.library.version";
|
||||
|
||||
private final ThrottlingLogger logger = new ThrottlingLogger(baseLogger);
|
||||
|
||||
private final BytesEncoder<Span> encoder;
|
||||
private final Sender sender;
|
||||
private final ExporterMetrics exporterMetrics;
|
||||
@Nullable private final InetAddress localAddress;
|
||||
|
||||
ZipkinSpanExporter(BytesEncoder<Span> encoder, Sender sender, MeterProvider meterProvider) {
|
||||
private final OtelToZipkinSpanTransformer transformer;
|
||||
|
||||
ZipkinSpanExporter(
|
||||
BytesEncoder<Span> encoder,
|
||||
Sender sender,
|
||||
MeterProvider meterProvider,
|
||||
OtelToZipkinSpanTransformer transformer) {
|
||||
this.encoder = encoder;
|
||||
this.sender = sender;
|
||||
this.exporterMetrics =
|
||||
sender.encoding() == Encoding.JSON
|
||||
? ExporterMetrics.createHttpJson("zipkin", "span", meterProvider)
|
||||
: ExporterMetrics.createHttpProtobuf("zipkin", "span", meterProvider);
|
||||
localAddress = produceLocalIp();
|
||||
}
|
||||
|
||||
/** Logic borrowed from brave.internal.Platform.produceLocalEndpoint */
|
||||
@Nullable
|
||||
static InetAddress produceLocalIp() {
|
||||
try {
|
||||
Enumeration<NetworkInterface> nics = NetworkInterface.getNetworkInterfaces();
|
||||
while (nics.hasMoreElements()) {
|
||||
NetworkInterface nic = nics.nextElement();
|
||||
Enumeration<InetAddress> addresses = nic.getInetAddresses();
|
||||
while (addresses.hasMoreElements()) {
|
||||
InetAddress address = addresses.nextElement();
|
||||
if (address.isSiteLocalAddress()) {
|
||||
return address;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// don't crash the caller if there was a problem reading nics
|
||||
baseLogger.log(Level.FINE, "error reading nics", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// VisibleForTesting
|
||||
Span generateSpan(SpanData spanData) {
|
||||
Endpoint endpoint = getEndpoint(spanData);
|
||||
|
||||
long startTimestamp = toEpochMicros(spanData.getStartEpochNanos());
|
||||
long endTimestamp = toEpochMicros(spanData.getEndEpochNanos());
|
||||
|
||||
Span.Builder spanBuilder =
|
||||
Span.newBuilder()
|
||||
.traceId(spanData.getTraceId())
|
||||
.id(spanData.getSpanId())
|
||||
.kind(toSpanKind(spanData))
|
||||
.name(spanData.getName())
|
||||
.timestamp(toEpochMicros(spanData.getStartEpochNanos()))
|
||||
.duration(Math.max(1, endTimestamp - startTimestamp))
|
||||
.localEndpoint(endpoint);
|
||||
|
||||
if (spanData.getParentSpanContext().isValid()) {
|
||||
spanBuilder.parentId(spanData.getParentSpanId());
|
||||
}
|
||||
|
||||
Attributes spanAttributes = spanData.getAttributes();
|
||||
spanAttributes.forEach(
|
||||
(key, value) -> spanBuilder.putTag(key.getKey(), valueToString(key, value)));
|
||||
int droppedAttributes = spanData.getTotalAttributeCount() - spanAttributes.size();
|
||||
if (droppedAttributes > 0) {
|
||||
spanBuilder.putTag(OTEL_DROPPED_ATTRIBUTES_COUNT, String.valueOf(droppedAttributes));
|
||||
}
|
||||
|
||||
StatusData status = spanData.getStatus();
|
||||
|
||||
// include status code & error
|
||||
if (status.getStatusCode() != StatusCode.UNSET) {
|
||||
spanBuilder.putTag(OTEL_STATUS_CODE, status.getStatusCode().toString());
|
||||
|
||||
// add the error tag, if it isn't already in the source span
|
||||
if (status.getStatusCode() == StatusCode.ERROR && spanAttributes.get(STATUS_ERROR) == null) {
|
||||
spanBuilder.putTag(STATUS_ERROR.getKey(), status.getDescription());
|
||||
}
|
||||
}
|
||||
|
||||
InstrumentationScopeInfo instrumentationScopeInfo = spanData.getInstrumentationScopeInfo();
|
||||
|
||||
if (!instrumentationScopeInfo.getName().isEmpty()) {
|
||||
spanBuilder.putTag(KEY_INSTRUMENTATION_SCOPE_NAME, instrumentationScopeInfo.getName());
|
||||
// include instrumentation library name for backwards compatibility
|
||||
spanBuilder.putTag(KEY_INSTRUMENTATION_LIBRARY_NAME, instrumentationScopeInfo.getName());
|
||||
}
|
||||
if (instrumentationScopeInfo.getVersion() != null) {
|
||||
spanBuilder.putTag(KEY_INSTRUMENTATION_SCOPE_VERSION, instrumentationScopeInfo.getVersion());
|
||||
// include instrumentation library name for backwards compatibility
|
||||
spanBuilder.putTag(
|
||||
KEY_INSTRUMENTATION_LIBRARY_VERSION, instrumentationScopeInfo.getVersion());
|
||||
}
|
||||
|
||||
for (EventData annotation : spanData.getEvents()) {
|
||||
spanBuilder.addAnnotation(toEpochMicros(annotation.getEpochNanos()), annotation.getName());
|
||||
}
|
||||
int droppedEvents = spanData.getTotalRecordedEvents() - spanData.getEvents().size();
|
||||
if (droppedEvents > 0) {
|
||||
spanBuilder.putTag(OTEL_DROPPED_EVENTS_COUNT, String.valueOf(droppedEvents));
|
||||
}
|
||||
|
||||
return spanBuilder.build();
|
||||
}
|
||||
|
||||
private Endpoint getEndpoint(SpanData spanData) {
|
||||
Attributes resourceAttributes = spanData.getResource().getAttributes();
|
||||
|
||||
Endpoint.Builder endpoint = Endpoint.newBuilder().ip(localAddress);
|
||||
|
||||
// use the service.name from the Resource, if it's been set
|
||||
String serviceNameValue = resourceAttributes.get(ResourceAttributes.SERVICE_NAME);
|
||||
if (serviceNameValue == null) {
|
||||
serviceNameValue = Resource.getDefault().getAttribute(ResourceAttributes.SERVICE_NAME);
|
||||
}
|
||||
// in practice should never be null unless the default Resource spec is changed
|
||||
if (serviceNameValue != null) {
|
||||
endpoint.serviceName(serviceNameValue);
|
||||
}
|
||||
return endpoint.build();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Span.Kind toSpanKind(SpanData spanData) {
|
||||
switch (spanData.getKind()) {
|
||||
case SERVER:
|
||||
return Span.Kind.SERVER;
|
||||
case CLIENT:
|
||||
return Span.Kind.CLIENT;
|
||||
case PRODUCER:
|
||||
return Span.Kind.PRODUCER;
|
||||
case CONSUMER:
|
||||
return Span.Kind.CONSUMER;
|
||||
case INTERNAL:
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static long toEpochMicros(long epochNanos) {
|
||||
return NANOSECONDS.toMicros(epochNanos);
|
||||
}
|
||||
|
||||
private static String valueToString(AttributeKey<?> key, Object attributeValue) {
|
||||
AttributeType type = key.getType();
|
||||
switch (type) {
|
||||
case STRING:
|
||||
case BOOLEAN:
|
||||
case LONG:
|
||||
case DOUBLE:
|
||||
return String.valueOf(attributeValue);
|
||||
case STRING_ARRAY:
|
||||
case BOOLEAN_ARRAY:
|
||||
case LONG_ARRAY:
|
||||
case DOUBLE_ARRAY:
|
||||
return commaSeparated((List<?>) attributeValue);
|
||||
}
|
||||
throw new IllegalStateException("Unknown attribute type: " + type);
|
||||
}
|
||||
|
||||
private static String commaSeparated(List<?> values) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (Object value : values) {
|
||||
if (builder.length() != 0) {
|
||||
builder.append(',');
|
||||
}
|
||||
builder.append(value);
|
||||
}
|
||||
return builder.toString();
|
||||
this.transformer = transformer;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -239,7 +62,8 @@ public final class ZipkinSpanExporter implements SpanExporter {
|
|||
|
||||
List<byte[]> encodedSpans = new ArrayList<>(numItems);
|
||||
for (SpanData spanData : spanDataList) {
|
||||
encodedSpans.add(encoder.encode(generateSpan(spanData)));
|
||||
Span zipkinSpan = transformer.generateSpan(spanData);
|
||||
encodedSpans.add(encoder.encode(zipkinSpan));
|
||||
}
|
||||
|
||||
CompletableResultCode result = new CompletableResultCode();
|
||||
|
@ -287,10 +111,4 @@ public final class ZipkinSpanExporter implements SpanExporter {
|
|||
public static ZipkinSpanExporterBuilder builder() {
|
||||
return new ZipkinSpanExporterBuilder();
|
||||
}
|
||||
|
||||
// VisibleForTesting
|
||||
@Nullable
|
||||
InetAddress getLocalAddressForTest() {
|
||||
return localAddress;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,8 +9,10 @@ import static io.opentelemetry.api.internal.Utils.checkArgument;
|
|||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import io.opentelemetry.api.metrics.MeterProvider;
|
||||
import java.net.InetAddress;
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
import javax.annotation.Nullable;
|
||||
import zipkin2.Span;
|
||||
import zipkin2.codec.BytesEncoder;
|
||||
|
@ -21,6 +23,7 @@ import zipkin2.reporter.okhttp3.OkHttpSender;
|
|||
/** Builder class for {@link ZipkinSpanExporter}. */
|
||||
public final class ZipkinSpanExporterBuilder {
|
||||
private BytesEncoder<Span> encoder = SpanBytesEncoder.JSON_V2;
|
||||
private Supplier<InetAddress> localIpAddressSupplier = LocalInetAddressSupplier.getInstance();
|
||||
@Nullable private Sender sender;
|
||||
private String endpoint = ZipkinSpanExporter.DEFAULT_ENDPOINT;
|
||||
private long readTimeoutMillis = TimeUnit.SECONDS.toMillis(10);
|
||||
|
@ -55,6 +58,21 @@ public final class ZipkinSpanExporterBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Supplier of InetAddress. This Supplier will be used by the {@link
|
||||
* OtelToZipkinSpanTransformer} when creating the Zipkin local endpoint. The default
|
||||
* implementation uses a Supplier that returns a single unchanging IP address that is captured at
|
||||
* creation time.
|
||||
*
|
||||
* @param supplier - A supplier that returns an InetAddress that may be null.
|
||||
* @return this
|
||||
*/
|
||||
public ZipkinSpanExporterBuilder setLocalIpAddressSupplier(Supplier<InetAddress> supplier) {
|
||||
requireNonNull(supplier, "encoder");
|
||||
this.localIpAddressSupplier = supplier;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the zipkin endpoint. This will use the endpoint to assign a {@link OkHttpSender} instance
|
||||
* to this builder.
|
||||
|
@ -118,6 +136,8 @@ public final class ZipkinSpanExporterBuilder {
|
|||
sender =
|
||||
OkHttpSender.newBuilder().endpoint(endpoint).readTimeout((int) readTimeoutMillis).build();
|
||||
}
|
||||
return new ZipkinSpanExporter(encoder, sender, meterProvider);
|
||||
OtelToZipkinSpanTransformer transformer =
|
||||
OtelToZipkinSpanTransformer.create(localIpAddressSupplier);
|
||||
return new ZipkinSpanExporter(encoder, sender, meterProvider, transformer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,305 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.exporter.zipkin;
|
||||
|
||||
import static io.opentelemetry.api.common.AttributeKey.booleanArrayKey;
|
||||
import static io.opentelemetry.api.common.AttributeKey.booleanKey;
|
||||
import static io.opentelemetry.api.common.AttributeKey.doubleArrayKey;
|
||||
import static io.opentelemetry.api.common.AttributeKey.doubleKey;
|
||||
import static io.opentelemetry.api.common.AttributeKey.longArrayKey;
|
||||
import static io.opentelemetry.api.common.AttributeKey.longKey;
|
||||
import static io.opentelemetry.api.common.AttributeKey.stringArrayKey;
|
||||
import static io.opentelemetry.api.common.AttributeKey.stringKey;
|
||||
import static io.opentelemetry.exporter.zipkin.ZipkinTestUtil.spanBuilder;
|
||||
import static io.opentelemetry.exporter.zipkin.ZipkinTestUtil.zipkinSpan;
|
||||
import static io.opentelemetry.exporter.zipkin.ZipkinTestUtil.zipkinSpanBuilder;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.api.trace.StatusCode;
|
||||
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
|
||||
import io.opentelemetry.sdk.resources.Resource;
|
||||
import io.opentelemetry.sdk.trace.data.SpanData;
|
||||
import io.opentelemetry.sdk.trace.data.StatusData;
|
||||
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||
import java.net.InetAddress;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import zipkin2.Endpoint;
|
||||
import zipkin2.Span;
|
||||
|
||||
class OtelToZipkinSpanTransformerTest {
|
||||
|
||||
private OtelToZipkinSpanTransformer transformer;
|
||||
private InetAddress localIp;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
localIp = mock(InetAddress.class);
|
||||
transformer = OtelToZipkinSpanTransformer.create(() -> localIp);
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_remoteParent() {
|
||||
SpanData data = spanBuilder().build();
|
||||
|
||||
assertThat(transformer.generateSpan(data))
|
||||
.isEqualTo(
|
||||
zipkinSpanBuilder(Span.Kind.SERVER, localIp)
|
||||
.putTag(OtelToZipkinSpanTransformer.OTEL_STATUS_CODE, "OK")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_subMicroDurations() {
|
||||
SpanData data =
|
||||
spanBuilder()
|
||||
.setStartEpochNanos(1505855794_194009601L)
|
||||
.setEndEpochNanos(1505855794_194009999L)
|
||||
.build();
|
||||
|
||||
Span expected =
|
||||
zipkinSpanBuilder(Span.Kind.SERVER, localIp)
|
||||
.putTag(OtelToZipkinSpanTransformer.OTEL_STATUS_CODE, "OK")
|
||||
.duration(1)
|
||||
.build();
|
||||
assertThat(transformer.generateSpan(data)).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_ServerKind() {
|
||||
SpanData data = spanBuilder().setKind(SpanKind.SERVER).build();
|
||||
|
||||
assertThat(transformer.generateSpan(data))
|
||||
.isEqualTo(
|
||||
zipkinSpanBuilder(Span.Kind.SERVER, localIp)
|
||||
.putTag(OtelToZipkinSpanTransformer.OTEL_STATUS_CODE, "OK")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_ClientKind() {
|
||||
SpanData data = spanBuilder().setKind(SpanKind.CLIENT).build();
|
||||
|
||||
assertThat(transformer.generateSpan(data))
|
||||
.isEqualTo(
|
||||
zipkinSpanBuilder(Span.Kind.CLIENT, localIp)
|
||||
.putTag(OtelToZipkinSpanTransformer.OTEL_STATUS_CODE, "OK")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_InternalKind() {
|
||||
SpanData data = spanBuilder().setKind(SpanKind.INTERNAL).build();
|
||||
|
||||
assertThat(transformer.generateSpan(data))
|
||||
.isEqualTo(
|
||||
zipkinSpanBuilder(null, localIp)
|
||||
.putTag(OtelToZipkinSpanTransformer.OTEL_STATUS_CODE, "OK")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_ConsumeKind() {
|
||||
SpanData data = spanBuilder().setKind(SpanKind.CONSUMER).build();
|
||||
|
||||
assertThat(transformer.generateSpan(data))
|
||||
.isEqualTo(
|
||||
zipkinSpanBuilder(Span.Kind.CONSUMER, localIp)
|
||||
.putTag(OtelToZipkinSpanTransformer.OTEL_STATUS_CODE, "OK")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_ProducerKind() {
|
||||
SpanData data = spanBuilder().setKind(SpanKind.PRODUCER).build();
|
||||
|
||||
assertThat(transformer.generateSpan(data))
|
||||
.isEqualTo(
|
||||
zipkinSpanBuilder(Span.Kind.PRODUCER, localIp)
|
||||
.putTag(OtelToZipkinSpanTransformer.OTEL_STATUS_CODE, "OK")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_ResourceServiceNameMapping() {
|
||||
Resource resource =
|
||||
Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, "super-zipkin-service"));
|
||||
SpanData data = spanBuilder().setResource(resource).build();
|
||||
|
||||
Endpoint expectedEndpoint =
|
||||
Endpoint.newBuilder().serviceName("super-zipkin-service").ip(localIp).build();
|
||||
Span expectedZipkinSpan =
|
||||
zipkinSpan(Span.Kind.SERVER, localIp).toBuilder()
|
||||
.localEndpoint(expectedEndpoint)
|
||||
.putTag(OtelToZipkinSpanTransformer.OTEL_STATUS_CODE, "OK")
|
||||
.build();
|
||||
assertThat(transformer.generateSpan(data)).isEqualTo(expectedZipkinSpan);
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_defaultResourceServiceName() {
|
||||
SpanData data = spanBuilder().setResource(Resource.empty()).build();
|
||||
|
||||
Endpoint expectedEndpoint =
|
||||
Endpoint.newBuilder()
|
||||
.serviceName(Resource.getDefault().getAttribute(ResourceAttributes.SERVICE_NAME))
|
||||
.ip(localIp)
|
||||
.build();
|
||||
Span expectedZipkinSpan =
|
||||
zipkinSpan(Span.Kind.SERVER, localIp).toBuilder()
|
||||
.localEndpoint(expectedEndpoint)
|
||||
.putTag(OtelToZipkinSpanTransformer.OTEL_STATUS_CODE, "OK")
|
||||
.build();
|
||||
assertThat(transformer.generateSpan(data)).isEqualTo(expectedZipkinSpan);
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_WithAttributes() {
|
||||
Attributes attributes =
|
||||
Attributes.builder()
|
||||
.put(stringKey("string"), "string value")
|
||||
.put(booleanKey("boolean"), false)
|
||||
.put(longKey("long"), 9999L)
|
||||
.put(doubleKey("double"), 222.333d)
|
||||
.put(booleanArrayKey("booleanArray"), Arrays.asList(true, false))
|
||||
.put(stringArrayKey("stringArray"), Collections.singletonList("Hello"))
|
||||
.put(doubleArrayKey("doubleArray"), Arrays.asList(32.33d, -98.3d))
|
||||
.put(longArrayKey("longArray"), Arrays.asList(33L, 999L))
|
||||
.build();
|
||||
SpanData data =
|
||||
spanBuilder()
|
||||
.setAttributes(attributes)
|
||||
.setTotalAttributeCount(28)
|
||||
.setTotalRecordedEvents(3)
|
||||
.setKind(SpanKind.CLIENT)
|
||||
.build();
|
||||
|
||||
assertThat(transformer.generateSpan(data))
|
||||
.isEqualTo(
|
||||
zipkinSpan(Span.Kind.CLIENT, localIp).toBuilder()
|
||||
.putTag("string", "string value")
|
||||
.putTag("boolean", "false")
|
||||
.putTag("long", "9999")
|
||||
.putTag("double", "222.333")
|
||||
.putTag("booleanArray", "true,false")
|
||||
.putTag("stringArray", "Hello")
|
||||
.putTag("doubleArray", "32.33,-98.3")
|
||||
.putTag("longArray", "33,999")
|
||||
.putTag(OtelToZipkinSpanTransformer.OTEL_STATUS_CODE, "OK")
|
||||
.putTag(OtelToZipkinSpanTransformer.OTEL_DROPPED_ATTRIBUTES_COUNT, "20")
|
||||
.putTag(OtelToZipkinSpanTransformer.OTEL_DROPPED_EVENTS_COUNT, "1")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_WithInstrumentationLibraryInfo() {
|
||||
SpanData data =
|
||||
spanBuilder()
|
||||
.setInstrumentationScopeInfo(
|
||||
InstrumentationScopeInfo.create("io.opentelemetry.auto", "1.0.0", null))
|
||||
.setKind(SpanKind.CLIENT)
|
||||
.build();
|
||||
|
||||
assertThat(transformer.generateSpan(data))
|
||||
.isEqualTo(
|
||||
zipkinSpan(Span.Kind.CLIENT, localIp).toBuilder()
|
||||
.putTag("otel.scope.name", "io.opentelemetry.auto")
|
||||
.putTag("otel.scope.version", "1.0.0")
|
||||
.putTag("otel.library.name", "io.opentelemetry.auto")
|
||||
.putTag("otel.library.version", "1.0.0")
|
||||
.putTag(OtelToZipkinSpanTransformer.OTEL_STATUS_CODE, "OK")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_AlreadyHasHttpStatusInfo() {
|
||||
Attributes attributes =
|
||||
Attributes.of(
|
||||
SemanticAttributes.HTTP_STATUS_CODE, 404L, stringKey("error"), "A user provided error");
|
||||
SpanData data =
|
||||
spanBuilder()
|
||||
.setAttributes(attributes)
|
||||
.setKind(SpanKind.CLIENT)
|
||||
.setStatus(StatusData.error())
|
||||
.setTotalAttributeCount(2)
|
||||
.build();
|
||||
|
||||
assertThat(transformer.generateSpan(data))
|
||||
.isEqualTo(
|
||||
zipkinSpan(Span.Kind.CLIENT, localIp).toBuilder()
|
||||
.clearTags()
|
||||
.putTag(SemanticAttributes.HTTP_STATUS_CODE.getKey(), "404")
|
||||
.putTag(OtelToZipkinSpanTransformer.OTEL_STATUS_CODE, "ERROR")
|
||||
.putTag("error", "A user provided error")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_WithRpcTimeoutErrorStatus_WithTimeoutErrorDescription() {
|
||||
Attributes attributes = Attributes.of(SemanticAttributes.RPC_SERVICE, "my service name");
|
||||
|
||||
String errorMessage = "timeout";
|
||||
|
||||
SpanData data =
|
||||
spanBuilder()
|
||||
.setStatus(StatusData.create(StatusCode.ERROR, errorMessage))
|
||||
.setAttributes(attributes)
|
||||
.setTotalAttributeCount(1)
|
||||
.build();
|
||||
|
||||
assertThat(transformer.generateSpan(data))
|
||||
.isEqualTo(
|
||||
zipkinSpan(Span.Kind.SERVER, localIp).toBuilder()
|
||||
.putTag(SemanticAttributes.RPC_SERVICE.getKey(), "my service name")
|
||||
.putTag(OtelToZipkinSpanTransformer.OTEL_STATUS_CODE, "ERROR")
|
||||
.putTag(OtelToZipkinSpanTransformer.STATUS_ERROR.getKey(), errorMessage)
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_WithRpcErrorStatus_WithEmptyErrorDescription() {
|
||||
Attributes attributes = Attributes.of(SemanticAttributes.RPC_SERVICE, "my service name");
|
||||
|
||||
SpanData data =
|
||||
spanBuilder()
|
||||
.setStatus(StatusData.create(StatusCode.ERROR, ""))
|
||||
.setAttributes(attributes)
|
||||
.setTotalAttributeCount(1)
|
||||
.build();
|
||||
|
||||
assertThat(transformer.generateSpan(data))
|
||||
.isEqualTo(
|
||||
zipkinSpan(Span.Kind.SERVER, localIp).toBuilder()
|
||||
.putTag(SemanticAttributes.RPC_SERVICE.getKey(), "my service name")
|
||||
.putTag(OtelToZipkinSpanTransformer.OTEL_STATUS_CODE, "ERROR")
|
||||
.putTag(OtelToZipkinSpanTransformer.STATUS_ERROR.getKey(), "")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_WithRpcUnsetStatus() {
|
||||
Attributes attributes = Attributes.of(SemanticAttributes.RPC_SERVICE, "my service name");
|
||||
|
||||
SpanData data =
|
||||
spanBuilder()
|
||||
.setStatus(StatusData.create(StatusCode.UNSET, ""))
|
||||
.setAttributes(attributes)
|
||||
.setTotalAttributeCount(1)
|
||||
.build();
|
||||
|
||||
assertThat(transformer.generateSpan(data))
|
||||
.isEqualTo(
|
||||
zipkinSpan(Span.Kind.SERVER, localIp).toBuilder()
|
||||
.putTag(SemanticAttributes.RPC_SERVICE.getKey(), "my service name")
|
||||
.build());
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
package io.opentelemetry.exporter.zipkin;
|
||||
|
||||
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import com.linecorp.armeria.client.WebClient;
|
||||
import com.linecorp.armeria.common.AggregatedHttpResponse;
|
||||
|
@ -88,6 +89,8 @@ class ZipkinSpanExporterEndToEndHttpTest {
|
|||
private final SdkMeterProvider sdkMeterProvider =
|
||||
SdkMeterProvider.builder().registerMetricReader(sdkMeterReader).build();
|
||||
|
||||
private static final InetAddress localIp = mock(InetAddress.class);
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
sdkMeterProvider.close();
|
||||
|
@ -99,6 +102,7 @@ class ZipkinSpanExporterEndToEndHttpTest {
|
|||
ZipkinSpanExporter.builder()
|
||||
.setEndpoint(zipkinUrl(ENDPOINT_V2_SPANS))
|
||||
.setMeterProvider(sdkMeterProvider)
|
||||
.setLocalIpAddressSupplier(() -> localIp)
|
||||
.build();
|
||||
exportAndVerify(exporter);
|
||||
|
||||
|
@ -173,6 +177,7 @@ class ZipkinSpanExporterEndToEndHttpTest {
|
|||
.setSender(OkHttpSender.newBuilder().endpoint(endpoint).encoding(encoding).build())
|
||||
.setEncoder(encoder)
|
||||
.setMeterProvider(meterProvider)
|
||||
.setLocalIpAddressSupplier(() -> localIp)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -191,9 +196,7 @@ class ZipkinSpanExporterEndToEndHttpTest {
|
|||
|
||||
assertThat(zipkinSpans).isNotNull();
|
||||
assertThat(zipkinSpans.size()).isEqualTo(1);
|
||||
InetAddress address = zipkinSpanExporter.getLocalAddressForTest();
|
||||
assertThat(address).isNotNull();
|
||||
assertThat(zipkinSpans.get(0)).isEqualTo(buildZipkinSpan(address, traceId));
|
||||
assertThat(zipkinSpans.get(0)).isEqualTo(buildZipkinSpan(localIp, traceId));
|
||||
}
|
||||
|
||||
private static TestSpanData.Builder buildStandardSpan(String traceId) {
|
||||
|
@ -229,7 +232,7 @@ class ZipkinSpanExporterEndToEndHttpTest {
|
|||
.localEndpoint(Endpoint.newBuilder().serviceName(SERVICE_NAME).ip(localAddress).build())
|
||||
.addAnnotation(RECEIVED_TIMESTAMP_NANOS / 1000, "RECEIVED")
|
||||
.addAnnotation(SENT_TIMESTAMP_NANOS / 1000, "SENT")
|
||||
.putTag(ZipkinSpanExporter.OTEL_STATUS_CODE, "OK")
|
||||
.putTag(OtelToZipkinSpanTransformer.OTEL_STATUS_CODE, "OK")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -5,14 +5,8 @@
|
|||
|
||||
package io.opentelemetry.exporter.zipkin;
|
||||
|
||||
import static io.opentelemetry.api.common.AttributeKey.booleanArrayKey;
|
||||
import static io.opentelemetry.api.common.AttributeKey.booleanKey;
|
||||
import static io.opentelemetry.api.common.AttributeKey.doubleArrayKey;
|
||||
import static io.opentelemetry.api.common.AttributeKey.doubleKey;
|
||||
import static io.opentelemetry.api.common.AttributeKey.longArrayKey;
|
||||
import static io.opentelemetry.api.common.AttributeKey.longKey;
|
||||
import static io.opentelemetry.api.common.AttributeKey.stringArrayKey;
|
||||
import static io.opentelemetry.api.common.AttributeKey.stringKey;
|
||||
import static io.opentelemetry.exporter.zipkin.ZipkinTestUtil.spanBuilder;
|
||||
import static io.opentelemetry.exporter.zipkin.ZipkinTestUtil.zipkinSpanBuilder;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
|
@ -20,27 +14,13 @@ import static org.mockito.Mockito.doAnswer;
|
|||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.api.metrics.MeterProvider;
|
||||
import io.opentelemetry.api.trace.SpanContext;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.api.trace.StatusCode;
|
||||
import io.opentelemetry.api.trace.TraceFlags;
|
||||
import io.opentelemetry.api.trace.TraceState;
|
||||
import io.opentelemetry.internal.testing.slf4j.SuppressLogger;
|
||||
import io.opentelemetry.sdk.common.CompletableResultCode;
|
||||
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
|
||||
import io.opentelemetry.sdk.resources.Resource;
|
||||
import io.opentelemetry.sdk.testing.trace.TestSpanData;
|
||||
import io.opentelemetry.sdk.trace.data.EventData;
|
||||
import io.opentelemetry.sdk.trace.data.SpanData;
|
||||
import io.opentelemetry.sdk.trace.data.StatusData;
|
||||
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.net.InetAddress;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
@ -48,7 +28,6 @@ import org.mockito.Mock;
|
|||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import zipkin2.Call;
|
||||
import zipkin2.Callback;
|
||||
import zipkin2.Endpoint;
|
||||
import zipkin2.Span;
|
||||
import zipkin2.codec.SpanBytesEncoder;
|
||||
import zipkin2.reporter.Sender;
|
||||
|
@ -59,289 +38,23 @@ class ZipkinSpanExporterTest {
|
|||
@Mock private Sender mockSender;
|
||||
@Mock private SpanBytesEncoder mockEncoder;
|
||||
@Mock private Call<Void> mockZipkinCall;
|
||||
|
||||
private static final String TRACE_ID = "d239036e7d5cec116b562147388b35bf";
|
||||
private static final String SPAN_ID = "9cc1e3049173be09";
|
||||
private static final String PARENT_SPAN_ID = "8b03ab423da481c5";
|
||||
private static final Attributes attributes = Attributes.empty();
|
||||
private static final List<EventData> annotations =
|
||||
Collections.unmodifiableList(
|
||||
Arrays.asList(
|
||||
EventData.create(1505855799_433901068L, "RECEIVED", Attributes.empty()),
|
||||
EventData.create(1505855799_459486280L, "SENT", Attributes.empty())));
|
||||
|
||||
private final ZipkinSpanExporter exporter = ZipkinSpanExporter.builder().build();
|
||||
|
||||
@Test
|
||||
void generateSpan_remoteParent() {
|
||||
SpanData data = buildStandardSpan().build();
|
||||
|
||||
assertThat(exporter.generateSpan(data))
|
||||
.isEqualTo(
|
||||
standardZipkinSpanBuilder(Span.Kind.SERVER)
|
||||
.putTag(ZipkinSpanExporter.OTEL_STATUS_CODE, "OK")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_subMicroDurations() {
|
||||
SpanData data =
|
||||
buildStandardSpan()
|
||||
.setStartEpochNanos(1505855794_194009601L)
|
||||
.setEndEpochNanos(1505855794_194009999L)
|
||||
.build();
|
||||
|
||||
Span expected =
|
||||
standardZipkinSpanBuilder(Span.Kind.SERVER)
|
||||
.putTag(ZipkinSpanExporter.OTEL_STATUS_CODE, "OK")
|
||||
.duration(1)
|
||||
.build();
|
||||
assertThat(exporter.generateSpan(data)).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_ServerKind() {
|
||||
SpanData data = buildStandardSpan().setKind(SpanKind.SERVER).build();
|
||||
|
||||
assertThat(exporter.generateSpan(data))
|
||||
.isEqualTo(
|
||||
standardZipkinSpanBuilder(Span.Kind.SERVER)
|
||||
.putTag(ZipkinSpanExporter.OTEL_STATUS_CODE, "OK")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_ClientKind() {
|
||||
SpanData data = buildStandardSpan().setKind(SpanKind.CLIENT).build();
|
||||
|
||||
assertThat(exporter.generateSpan(data))
|
||||
.isEqualTo(
|
||||
standardZipkinSpanBuilder(Span.Kind.CLIENT)
|
||||
.putTag(ZipkinSpanExporter.OTEL_STATUS_CODE, "OK")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_InternalKind() {
|
||||
SpanData data = buildStandardSpan().setKind(SpanKind.INTERNAL).build();
|
||||
|
||||
assertThat(exporter.generateSpan(data))
|
||||
.isEqualTo(
|
||||
standardZipkinSpanBuilder(null)
|
||||
.putTag(ZipkinSpanExporter.OTEL_STATUS_CODE, "OK")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_ConsumeKind() {
|
||||
SpanData data = buildStandardSpan().setKind(SpanKind.CONSUMER).build();
|
||||
|
||||
assertThat(exporter.generateSpan(data))
|
||||
.isEqualTo(
|
||||
standardZipkinSpanBuilder(Span.Kind.CONSUMER)
|
||||
.putTag(ZipkinSpanExporter.OTEL_STATUS_CODE, "OK")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_ProducerKind() {
|
||||
SpanData data = buildStandardSpan().setKind(SpanKind.PRODUCER).build();
|
||||
|
||||
assertThat(exporter.generateSpan(data))
|
||||
.isEqualTo(
|
||||
standardZipkinSpanBuilder(Span.Kind.PRODUCER)
|
||||
.putTag(ZipkinSpanExporter.OTEL_STATUS_CODE, "OK")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_ResourceServiceNameMapping() {
|
||||
Resource resource =
|
||||
Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, "super-zipkin-service"));
|
||||
SpanData data = buildStandardSpan().setResource(resource).build();
|
||||
|
||||
Endpoint expectedEndpoint =
|
||||
Endpoint.newBuilder()
|
||||
.serviceName("super-zipkin-service")
|
||||
.ip(exporter.getLocalAddressForTest())
|
||||
.build();
|
||||
Span expectedZipkinSpan =
|
||||
buildZipkinSpan(Span.Kind.SERVER).toBuilder()
|
||||
.localEndpoint(expectedEndpoint)
|
||||
.putTag(ZipkinSpanExporter.OTEL_STATUS_CODE, "OK")
|
||||
.build();
|
||||
assertThat(exporter.generateSpan(data)).isEqualTo(expectedZipkinSpan);
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_defaultResourceServiceName() {
|
||||
SpanData data = buildStandardSpan().setResource(Resource.empty()).build();
|
||||
|
||||
Endpoint expectedEndpoint =
|
||||
Endpoint.newBuilder()
|
||||
.serviceName(Resource.getDefault().getAttribute(ResourceAttributes.SERVICE_NAME))
|
||||
.ip(exporter.getLocalAddressForTest())
|
||||
.build();
|
||||
Span expectedZipkinSpan =
|
||||
buildZipkinSpan(Span.Kind.SERVER).toBuilder()
|
||||
.localEndpoint(expectedEndpoint)
|
||||
.putTag(ZipkinSpanExporter.OTEL_STATUS_CODE, "OK")
|
||||
.build();
|
||||
assertThat(exporter.generateSpan(data)).isEqualTo(expectedZipkinSpan);
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_WithAttributes() {
|
||||
Attributes attributes =
|
||||
Attributes.builder()
|
||||
.put(stringKey("string"), "string value")
|
||||
.put(booleanKey("boolean"), false)
|
||||
.put(longKey("long"), 9999L)
|
||||
.put(doubleKey("double"), 222.333d)
|
||||
.put(booleanArrayKey("booleanArray"), Arrays.asList(true, false))
|
||||
.put(stringArrayKey("stringArray"), Collections.singletonList("Hello"))
|
||||
.put(doubleArrayKey("doubleArray"), Arrays.asList(32.33d, -98.3d))
|
||||
.put(longArrayKey("longArray"), Arrays.asList(33L, 999L))
|
||||
.build();
|
||||
SpanData data =
|
||||
buildStandardSpan()
|
||||
.setAttributes(attributes)
|
||||
.setTotalAttributeCount(28)
|
||||
.setTotalRecordedEvents(3)
|
||||
.setKind(SpanKind.CLIENT)
|
||||
.build();
|
||||
|
||||
assertThat(exporter.generateSpan(data))
|
||||
.isEqualTo(
|
||||
buildZipkinSpan(Span.Kind.CLIENT).toBuilder()
|
||||
.putTag("string", "string value")
|
||||
.putTag("boolean", "false")
|
||||
.putTag("long", "9999")
|
||||
.putTag("double", "222.333")
|
||||
.putTag("booleanArray", "true,false")
|
||||
.putTag("stringArray", "Hello")
|
||||
.putTag("doubleArray", "32.33,-98.3")
|
||||
.putTag("longArray", "33,999")
|
||||
.putTag(ZipkinSpanExporter.OTEL_STATUS_CODE, "OK")
|
||||
.putTag(ZipkinSpanExporter.OTEL_DROPPED_ATTRIBUTES_COUNT, "20")
|
||||
.putTag(ZipkinSpanExporter.OTEL_DROPPED_EVENTS_COUNT, "1")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_WithInstrumentationLibraryInfo() {
|
||||
SpanData data =
|
||||
buildStandardSpan()
|
||||
.setInstrumentationScopeInfo(
|
||||
InstrumentationScopeInfo.create("io.opentelemetry.auto", "1.0.0", null))
|
||||
.setKind(SpanKind.CLIENT)
|
||||
.build();
|
||||
|
||||
assertThat(exporter.generateSpan(data))
|
||||
.isEqualTo(
|
||||
buildZipkinSpan(Span.Kind.CLIENT).toBuilder()
|
||||
.putTag("otel.scope.name", "io.opentelemetry.auto")
|
||||
.putTag("otel.scope.version", "1.0.0")
|
||||
.putTag("otel.library.name", "io.opentelemetry.auto")
|
||||
.putTag("otel.library.version", "1.0.0")
|
||||
.putTag(ZipkinSpanExporter.OTEL_STATUS_CODE, "OK")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_AlreadyHasHttpStatusInfo() {
|
||||
Attributes attributeMap =
|
||||
Attributes.of(
|
||||
SemanticAttributes.HTTP_STATUS_CODE, 404L, stringKey("error"), "A user provided error");
|
||||
SpanData data =
|
||||
buildStandardSpan()
|
||||
.setAttributes(attributeMap)
|
||||
.setKind(SpanKind.CLIENT)
|
||||
.setStatus(StatusData.error())
|
||||
.setTotalAttributeCount(2)
|
||||
.build();
|
||||
|
||||
assertThat(exporter.generateSpan(data))
|
||||
.isEqualTo(
|
||||
buildZipkinSpan(Span.Kind.CLIENT).toBuilder()
|
||||
.clearTags()
|
||||
.putTag(SemanticAttributes.HTTP_STATUS_CODE.getKey(), "404")
|
||||
.putTag(ZipkinSpanExporter.OTEL_STATUS_CODE, "ERROR")
|
||||
.putTag("error", "A user provided error")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_WithRpcTimeoutErrorStatus_WithTimeoutErrorDescription() {
|
||||
Attributes attributeMap = Attributes.of(SemanticAttributes.RPC_SERVICE, "my service name");
|
||||
|
||||
String errorMessage = "timeout";
|
||||
|
||||
SpanData data =
|
||||
buildStandardSpan()
|
||||
.setStatus(StatusData.create(StatusCode.ERROR, errorMessage))
|
||||
.setAttributes(attributeMap)
|
||||
.setTotalAttributeCount(1)
|
||||
.build();
|
||||
|
||||
assertThat(exporter.generateSpan(data))
|
||||
.isEqualTo(
|
||||
buildZipkinSpan(Span.Kind.SERVER).toBuilder()
|
||||
.putTag(SemanticAttributes.RPC_SERVICE.getKey(), "my service name")
|
||||
.putTag(ZipkinSpanExporter.OTEL_STATUS_CODE, "ERROR")
|
||||
.putTag(ZipkinSpanExporter.STATUS_ERROR.getKey(), errorMessage)
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_WithRpcErrorStatus_WithEmptyErrorDescription() {
|
||||
Attributes attributeMap = Attributes.of(SemanticAttributes.RPC_SERVICE, "my service name");
|
||||
|
||||
SpanData data =
|
||||
buildStandardSpan()
|
||||
.setStatus(StatusData.create(StatusCode.ERROR, ""))
|
||||
.setAttributes(attributeMap)
|
||||
.setTotalAttributeCount(1)
|
||||
.build();
|
||||
|
||||
assertThat(exporter.generateSpan(data))
|
||||
.isEqualTo(
|
||||
buildZipkinSpan(Span.Kind.SERVER).toBuilder()
|
||||
.putTag(SemanticAttributes.RPC_SERVICE.getKey(), "my service name")
|
||||
.putTag(ZipkinSpanExporter.OTEL_STATUS_CODE, "ERROR")
|
||||
.putTag(ZipkinSpanExporter.STATUS_ERROR.getKey(), "")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSpan_WithRpcUnsetStatus() {
|
||||
Attributes attributeMap = Attributes.of(SemanticAttributes.RPC_SERVICE, "my service name");
|
||||
|
||||
SpanData data =
|
||||
buildStandardSpan()
|
||||
.setStatus(StatusData.create(StatusCode.UNSET, ""))
|
||||
.setAttributes(attributeMap)
|
||||
.setTotalAttributeCount(1)
|
||||
.build();
|
||||
|
||||
assertThat(exporter.generateSpan(data))
|
||||
.isEqualTo(
|
||||
buildZipkinSpan(Span.Kind.SERVER).toBuilder()
|
||||
.putTag(SemanticAttributes.RPC_SERVICE.getKey(), "my service name")
|
||||
.build());
|
||||
}
|
||||
@Mock private OtelToZipkinSpanTransformer mockTransformer;
|
||||
@Mock private InetAddress localIp;
|
||||
|
||||
@Test
|
||||
void testExport() {
|
||||
TestSpanData testSpanData = spanBuilder().build();
|
||||
|
||||
ZipkinSpanExporter zipkinSpanExporter =
|
||||
new ZipkinSpanExporter(mockEncoder, mockSender, MeterProvider.noop());
|
||||
new ZipkinSpanExporter(mockEncoder, mockSender, MeterProvider.noop(), mockTransformer);
|
||||
|
||||
byte[] someBytes = new byte[0];
|
||||
when(mockEncoder.encode(
|
||||
standardZipkinSpanBuilder(Span.Kind.SERVER)
|
||||
.putTag(ZipkinSpanExporter.OTEL_STATUS_CODE, "OK")
|
||||
.build()))
|
||||
.thenReturn(someBytes);
|
||||
Span zipkinSpan =
|
||||
zipkinSpanBuilder(Span.Kind.SERVER, localIp)
|
||||
.putTag(OtelToZipkinSpanTransformer.OTEL_STATUS_CODE, "OK")
|
||||
.build();
|
||||
when(mockTransformer.generateSpan(testSpanData)).thenReturn(zipkinSpan);
|
||||
when(mockEncoder.encode(zipkinSpan)).thenReturn(someBytes);
|
||||
when(mockSender.sendSpans(Collections.singletonList(someBytes))).thenReturn(mockZipkinCall);
|
||||
doAnswer(
|
||||
invocation -> {
|
||||
|
@ -353,7 +66,7 @@ class ZipkinSpanExporterTest {
|
|||
.enqueue(any());
|
||||
|
||||
CompletableResultCode resultCode =
|
||||
zipkinSpanExporter.export(Collections.singleton(buildStandardSpan().build()));
|
||||
zipkinSpanExporter.export(Collections.singleton(testSpanData));
|
||||
|
||||
assertThat(resultCode.isSuccess()).isTrue();
|
||||
}
|
||||
|
@ -361,15 +74,18 @@ class ZipkinSpanExporterTest {
|
|||
@Test
|
||||
@SuppressLogger(ZipkinSpanExporter.class)
|
||||
void testExport_failed() {
|
||||
TestSpanData testSpanData = spanBuilder().build();
|
||||
|
||||
ZipkinSpanExporter zipkinSpanExporter =
|
||||
new ZipkinSpanExporter(mockEncoder, mockSender, MeterProvider.noop());
|
||||
new ZipkinSpanExporter(mockEncoder, mockSender, MeterProvider.noop(), mockTransformer);
|
||||
|
||||
byte[] someBytes = new byte[0];
|
||||
when(mockEncoder.encode(
|
||||
standardZipkinSpanBuilder(Span.Kind.SERVER)
|
||||
.putTag(ZipkinSpanExporter.OTEL_STATUS_CODE, "OK")
|
||||
.build()))
|
||||
.thenReturn(someBytes);
|
||||
Span zipkinSpan =
|
||||
zipkinSpanBuilder(Span.Kind.SERVER, localIp)
|
||||
.putTag(OtelToZipkinSpanTransformer.OTEL_STATUS_CODE, "OK")
|
||||
.build();
|
||||
when(mockTransformer.generateSpan(testSpanData)).thenReturn(zipkinSpan);
|
||||
when(mockEncoder.encode(zipkinSpan)).thenReturn(someBytes);
|
||||
when(mockSender.sendSpans(Collections.singletonList(someBytes))).thenReturn(mockZipkinCall);
|
||||
doAnswer(
|
||||
invocation -> {
|
||||
|
@ -381,7 +97,7 @@ class ZipkinSpanExporterTest {
|
|||
.enqueue(any());
|
||||
|
||||
CompletableResultCode resultCode =
|
||||
zipkinSpanExporter.export(Collections.singleton(buildStandardSpan().build()));
|
||||
zipkinSpanExporter.export(Collections.singleton(testSpanData));
|
||||
|
||||
assertThat(resultCode.isSuccess()).isFalse();
|
||||
}
|
||||
|
@ -401,51 +117,6 @@ class ZipkinSpanExporterTest {
|
|||
verify(mockSender).close();
|
||||
}
|
||||
|
||||
private static TestSpanData.Builder buildStandardSpan() {
|
||||
return TestSpanData.builder()
|
||||
.setSpanContext(
|
||||
SpanContext.create(TRACE_ID, SPAN_ID, TraceFlags.getSampled(), TraceState.getDefault()))
|
||||
.setParentSpanContext(
|
||||
SpanContext.create(
|
||||
TRACE_ID, PARENT_SPAN_ID, TraceFlags.getDefault(), TraceState.getDefault()))
|
||||
.setResource(
|
||||
Resource.create(
|
||||
Attributes.builder().put(ResourceAttributes.SERVICE_NAME, "tweetiebird").build()))
|
||||
.setStatus(StatusData.ok())
|
||||
.setKind(SpanKind.SERVER)
|
||||
.setName("Recv.helloworld.Greeter.SayHello")
|
||||
.setStartEpochNanos(1505855794_194009601L)
|
||||
.setEndEpochNanos(1505855799_465726528L)
|
||||
.setAttributes(attributes)
|
||||
.setTotalAttributeCount(attributes.size())
|
||||
.setTotalRecordedEvents(annotations.size())
|
||||
.setEvents(annotations)
|
||||
.setLinks(Collections.emptyList())
|
||||
.setHasEnded(true);
|
||||
}
|
||||
|
||||
private Span buildZipkinSpan(Span.Kind kind) {
|
||||
return standardZipkinSpanBuilder(kind).build();
|
||||
}
|
||||
|
||||
private Span.Builder standardZipkinSpanBuilder(Span.Kind kind) {
|
||||
return Span.newBuilder()
|
||||
.traceId(TRACE_ID)
|
||||
.parentId(PARENT_SPAN_ID)
|
||||
.id(SPAN_ID)
|
||||
.kind(kind)
|
||||
.name("Recv.helloworld.Greeter.SayHello")
|
||||
.timestamp(1505855794000000L + 194009601L / 1000)
|
||||
.duration((1505855799000000L + 465726528L / 1000) - (1505855794000000L + 194009601L / 1000))
|
||||
.localEndpoint(
|
||||
Endpoint.newBuilder()
|
||||
.ip(exporter.getLocalAddressForTest())
|
||||
.serviceName("tweetiebird")
|
||||
.build())
|
||||
.addAnnotation(1505855799000000L + 433901068L / 1000, "RECEIVED")
|
||||
.addAnnotation(1505855799000000L + 459486280L / 1000, "SENT");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("PreferJavaTimeOverload")
|
||||
void invalidConfig() {
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.exporter.zipkin;
|
||||
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.api.trace.SpanContext;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.api.trace.TraceFlags;
|
||||
import io.opentelemetry.api.trace.TraceState;
|
||||
import io.opentelemetry.sdk.resources.Resource;
|
||||
import io.opentelemetry.sdk.testing.trace.TestSpanData;
|
||||
import io.opentelemetry.sdk.trace.data.EventData;
|
||||
import io.opentelemetry.sdk.trace.data.StatusData;
|
||||
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
|
||||
import java.net.InetAddress;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import zipkin2.Endpoint;
|
||||
import zipkin2.Span;
|
||||
|
||||
class ZipkinTestUtil {
|
||||
|
||||
static final String TRACE_ID = "d239036e7d5cec116b562147388b35bf";
|
||||
static final String SPAN_ID = "9cc1e3049173be09";
|
||||
static final String PARENT_SPAN_ID = "8b03ab423da481c5";
|
||||
|
||||
private static final Attributes attributes = Attributes.empty();
|
||||
private static final List<EventData> annotations =
|
||||
Collections.unmodifiableList(
|
||||
Arrays.asList(
|
||||
EventData.create(1505855799_433901068L, "RECEIVED", Attributes.empty()),
|
||||
EventData.create(1505855799_459486280L, "SENT", Attributes.empty())));
|
||||
|
||||
private ZipkinTestUtil() {}
|
||||
|
||||
static TestSpanData.Builder spanBuilder() {
|
||||
return TestSpanData.builder()
|
||||
.setSpanContext(
|
||||
SpanContext.create(TRACE_ID, SPAN_ID, TraceFlags.getSampled(), TraceState.getDefault()))
|
||||
.setParentSpanContext(
|
||||
SpanContext.create(
|
||||
TRACE_ID, PARENT_SPAN_ID, TraceFlags.getDefault(), TraceState.getDefault()))
|
||||
.setResource(
|
||||
Resource.create(
|
||||
Attributes.builder().put(ResourceAttributes.SERVICE_NAME, "tweetiebird").build()))
|
||||
.setStatus(StatusData.ok())
|
||||
.setKind(SpanKind.SERVER)
|
||||
.setName("Recv.helloworld.Greeter.SayHello")
|
||||
.setStartEpochNanos(1505855794_194009601L)
|
||||
.setEndEpochNanos(1505855799_465726528L)
|
||||
.setAttributes(attributes)
|
||||
.setTotalAttributeCount(attributes.size())
|
||||
.setTotalRecordedEvents(annotations.size())
|
||||
.setEvents(annotations)
|
||||
.setLinks(Collections.emptyList())
|
||||
.setHasEnded(true);
|
||||
}
|
||||
|
||||
static Span zipkinSpan(Span.Kind kind, InetAddress localIp) {
|
||||
return zipkinSpanBuilder(kind, localIp).build();
|
||||
}
|
||||
|
||||
static Span.Builder zipkinSpanBuilder(Span.Kind kind, InetAddress localIp) {
|
||||
return Span.newBuilder()
|
||||
.traceId(TRACE_ID)
|
||||
.parentId(PARENT_SPAN_ID)
|
||||
.id(SPAN_ID)
|
||||
.kind(kind)
|
||||
.name("Recv.helloworld.Greeter.SayHello")
|
||||
.timestamp(1505855794000000L + 194009601L / 1000)
|
||||
.duration((1505855799000000L + 465726528L / 1000) - (1505855794000000L + 194009601L / 1000))
|
||||
.localEndpoint(Endpoint.newBuilder().ip(localIp).serviceName("tweetiebird").build())
|
||||
.addAnnotation(1505855799000000L + 433901068L / 1000, "RECEIVED")
|
||||
.addAnnotation(1505855799000000L + 459486280L / 1000, "SENT");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue