Add OTLP trace implementation (#984)
Signed-off-by: Bogdan Cristian Drutu <bogdandrutu@gmail.com>
This commit is contained in:
parent
49a5e01ce1
commit
0aa70d123f
|
|
@ -9,10 +9,12 @@ description = 'OpenTelemetry Protocol Exporter'
|
|||
ext.moduleName = "io.opentelemetry.exporters.otprotocol"
|
||||
|
||||
dependencies {
|
||||
api project(':opentelemetry-proto'),
|
||||
project(':opentelemetry-sdk')
|
||||
api project(':opentelemetry-sdk')
|
||||
|
||||
implementation libraries.grpc_protobuf,
|
||||
implementation project(':opentelemetry-sdk-contrib-otproto'),
|
||||
project(':opentelemetry-sdk'),
|
||||
libraries.grpc_api,
|
||||
libraries.grpc_protobuf,
|
||||
libraries.grpc_stub,
|
||||
libraries.protobuf,
|
||||
libraries.protobuf_util
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright 2020, OpenTelemetry Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.opentelemetry.exporters.otlp;
|
||||
|
||||
import io.opentelemetry.proto.common.v1.AttributeKeyValue;
|
||||
import io.opentelemetry.proto.common.v1.AttributeKeyValue.ValueType;
|
||||
import io.opentelemetry.trace.AttributeValue;
|
||||
|
||||
final class CommonAdapter {
|
||||
static AttributeKeyValue toProtoAttribute(String key, AttributeValue attributeValue) {
|
||||
AttributeKeyValue.Builder builder = AttributeKeyValue.newBuilder().setKey(key);
|
||||
switch (attributeValue.getType()) {
|
||||
case STRING:
|
||||
return builder
|
||||
.setType(ValueType.STRING)
|
||||
.setStringValue(attributeValue.getStringValue())
|
||||
.build();
|
||||
case BOOLEAN:
|
||||
return builder
|
||||
.setType(ValueType.BOOL)
|
||||
.setBoolValue(attributeValue.getBooleanValue())
|
||||
.build();
|
||||
case LONG:
|
||||
return builder.setType(ValueType.INT).setIntValue(attributeValue.getLongValue()).build();
|
||||
case DOUBLE:
|
||||
return builder
|
||||
.setType(ValueType.DOUBLE)
|
||||
.setDoubleValue(attributeValue.getDoubleValue())
|
||||
.build();
|
||||
}
|
||||
return builder.setType(ValueType.UNRECOGNIZED).build();
|
||||
}
|
||||
|
||||
private CommonAdapter() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* Copyright 2020, OpenTelemetry Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.opentelemetry.exporters.otlp;
|
||||
|
||||
import io.grpc.ManagedChannel;
|
||||
import io.grpc.StatusRuntimeException;
|
||||
import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest;
|
||||
import io.opentelemetry.proto.collector.trace.v1.TraceServiceGrpc;
|
||||
import io.opentelemetry.sdk.trace.data.SpanData;
|
||||
import io.opentelemetry.sdk.trace.export.SpanExporter;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
|
||||
/** Exports spans using OTLP via gRPC, using OpenTelemetry's protobuf model. */
|
||||
@ThreadSafe
|
||||
public final class OtlpGrpcSpanExporter implements SpanExporter {
|
||||
private static final Logger logger = Logger.getLogger(OtlpGrpcSpanExporter.class.getName());
|
||||
|
||||
private final TraceServiceGrpc.TraceServiceBlockingStub blockingStub;
|
||||
private final ManagedChannel managedChannel;
|
||||
private final long deadlineMs;
|
||||
|
||||
/**
|
||||
* Creates a new Jaeger gRPC Span Reporter with the given name, using the given channel.
|
||||
*
|
||||
* @param channel the channel to use when communicating with the Jaeger Collector.
|
||||
* @param deadlineMs max waiting time for the collector to process each span batch. When set to 0
|
||||
* or to a negative value, the exporter will wait indefinitely.
|
||||
*/
|
||||
private OtlpGrpcSpanExporter(ManagedChannel channel, long deadlineMs) {
|
||||
this.managedChannel = channel;
|
||||
this.blockingStub = TraceServiceGrpc.newBlockingStub(channel);
|
||||
this.deadlineMs = deadlineMs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits all the given spans in a single batch to the Jaeger collector.
|
||||
*
|
||||
* @param spans the list of sampled Spans to be exported.
|
||||
* @return the result of the operation
|
||||
*/
|
||||
@Override
|
||||
public ResultCode export(List<SpanData> spans) {
|
||||
ExportTraceServiceRequest exportTraceServiceRequest =
|
||||
ExportTraceServiceRequest.newBuilder()
|
||||
.addAllResourceSpans(SpanAdapter.toProtoResourceSpans(spans))
|
||||
.build();
|
||||
|
||||
try {
|
||||
TraceServiceGrpc.TraceServiceBlockingStub stub = this.blockingStub;
|
||||
if (deadlineMs > 0) {
|
||||
stub = stub.withDeadlineAfter(deadlineMs, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
// for now, there's nothing to check in the response object
|
||||
// noinspection ResultOfMethodCallIgnored
|
||||
stub.export(exportTraceServiceRequest);
|
||||
return ResultCode.SUCCESS;
|
||||
} catch (StatusRuntimeException e) {
|
||||
// Retryable codes from https://github.com/open-telemetry/oteps/pull/65
|
||||
switch (e.getStatus().getCode()) {
|
||||
case CANCELLED:
|
||||
case DEADLINE_EXCEEDED:
|
||||
case RESOURCE_EXHAUSTED:
|
||||
case OUT_OF_RANGE:
|
||||
case UNAVAILABLE:
|
||||
case DATA_LOSS:
|
||||
logger.info(e.getStatus().toString());
|
||||
return ResultCode.FAILED_RETRYABLE;
|
||||
default:
|
||||
return ResultCode.FAILED_NOT_RETRYABLE;
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
return ResultCode.FAILED_NOT_RETRYABLE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new builder instance.
|
||||
*
|
||||
* @return a new instance builder for this exporter
|
||||
*/
|
||||
public static Builder newBuilder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates an orderly shutdown in which preexisting calls continue but new calls are immediately
|
||||
* cancelled. The channel is forcefully closed after a timeout.
|
||||
*/
|
||||
@Override
|
||||
public void shutdown() {
|
||||
try {
|
||||
managedChannel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
logger.log(Level.WARNING, "Failed to shutdown the gRPC channel", e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Builder utility for this exporter. */
|
||||
public static class Builder {
|
||||
private ManagedChannel channel;
|
||||
private long deadlineMs = 1_000; // 1 second
|
||||
|
||||
/**
|
||||
* Sets the managed chanel to use when communicating with the backend. Required.
|
||||
*
|
||||
* @param channel the channel to use
|
||||
* @return this builder's instance
|
||||
*/
|
||||
public Builder setChannel(ManagedChannel channel) {
|
||||
this.channel = channel;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the max waiting time for the collector to process each span batch. Optional.
|
||||
*
|
||||
* @param deadlineMs the max waiting time
|
||||
* @return this builder's instance
|
||||
*/
|
||||
public Builder setDeadlineMs(long deadlineMs) {
|
||||
this.deadlineMs = deadlineMs;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the exporter based on the builder's values.
|
||||
*
|
||||
* @return a new exporter's instance
|
||||
*/
|
||||
public OtlpGrpcSpanExporter build() {
|
||||
return new OtlpGrpcSpanExporter(channel, deadlineMs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright 2020, OpenTelemetry Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.opentelemetry.exporters.otlp;
|
||||
|
||||
import io.opentelemetry.proto.resource.v1.Resource;
|
||||
import io.opentelemetry.trace.AttributeValue;
|
||||
import java.util.Map;
|
||||
|
||||
final class ResourceAdapter {
|
||||
static Resource toProtoResource(io.opentelemetry.sdk.resources.Resource resource) {
|
||||
Resource.Builder builder = Resource.newBuilder();
|
||||
for (Map.Entry<String, AttributeValue> resourceEntry : resource.getLabels().entrySet()) {
|
||||
builder.addAttributes(
|
||||
CommonAdapter.toProtoAttribute(resourceEntry.getKey(), resourceEntry.getValue()));
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private ResourceAdapter() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Copyright 2020, OpenTelemetry Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.opentelemetry.exporters.otlp;
|
||||
|
||||
import io.opentelemetry.proto.trace.v1.ResourceSpans;
|
||||
import io.opentelemetry.proto.trace.v1.Span;
|
||||
import io.opentelemetry.proto.trace.v1.Span.SpanKind;
|
||||
import io.opentelemetry.proto.trace.v1.Status;
|
||||
import io.opentelemetry.proto.trace.v1.Status.StatusCode;
|
||||
import io.opentelemetry.sdk.contrib.otproto.TraceProtoUtils;
|
||||
import io.opentelemetry.sdk.resources.Resource;
|
||||
import io.opentelemetry.sdk.trace.data.SpanData;
|
||||
import io.opentelemetry.sdk.trace.data.SpanData.TimedEvent;
|
||||
import io.opentelemetry.trace.AttributeValue;
|
||||
import io.opentelemetry.trace.Link;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
final class SpanAdapter {
|
||||
static List<ResourceSpans> toProtoResourceSpans(List<SpanData> spanDataList) {
|
||||
Map<Resource, ResourceSpans.Builder> resourceSpansBuilderMap = new HashMap<>();
|
||||
for (SpanData spanData : spanDataList) {
|
||||
Resource resource = spanData.getResource();
|
||||
ResourceSpans.Builder resourceSpansBuilder =
|
||||
resourceSpansBuilderMap.get(spanData.getResource());
|
||||
if (resourceSpansBuilder == null) {
|
||||
resourceSpansBuilder =
|
||||
ResourceSpans.newBuilder().setResource(ResourceAdapter.toProtoResource(resource));
|
||||
resourceSpansBuilderMap.put(resource, resourceSpansBuilder);
|
||||
}
|
||||
resourceSpansBuilder.addSpans(toProtoSpan(spanData));
|
||||
}
|
||||
List<ResourceSpans> resourceSpans = new ArrayList<>(resourceSpansBuilderMap.size());
|
||||
for (ResourceSpans.Builder resourceSpansBuilder : resourceSpansBuilderMap.values()) {
|
||||
resourceSpans.add(resourceSpansBuilder.build());
|
||||
}
|
||||
return resourceSpans;
|
||||
}
|
||||
|
||||
static Span toProtoSpan(SpanData spanData) {
|
||||
Span.Builder builder = Span.newBuilder();
|
||||
builder.setTraceId(TraceProtoUtils.toProtoTraceId(spanData.getTraceId()));
|
||||
builder.setSpanId(TraceProtoUtils.toProtoSpanId(spanData.getSpanId()));
|
||||
// TODO: Set TraceState;
|
||||
builder.setParentSpanId(TraceProtoUtils.toProtoSpanId(spanData.getParentSpanId()));
|
||||
builder.setName(spanData.getName());
|
||||
builder.setKind(toProtoSpanKind(spanData.getKind()));
|
||||
builder.setStartTimeUnixnano(spanData.getStartEpochNanos());
|
||||
builder.setEndTimeUnixnano(spanData.getEndEpochNanos());
|
||||
for (Map.Entry<String, AttributeValue> resourceEntry : spanData.getAttributes().entrySet()) {
|
||||
builder.addAttributes(
|
||||
CommonAdapter.toProtoAttribute(resourceEntry.getKey(), resourceEntry.getValue()));
|
||||
}
|
||||
// TODO: Set DroppedAttributesCount;
|
||||
for (TimedEvent timedEvent : spanData.getTimedEvents()) {
|
||||
builder.addEvents(toProtoSpanEvent(timedEvent));
|
||||
}
|
||||
builder.setDroppedEventsCount(
|
||||
spanData.getTotalRecordedEvents() - spanData.getTimedEvents().size());
|
||||
for (Link link : spanData.getLinks()) {
|
||||
builder.addLinks(toProtoSpanLink(link));
|
||||
}
|
||||
builder.setDroppedLinksCount(spanData.getTotalRecordedLinks() - spanData.getLinks().size());
|
||||
builder.setStatus(toStatusProto(spanData.getStatus()));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
static Span.SpanKind toProtoSpanKind(io.opentelemetry.trace.Span.Kind kind) {
|
||||
switch (kind) {
|
||||
case INTERNAL:
|
||||
return SpanKind.INTERNAL;
|
||||
case SERVER:
|
||||
return SpanKind.SERVER;
|
||||
case CLIENT:
|
||||
return SpanKind.CLIENT;
|
||||
case PRODUCER:
|
||||
return SpanKind.PRODUCER;
|
||||
case CONSUMER:
|
||||
return SpanKind.CONSUMER;
|
||||
}
|
||||
return SpanKind.UNRECOGNIZED;
|
||||
}
|
||||
|
||||
static Span.Event toProtoSpanEvent(TimedEvent timedEvent) {
|
||||
Span.Event.Builder builder = Span.Event.newBuilder();
|
||||
builder.setName(timedEvent.getName());
|
||||
builder.setTimeUnixnano(timedEvent.getEpochNanos());
|
||||
for (Map.Entry<String, AttributeValue> resourceEntry : timedEvent.getAttributes().entrySet()) {
|
||||
builder.addAttributes(
|
||||
CommonAdapter.toProtoAttribute(resourceEntry.getKey(), resourceEntry.getValue()));
|
||||
}
|
||||
// TODO: Set DroppedAttributesCount;
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
static Span.Link toProtoSpanLink(Link link) {
|
||||
Span.Link.Builder builder = Span.Link.newBuilder();
|
||||
builder.setTraceId(TraceProtoUtils.toProtoTraceId(link.getContext().getTraceId()));
|
||||
builder.setSpanId(TraceProtoUtils.toProtoSpanId(link.getContext().getSpanId()));
|
||||
// TODO: Set TraceState;
|
||||
for (Map.Entry<String, AttributeValue> resourceEntry : link.getAttributes().entrySet()) {
|
||||
builder.addAttributes(
|
||||
CommonAdapter.toProtoAttribute(resourceEntry.getKey(), resourceEntry.getValue()));
|
||||
}
|
||||
// TODO: Set DroppedAttributesCount;
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
static Status toStatusProto(io.opentelemetry.trace.Status status) {
|
||||
Status.Builder builder =
|
||||
Status.newBuilder().setCode(StatusCode.forNumber(status.getCanonicalCode().value()));
|
||||
if (status.getDescription() != null) {
|
||||
builder.setMessage(status.getDescription());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private SpanAdapter() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright 2019, OpenTelemetry Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.opentelemetry.exporters.otlp;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import io.opentelemetry.proto.common.v1.AttributeKeyValue;
|
||||
import io.opentelemetry.proto.common.v1.AttributeKeyValue.ValueType;
|
||||
import io.opentelemetry.trace.AttributeValue;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link CommonAdapter}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class CommonAdapterTest {
|
||||
@Test
|
||||
public void toProtoAttribute_Bool() {
|
||||
assertThat(CommonAdapter.toProtoAttribute("key", AttributeValue.booleanAttributeValue(true)))
|
||||
.isEqualTo(
|
||||
AttributeKeyValue.newBuilder()
|
||||
.setKey("key")
|
||||
.setBoolValue(true)
|
||||
.setType(ValueType.BOOL)
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toProtoAttribute_String() {
|
||||
assertThat(CommonAdapter.toProtoAttribute("key", AttributeValue.stringAttributeValue("string")))
|
||||
.isEqualTo(
|
||||
AttributeKeyValue.newBuilder()
|
||||
.setKey("key")
|
||||
.setStringValue("string")
|
||||
.setType(ValueType.STRING)
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toProtoAttribute_Int() {
|
||||
assertThat(CommonAdapter.toProtoAttribute("key", AttributeValue.longAttributeValue(100)))
|
||||
.isEqualTo(
|
||||
AttributeKeyValue.newBuilder()
|
||||
.setKey("key")
|
||||
.setIntValue(100)
|
||||
.setType(ValueType.INT)
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toProtoAttribute_Double() {
|
||||
assertThat(CommonAdapter.toProtoAttribute("key", AttributeValue.doubleAttributeValue(100.3)))
|
||||
.isEqualTo(
|
||||
AttributeKeyValue.newBuilder()
|
||||
.setKey("key")
|
||||
.setDoubleValue(100.3)
|
||||
.setType(ValueType.DOUBLE)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
* Copyright 2019, OpenTelemetry Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.opentelemetry.exporters.otlp;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import io.grpc.ManagedChannel;
|
||||
import io.grpc.Status.Code;
|
||||
import io.grpc.inprocess.InProcessChannelBuilder;
|
||||
import io.grpc.inprocess.InProcessServerBuilder;
|
||||
import io.grpc.testing.GrpcCleanupRule;
|
||||
import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest;
|
||||
import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceResponse;
|
||||
import io.opentelemetry.proto.collector.trace.v1.TraceServiceGrpc;
|
||||
import io.opentelemetry.proto.trace.v1.ResourceSpans;
|
||||
import io.opentelemetry.sdk.trace.data.SpanData;
|
||||
import io.opentelemetry.sdk.trace.export.SpanExporter.ResultCode;
|
||||
import io.opentelemetry.trace.Link;
|
||||
import io.opentelemetry.trace.Span.Kind;
|
||||
import io.opentelemetry.trace.SpanId;
|
||||
import io.opentelemetry.trace.Status;
|
||||
import io.opentelemetry.trace.TraceId;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link OtlpGrpcSpanExporter}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class OtlpGrpcSpanExporterTest {
|
||||
private static final String TRACE_ID = "00000000000000000000000000abc123";
|
||||
private static final String SPAN_ID = "0000000000def456";
|
||||
|
||||
@Rule public final GrpcCleanupRule grpcCleanup = new GrpcCleanupRule();
|
||||
|
||||
private final FakeCollector fakeCollector = new FakeCollector();
|
||||
private final String serverName = InProcessServerBuilder.generateName();
|
||||
private final ManagedChannel inProcessChannel =
|
||||
InProcessChannelBuilder.forName(serverName).directExecutor().build();
|
||||
|
||||
@Before
|
||||
public void setup() throws IOException {
|
||||
grpcCleanup.register(
|
||||
InProcessServerBuilder.forName(serverName)
|
||||
.directExecutor()
|
||||
.addService(fakeCollector)
|
||||
.build()
|
||||
.start());
|
||||
grpcCleanup.register(inProcessChannel);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExport() {
|
||||
SpanData span = generateFakeSpan();
|
||||
OtlpGrpcSpanExporter exporter =
|
||||
OtlpGrpcSpanExporter.newBuilder().setChannel(inProcessChannel).build();
|
||||
try {
|
||||
assertThat(exporter.export(Collections.singletonList(span))).isEqualTo(ResultCode.SUCCESS);
|
||||
assertThat(fakeCollector.getReceivedSpans())
|
||||
.isEqualTo(SpanAdapter.toProtoResourceSpans(Collections.singletonList(span)));
|
||||
} finally {
|
||||
exporter.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExport_MultipleSpans() {
|
||||
List<SpanData> spans = new ArrayList<>();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
spans.add(generateFakeSpan());
|
||||
}
|
||||
OtlpGrpcSpanExporter exporter =
|
||||
OtlpGrpcSpanExporter.newBuilder().setChannel(inProcessChannel).build();
|
||||
try {
|
||||
assertThat(exporter.export(spans)).isEqualTo(ResultCode.SUCCESS);
|
||||
assertThat(fakeCollector.getReceivedSpans())
|
||||
.isEqualTo(SpanAdapter.toProtoResourceSpans(spans));
|
||||
} finally {
|
||||
exporter.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExport_AfterShutdown() {
|
||||
SpanData span = generateFakeSpan();
|
||||
OtlpGrpcSpanExporter exporter =
|
||||
OtlpGrpcSpanExporter.newBuilder().setChannel(inProcessChannel).build();
|
||||
exporter.shutdown();
|
||||
// TODO: This probably should not be retryable because we never restart the channel.
|
||||
assertThat(exporter.export(Collections.singletonList(span)))
|
||||
.isEqualTo(ResultCode.FAILED_RETRYABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExport_Cancelled() {
|
||||
fakeCollector.setReturnedStatus(io.grpc.Status.CANCELLED);
|
||||
OtlpGrpcSpanExporter exporter =
|
||||
OtlpGrpcSpanExporter.newBuilder().setChannel(inProcessChannel).build();
|
||||
try {
|
||||
assertThat(exporter.export(Collections.singletonList(generateFakeSpan())))
|
||||
.isEqualTo(ResultCode.FAILED_RETRYABLE);
|
||||
} finally {
|
||||
exporter.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExport_DeadlineExceeded() {
|
||||
fakeCollector.setReturnedStatus(io.grpc.Status.DEADLINE_EXCEEDED);
|
||||
OtlpGrpcSpanExporter exporter =
|
||||
OtlpGrpcSpanExporter.newBuilder().setChannel(inProcessChannel).build();
|
||||
try {
|
||||
assertThat(exporter.export(Collections.singletonList(generateFakeSpan())))
|
||||
.isEqualTo(ResultCode.FAILED_RETRYABLE);
|
||||
} finally {
|
||||
exporter.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExport_ResourceExhausted() {
|
||||
fakeCollector.setReturnedStatus(io.grpc.Status.RESOURCE_EXHAUSTED);
|
||||
OtlpGrpcSpanExporter exporter =
|
||||
OtlpGrpcSpanExporter.newBuilder().setChannel(inProcessChannel).build();
|
||||
try {
|
||||
assertThat(exporter.export(Collections.singletonList(generateFakeSpan())))
|
||||
.isEqualTo(ResultCode.FAILED_RETRYABLE);
|
||||
} finally {
|
||||
exporter.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExport_OutOfRange() {
|
||||
fakeCollector.setReturnedStatus(io.grpc.Status.OUT_OF_RANGE);
|
||||
OtlpGrpcSpanExporter exporter =
|
||||
OtlpGrpcSpanExporter.newBuilder().setChannel(inProcessChannel).build();
|
||||
try {
|
||||
assertThat(exporter.export(Collections.singletonList(generateFakeSpan())))
|
||||
.isEqualTo(ResultCode.FAILED_RETRYABLE);
|
||||
} finally {
|
||||
exporter.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExport_Unavailable() {
|
||||
fakeCollector.setReturnedStatus(io.grpc.Status.UNAVAILABLE);
|
||||
OtlpGrpcSpanExporter exporter =
|
||||
OtlpGrpcSpanExporter.newBuilder().setChannel(inProcessChannel).build();
|
||||
try {
|
||||
assertThat(exporter.export(Collections.singletonList(generateFakeSpan())))
|
||||
.isEqualTo(ResultCode.FAILED_RETRYABLE);
|
||||
} finally {
|
||||
exporter.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExport_DataLoss() {
|
||||
fakeCollector.setReturnedStatus(io.grpc.Status.DATA_LOSS);
|
||||
OtlpGrpcSpanExporter exporter =
|
||||
OtlpGrpcSpanExporter.newBuilder().setChannel(inProcessChannel).build();
|
||||
try {
|
||||
assertThat(exporter.export(Collections.singletonList(generateFakeSpan())))
|
||||
.isEqualTo(ResultCode.FAILED_RETRYABLE);
|
||||
} finally {
|
||||
exporter.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExport_PermissionDenied() {
|
||||
fakeCollector.setReturnedStatus(io.grpc.Status.PERMISSION_DENIED);
|
||||
OtlpGrpcSpanExporter exporter =
|
||||
OtlpGrpcSpanExporter.newBuilder().setChannel(inProcessChannel).build();
|
||||
try {
|
||||
assertThat(exporter.export(Collections.singletonList(generateFakeSpan())))
|
||||
.isEqualTo(ResultCode.FAILED_NOT_RETRYABLE);
|
||||
} finally {
|
||||
exporter.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
private static SpanData generateFakeSpan() {
|
||||
long duration = TimeUnit.MILLISECONDS.toNanos(900);
|
||||
long startNs = TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis());
|
||||
long endNs = startNs + duration;
|
||||
return SpanData.newBuilder()
|
||||
.setHasEnded(true)
|
||||
.setTraceId(TraceId.fromLowerBase16(TRACE_ID, 0))
|
||||
.setSpanId(SpanId.fromLowerBase16(SPAN_ID, 0))
|
||||
.setName("GET /api/endpoint")
|
||||
.setStartEpochNanos(startNs)
|
||||
.setEndEpochNanos(endNs)
|
||||
.setStatus(Status.OK)
|
||||
.setKind(Kind.SERVER)
|
||||
.setLinks(Collections.<Link>emptyList())
|
||||
.setTotalRecordedLinks(0)
|
||||
.setTotalRecordedEvents(0)
|
||||
.build();
|
||||
}
|
||||
|
||||
private static final class FakeCollector extends TraceServiceGrpc.TraceServiceImplBase {
|
||||
private final List<ResourceSpans> receivedSpans = new ArrayList<>();
|
||||
private io.grpc.Status returnedStatus = io.grpc.Status.OK;
|
||||
|
||||
@Override
|
||||
public void export(
|
||||
ExportTraceServiceRequest request,
|
||||
io.grpc.stub.StreamObserver<ExportTraceServiceResponse> responseObserver) {
|
||||
receivedSpans.addAll(request.getResourceSpansList());
|
||||
responseObserver.onNext(ExportTraceServiceResponse.newBuilder().build());
|
||||
if (!returnedStatus.isOk()) {
|
||||
if (returnedStatus.getCode() == Code.DEADLINE_EXCEEDED) {
|
||||
// Do not call onCompleted to simulate a deadline exceeded.
|
||||
return;
|
||||
}
|
||||
responseObserver.onError(returnedStatus.asRuntimeException());
|
||||
return;
|
||||
}
|
||||
responseObserver.onCompleted();
|
||||
}
|
||||
|
||||
List<ResourceSpans> getReceivedSpans() {
|
||||
return receivedSpans;
|
||||
}
|
||||
|
||||
void setReturnedStatus(io.grpc.Status returnedStatus) {
|
||||
this.returnedStatus = returnedStatus;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright 2019, OpenTelemetry Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.opentelemetry.exporters.otlp;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import io.opentelemetry.proto.common.v1.AttributeKeyValue;
|
||||
import io.opentelemetry.proto.common.v1.AttributeKeyValue.ValueType;
|
||||
import io.opentelemetry.sdk.resources.Resource;
|
||||
import io.opentelemetry.trace.AttributeValue;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link ResourceAdapter}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class ResourceAdapterTest {
|
||||
@Test
|
||||
public void toProtoResource() {
|
||||
assertThat(
|
||||
ResourceAdapter.toProtoResource(
|
||||
Resource.create(
|
||||
ImmutableMap.of(
|
||||
"key_bool",
|
||||
AttributeValue.booleanAttributeValue(true),
|
||||
"key_string",
|
||||
AttributeValue.stringAttributeValue("string"),
|
||||
"key_int",
|
||||
AttributeValue.longAttributeValue(100),
|
||||
"key_double",
|
||||
AttributeValue.doubleAttributeValue(100.3))))
|
||||
.getAttributesList())
|
||||
.containsExactly(
|
||||
AttributeKeyValue.newBuilder()
|
||||
.setKey("key_bool")
|
||||
.setBoolValue(true)
|
||||
.setType(ValueType.BOOL)
|
||||
.build(),
|
||||
AttributeKeyValue.newBuilder()
|
||||
.setKey("key_string")
|
||||
.setStringValue("string")
|
||||
.setType(ValueType.STRING)
|
||||
.build(),
|
||||
AttributeKeyValue.newBuilder()
|
||||
.setKey("key_int")
|
||||
.setIntValue(100)
|
||||
.setType(ValueType.INT)
|
||||
.build(),
|
||||
AttributeKeyValue.newBuilder()
|
||||
.setKey("key_double")
|
||||
.setDoubleValue(100.3)
|
||||
.setType(ValueType.DOUBLE)
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toProtoResource_Empty() {
|
||||
assertThat(ResourceAdapter.toProtoResource(Resource.getEmpty()))
|
||||
.isEqualTo(io.opentelemetry.proto.resource.v1.Resource.newBuilder().build());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,302 @@
|
|||
/*
|
||||
* Copyright 2019, OpenTelemetry Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.opentelemetry.exporters.otlp;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import io.opentelemetry.proto.common.v1.AttributeKeyValue;
|
||||
import io.opentelemetry.proto.common.v1.AttributeKeyValue.ValueType;
|
||||
import io.opentelemetry.proto.trace.v1.Span;
|
||||
import io.opentelemetry.proto.trace.v1.Span.SpanKind;
|
||||
import io.opentelemetry.proto.trace.v1.Status;
|
||||
import io.opentelemetry.proto.trace.v1.Status.StatusCode;
|
||||
import io.opentelemetry.sdk.trace.data.SpanData;
|
||||
import io.opentelemetry.sdk.trace.data.SpanData.Link;
|
||||
import io.opentelemetry.sdk.trace.data.SpanData.TimedEvent;
|
||||
import io.opentelemetry.trace.AttributeValue;
|
||||
import io.opentelemetry.trace.Span.Kind;
|
||||
import io.opentelemetry.trace.SpanContext;
|
||||
import io.opentelemetry.trace.SpanId;
|
||||
import io.opentelemetry.trace.TraceFlags;
|
||||
import io.opentelemetry.trace.TraceId;
|
||||
import io.opentelemetry.trace.TraceState;
|
||||
import java.util.Collections;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link ResourceAdapter}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class SpanAdapterTest {
|
||||
private static final byte[] TRACE_ID_BYTES =
|
||||
new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4};
|
||||
private static final TraceId TRACE_ID = TraceId.fromBytes(TRACE_ID_BYTES, 0);
|
||||
private static final byte[] SPAN_ID_BYTES = new byte[] {0, 0, 0, 0, 4, 3, 2, 1};
|
||||
private static final SpanId SPAN_ID = SpanId.fromBytes(SPAN_ID_BYTES, 0);
|
||||
private static final TraceState TRACE_STATE = TraceState.builder().build();
|
||||
private static final SpanContext SPAN_CONTEXT =
|
||||
SpanContext.create(
|
||||
TRACE_ID, SPAN_ID, TraceFlags.builder().setIsSampled(true).build(), TRACE_STATE);
|
||||
|
||||
@Test
|
||||
public void toProtoSpan() {
|
||||
Span span =
|
||||
SpanAdapter.toProtoSpan(
|
||||
SpanData.newBuilder()
|
||||
.setHasEnded(true)
|
||||
.setTraceId(TRACE_ID)
|
||||
.setSpanId(SPAN_ID)
|
||||
.setParentSpanId(SpanId.getInvalid())
|
||||
.setName("GET /api/endpoint")
|
||||
.setKind(Kind.SERVER)
|
||||
.setStartEpochNanos(12345)
|
||||
.setEndEpochNanos(12349)
|
||||
.setAttributes(
|
||||
Collections.singletonMap("key", AttributeValue.booleanAttributeValue(true)))
|
||||
.setTimedEvents(
|
||||
Collections.singletonList(
|
||||
TimedEvent.create(
|
||||
12347, "my_event", Collections.<String, AttributeValue>emptyMap())))
|
||||
.setTotalRecordedEvents(3)
|
||||
.setLinks(
|
||||
Collections.<io.opentelemetry.trace.Link>singletonList(
|
||||
Link.create(SPAN_CONTEXT)))
|
||||
.setTotalRecordedLinks(2)
|
||||
.setStatus(io.opentelemetry.trace.Status.OK)
|
||||
.build());
|
||||
|
||||
assertThat(span.getTraceId().toByteArray()).isEqualTo(TRACE_ID_BYTES);
|
||||
assertThat(span.getSpanId().toByteArray()).isEqualTo(SPAN_ID_BYTES);
|
||||
assertThat(span.getParentSpanId().toByteArray()).isEqualTo(new byte[] {0, 0, 0, 0, 0, 0, 0, 0});
|
||||
assertThat(span.getName()).isEqualTo("GET /api/endpoint");
|
||||
assertThat(span.getKind()).isEqualTo(SpanKind.SERVER);
|
||||
assertThat(span.getStartTimeUnixnano()).isEqualTo(12345);
|
||||
assertThat(span.getEndTimeUnixnano()).isEqualTo(12349);
|
||||
assertThat(span.getAttributesList())
|
||||
.containsExactly(
|
||||
AttributeKeyValue.newBuilder()
|
||||
.setKey("key")
|
||||
.setBoolValue(true)
|
||||
.setType(ValueType.BOOL)
|
||||
.build());
|
||||
// Fix this when we plugged dropped attributes.
|
||||
assertThat(span.getDroppedAttributesCount()).isEqualTo(0);
|
||||
assertThat(span.getEventsList())
|
||||
.containsExactly(
|
||||
Span.Event.newBuilder().setTimeUnixnano(12347).setName("my_event").build());
|
||||
assertThat(span.getDroppedEventsCount()).isEqualTo(2); // 3 - 1
|
||||
assertThat(span.getLinksList())
|
||||
.containsExactly(
|
||||
Span.Link.newBuilder()
|
||||
.setTraceId(ByteString.copyFrom(TRACE_ID_BYTES))
|
||||
.setSpanId(ByteString.copyFrom(SPAN_ID_BYTES))
|
||||
.build());
|
||||
assertThat(span.getDroppedLinksCount()).isEqualTo(1); // 2 - 1
|
||||
assertThat(span.getStatus()).isEqualTo(Status.newBuilder().setCode(StatusCode.Ok).build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toProtoSpanKind() {
|
||||
assertThat(SpanAdapter.toProtoSpanKind(Kind.INTERNAL)).isEqualTo(SpanKind.INTERNAL);
|
||||
assertThat(SpanAdapter.toProtoSpanKind(Kind.CLIENT)).isEqualTo(SpanKind.CLIENT);
|
||||
assertThat(SpanAdapter.toProtoSpanKind(Kind.SERVER)).isEqualTo(SpanKind.SERVER);
|
||||
assertThat(SpanAdapter.toProtoSpanKind(Kind.PRODUCER)).isEqualTo(SpanKind.PRODUCER);
|
||||
assertThat(SpanAdapter.toProtoSpanKind(Kind.CONSUMER)).isEqualTo(SpanKind.CONSUMER);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toProtoStatus() {
|
||||
assertThat(SpanAdapter.toStatusProto(io.opentelemetry.trace.Status.OK))
|
||||
.isEqualTo(Status.newBuilder().setCode(StatusCode.Ok).build());
|
||||
assertThat(
|
||||
SpanAdapter.toStatusProto(
|
||||
io.opentelemetry.trace.Status.CANCELLED.withDescription("CANCELLED")))
|
||||
.isEqualTo(
|
||||
Status.newBuilder().setCode(StatusCode.Cancelled).setMessage("CANCELLED").build());
|
||||
assertThat(
|
||||
SpanAdapter.toStatusProto(
|
||||
io.opentelemetry.trace.Status.UNKNOWN.withDescription("UNKNOWN")))
|
||||
.isEqualTo(
|
||||
Status.newBuilder().setCode(StatusCode.UnknownError).setMessage("UNKNOWN").build());
|
||||
assertThat(
|
||||
SpanAdapter.toStatusProto(
|
||||
io.opentelemetry.trace.Status.INVALID_ARGUMENT.withDescription("INVALID_ARGUMENT")))
|
||||
.isEqualTo(
|
||||
Status.newBuilder()
|
||||
.setCode(StatusCode.InvalidArgument)
|
||||
.setMessage("INVALID_ARGUMENT")
|
||||
.build());
|
||||
assertThat(
|
||||
SpanAdapter.toStatusProto(
|
||||
io.opentelemetry.trace.Status.DEADLINE_EXCEEDED.withDescription(
|
||||
"DEADLINE_EXCEEDED")))
|
||||
.isEqualTo(
|
||||
Status.newBuilder()
|
||||
.setCode(StatusCode.DeadlineExceeded)
|
||||
.setMessage("DEADLINE_EXCEEDED")
|
||||
.build());
|
||||
assertThat(
|
||||
SpanAdapter.toStatusProto(
|
||||
io.opentelemetry.trace.Status.NOT_FOUND.withDescription("NOT_FOUND")))
|
||||
.isEqualTo(
|
||||
Status.newBuilder().setCode(StatusCode.NotFound).setMessage("NOT_FOUND").build());
|
||||
assertThat(
|
||||
SpanAdapter.toStatusProto(
|
||||
io.opentelemetry.trace.Status.ALREADY_EXISTS.withDescription("ALREADY_EXISTS")))
|
||||
.isEqualTo(
|
||||
Status.newBuilder()
|
||||
.setCode(StatusCode.AlreadyExists)
|
||||
.setMessage("ALREADY_EXISTS")
|
||||
.build());
|
||||
assertThat(
|
||||
SpanAdapter.toStatusProto(
|
||||
io.opentelemetry.trace.Status.PERMISSION_DENIED.withDescription(
|
||||
"PERMISSION_DENIED")))
|
||||
.isEqualTo(
|
||||
Status.newBuilder()
|
||||
.setCode(StatusCode.PermissionDenied)
|
||||
.setMessage("PERMISSION_DENIED")
|
||||
.build());
|
||||
assertThat(
|
||||
SpanAdapter.toStatusProto(
|
||||
io.opentelemetry.trace.Status.RESOURCE_EXHAUSTED.withDescription(
|
||||
"RESOURCE_EXHAUSTED")))
|
||||
.isEqualTo(
|
||||
Status.newBuilder()
|
||||
.setCode(StatusCode.ResourceExhausted)
|
||||
.setMessage("RESOURCE_EXHAUSTED")
|
||||
.build());
|
||||
assertThat(
|
||||
SpanAdapter.toStatusProto(
|
||||
io.opentelemetry.trace.Status.FAILED_PRECONDITION.withDescription(
|
||||
"FAILED_PRECONDITION")))
|
||||
.isEqualTo(
|
||||
Status.newBuilder()
|
||||
.setCode(StatusCode.FailedPrecondition)
|
||||
.setMessage("FAILED_PRECONDITION")
|
||||
.build());
|
||||
assertThat(
|
||||
SpanAdapter.toStatusProto(
|
||||
io.opentelemetry.trace.Status.ABORTED.withDescription("ABORTED")))
|
||||
.isEqualTo(Status.newBuilder().setCode(StatusCode.Aborted).setMessage("ABORTED").build());
|
||||
assertThat(
|
||||
SpanAdapter.toStatusProto(
|
||||
io.opentelemetry.trace.Status.OUT_OF_RANGE.withDescription("OUT_OF_RANGE")))
|
||||
.isEqualTo(
|
||||
Status.newBuilder().setCode(StatusCode.OutOfRange).setMessage("OUT_OF_RANGE").build());
|
||||
assertThat(
|
||||
SpanAdapter.toStatusProto(
|
||||
io.opentelemetry.trace.Status.UNIMPLEMENTED.withDescription("UNIMPLEMENTED")))
|
||||
.isEqualTo(
|
||||
Status.newBuilder()
|
||||
.setCode(StatusCode.Unimplemented)
|
||||
.setMessage("UNIMPLEMENTED")
|
||||
.build());
|
||||
assertThat(
|
||||
SpanAdapter.toStatusProto(
|
||||
io.opentelemetry.trace.Status.INTERNAL.withDescription("INTERNAL")))
|
||||
.isEqualTo(
|
||||
Status.newBuilder().setCode(StatusCode.InternalError).setMessage("INTERNAL").build());
|
||||
assertThat(
|
||||
SpanAdapter.toStatusProto(
|
||||
io.opentelemetry.trace.Status.UNAVAILABLE.withDescription("UNAVAILABLE")))
|
||||
.isEqualTo(
|
||||
Status.newBuilder().setCode(StatusCode.Unavailable).setMessage("UNAVAILABLE").build());
|
||||
assertThat(
|
||||
SpanAdapter.toStatusProto(
|
||||
io.opentelemetry.trace.Status.DATA_LOSS.withDescription("DATA_LOSS")))
|
||||
.isEqualTo(
|
||||
Status.newBuilder().setCode(StatusCode.DataLoss).setMessage("DATA_LOSS").build());
|
||||
assertThat(
|
||||
SpanAdapter.toStatusProto(
|
||||
io.opentelemetry.trace.Status.UNAUTHENTICATED.withDescription("UNAUTHENTICATED")))
|
||||
.isEqualTo(
|
||||
Status.newBuilder()
|
||||
.setCode(StatusCode.Unauthenticated)
|
||||
.setMessage("UNAUTHENTICATED")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toProtoSpanEvent_WithoutAttributes() {
|
||||
assertThat(
|
||||
SpanAdapter.toProtoSpanEvent(
|
||||
TimedEvent.create(
|
||||
12345,
|
||||
"test_without_attributes",
|
||||
Collections.<String, AttributeValue>emptyMap())))
|
||||
.isEqualTo(
|
||||
Span.Event.newBuilder()
|
||||
.setTimeUnixnano(12345)
|
||||
.setName("test_without_attributes")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toProtoSpanEvent_WithAttributes() {
|
||||
assertThat(
|
||||
SpanAdapter.toProtoSpanEvent(
|
||||
TimedEvent.create(
|
||||
12345,
|
||||
"test_with_attributes",
|
||||
Collections.singletonMap(
|
||||
"key_string", AttributeValue.stringAttributeValue("string")))))
|
||||
.isEqualTo(
|
||||
Span.Event.newBuilder()
|
||||
.setTimeUnixnano(12345)
|
||||
.setName("test_with_attributes")
|
||||
.addAttributes(
|
||||
AttributeKeyValue.newBuilder()
|
||||
.setKey("key_string")
|
||||
.setStringValue("string")
|
||||
.setType(ValueType.STRING)
|
||||
.build())
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toProtoSpanLink_WithoutAttributes() {
|
||||
assertThat(SpanAdapter.toProtoSpanLink(Link.create(SPAN_CONTEXT)))
|
||||
.isEqualTo(
|
||||
Span.Link.newBuilder()
|
||||
.setTraceId(ByteString.copyFrom(TRACE_ID_BYTES))
|
||||
.setSpanId(ByteString.copyFrom(SPAN_ID_BYTES))
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toProtoSpanLink_WithAttributes() {
|
||||
assertThat(
|
||||
SpanAdapter.toProtoSpanLink(
|
||||
Link.create(
|
||||
SPAN_CONTEXT,
|
||||
Collections.singletonMap(
|
||||
"key_string", AttributeValue.stringAttributeValue("string")))))
|
||||
.isEqualTo(
|
||||
Span.Link.newBuilder()
|
||||
.setTraceId(ByteString.copyFrom(TRACE_ID_BYTES))
|
||||
.setSpanId(ByteString.copyFrom(SPAN_ID_BYTES))
|
||||
.addAttributes(
|
||||
AttributeKeyValue.newBuilder()
|
||||
.setKey("key_string")
|
||||
.setStringValue("string")
|
||||
.setType(ValueType.STRING)
|
||||
.build())
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,10 @@ description = 'OpenTelemetry Proto'
|
|||
ext.moduleName = 'io.opentelemetry.proto'
|
||||
|
||||
dependencies {
|
||||
api libraries.protobuf
|
||||
api libraries.protobuf,
|
||||
libraries.grpc_api,
|
||||
libraries.grpc_protobuf,
|
||||
libraries.grpc_stub
|
||||
|
||||
signature "org.codehaus.mojo.signature:java17:1.0@signature"
|
||||
signature "net.sf.androidscents.signature:android-api-level-14:4.0_r4@signature"
|
||||
|
|
@ -28,6 +31,12 @@ protobuf {
|
|||
// The artifact spec for the Protobuf Compiler
|
||||
artifact = "com.google.protobuf:protoc:${protocVersion}"
|
||||
}
|
||||
plugins {
|
||||
grpc { artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}" }
|
||||
}
|
||||
generateProtoTasks {
|
||||
all()*.plugins { grpc {} }
|
||||
}
|
||||
}
|
||||
|
||||
// IntelliJ complains that the generated classes are not found, ask IntelliJ to include the
|
||||
|
|
|
|||
Loading…
Reference in New Issue