From 3d51b5bda0589abaa1bd40169673624165abc830 Mon Sep 17 00:00:00 2001 From: Yang Song Date: Mon, 24 Sep 2018 16:32:55 -0700 Subject: Exporter/OCAgent: Move TraceProtoUtils to exporter. (#1470) --- CHANGELOG.md | 2 - RELEASING.md | 1 - all/build.gradle | 2 - build.gradle | 1 - buildscripts/import-control.xml | 9 +- contrib/opencensus_proto_util/README.md | 24 -- contrib/opencensus_proto_util/build.gradle | 16 - .../opencensus/proto/util/TraceProtoUtils.java | 382 --------------------- .../opencensus/proto/util/TraceProtoUtilsTest.java | 318 ----------------- .../exporter/trace/ocagent/TraceProtoUtils.java | 382 +++++++++++++++++++++ .../trace/ocagent/TraceProtoUtilsTest.java | 318 +++++++++++++++++ settings.gradle | 3 - 12 files changed, 703 insertions(+), 755 deletions(-) delete mode 100644 contrib/opencensus_proto_util/README.md delete mode 100644 contrib/opencensus_proto_util/build.gradle delete mode 100644 contrib/opencensus_proto_util/src/main/java/io/opencensus/contrib/opencensus/proto/util/TraceProtoUtils.java delete mode 100644 contrib/opencensus_proto_util/src/test/java/io/opencensus/contrib/opencensus/proto/util/TraceProtoUtilsTest.java create mode 100644 exporters/trace/ocagent/src/main/java/io/opencensus/exporter/trace/ocagent/TraceProtoUtils.java create mode 100644 exporters/trace/ocagent/src/test/java/io/opencensus/exporter/trace/ocagent/TraceProtoUtilsTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index b3fa3020..352c2419 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,6 @@ - Add `createWithSender` to `JaegerTraceExporter` to allow use of `HttpSender` with extra configurations. - Add an API `Functions.returnToString()`. -- Add `opencensus-contrib-opencensus-proto-util` that has helper utilities to convert between - Java data models and protos. - Migrate to new Stackdriver Kubernetes monitored resource. This could be a breaking change if you are using `gke_container` resources. For more info, https://cloud.google.com/monitoring/kubernetes-engine/migration#incompatible diff --git a/RELEASING.md b/RELEASING.md index 2b4aa512..6d896d44 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -210,7 +210,6 @@ $ README_FILES=( contrib/log_correlation/log4j2/README.md contrib/log_correlation/stackdriver/README.md contrib/monitored_resource_util/README.md - contrib/opencensus_proto_util/README.md contrib/spring/README.md contrib/spring_sleuth_v1x/README.md contrib/zpages/README.md diff --git a/all/build.gradle b/all/build.gradle index 66e6a893..e3a0c4c6 100644 --- a/all/build.gradle +++ b/all/build.gradle @@ -15,7 +15,6 @@ def subprojects = [ project(':opencensus-contrib-log-correlation-log4j2'), project(':opencensus-contrib-log-correlation-stackdriver'), project(':opencensus-contrib-monitored-resource-util'), - project(':opencensus-contrib-opencensus-proto-util'), project(':opencensus-contrib-spring'), project(':opencensus-contrib-spring-sleuth-v1x'), project(':opencensus-contrib-zpages'), @@ -42,7 +41,6 @@ def subprojects_javadoc = [ project(':opencensus-contrib-log-correlation-log4j2'), project(':opencensus-contrib-log-correlation-stackdriver'), project(':opencensus-contrib-monitored-resource-util'), - project(':opencensus-contrib-opencensus-proto-util'), project(':opencensus-contrib-spring'), project(':opencensus-contrib-spring-sleuth-v1x'), project(':opencensus-contrib-zpages'), diff --git a/build.gradle b/build.gradle index e3bcb688..3c675066 100644 --- a/build.gradle +++ b/build.gradle @@ -423,7 +423,6 @@ subprojects { 'opencensus-contrib-log-correlation-log4j2', 'opencensus-contrib-log-correlation-stackdriver', 'opencensus-contrib-monitored-resource-util', - 'opencensus-contrib-opencensus-proto-util', 'opencensus-contrib-spring', 'opencensus-contrib-spring-sleuth-v1x', 'opencensus-contrib-zpages', diff --git a/buildscripts/import-control.xml b/buildscripts/import-control.xml index 2467e35c..b4c7410b 100644 --- a/buildscripts/import-control.xml +++ b/buildscripts/import-control.xml @@ -134,12 +134,6 @@ General guidelines on imports: - - - - - - @@ -175,8 +169,11 @@ General guidelines on imports: + + + diff --git a/contrib/opencensus_proto_util/README.md b/contrib/opencensus_proto_util/README.md deleted file mode 100644 index e495121d..00000000 --- a/contrib/opencensus_proto_util/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# OpenCensus Proto Util - -The *OpenCensus Proto Util for Java* is a collection of utilities for converting OpenCensus Java -data models to OpenCensus proto data models. - -## Quickstart - -### Add the dependencies to your project - -For Maven add to your `pom.xml`: -```xml - - - io.opencensus - opencensus-contrib-opencensus-proto-util - 0.17.0 - - -``` - -For Gradle add to your dependencies: -```gradle -compile 'io.opencensus:opencensus-contrib-opencensus-proto-util:0.17.0' -``` diff --git a/contrib/opencensus_proto_util/build.gradle b/contrib/opencensus_proto_util/build.gradle deleted file mode 100644 index 8a622246..00000000 --- a/contrib/opencensus_proto_util/build.gradle +++ /dev/null @@ -1,16 +0,0 @@ -description = 'OpenCensus Proto Util' - -apply plugin: 'java' - -[compileJava, compileTestJava].each() { - it.sourceCompatibility = 1.7 - it.targetCompatibility = 1.7 -} - -dependencies { - compile project(':opencensus-api'), - libraries.opencensus_proto - - signature "org.codehaus.mojo.signature:java17:1.0@signature" - signature "net.sf.androidscents.signature:android-api-level-14:4.0_r4@signature" -} diff --git a/contrib/opencensus_proto_util/src/main/java/io/opencensus/contrib/opencensus/proto/util/TraceProtoUtils.java b/contrib/opencensus_proto_util/src/main/java/io/opencensus/contrib/opencensus/proto/util/TraceProtoUtils.java deleted file mode 100644 index f2ecd01a..00000000 --- a/contrib/opencensus_proto_util/src/main/java/io/opencensus/contrib/opencensus/proto/util/TraceProtoUtils.java +++ /dev/null @@ -1,382 +0,0 @@ -/* - * Copyright 2018, OpenCensus 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.opencensus.contrib.opencensus.proto.util; - -import com.google.common.annotations.VisibleForTesting; -import com.google.protobuf.BoolValue; -import com.google.protobuf.ByteString; -import com.google.protobuf.UInt32Value; -import io.opencensus.common.Function; -import io.opencensus.common.Functions; -import io.opencensus.common.Timestamp; -import io.opencensus.proto.trace.v1.AttributeValue; -import io.opencensus.proto.trace.v1.ConstantSampler; -import io.opencensus.proto.trace.v1.ProbabilitySampler; -import io.opencensus.proto.trace.v1.Span; -import io.opencensus.proto.trace.v1.Span.Attributes; -import io.opencensus.proto.trace.v1.Span.Link; -import io.opencensus.proto.trace.v1.Span.Links; -import io.opencensus.proto.trace.v1.Span.SpanKind; -import io.opencensus.proto.trace.v1.Span.TimeEvent; -import io.opencensus.proto.trace.v1.Span.TimeEvent.MessageEvent; -import io.opencensus.proto.trace.v1.Span.Tracestate; -import io.opencensus.proto.trace.v1.Span.Tracestate.Entry; -import io.opencensus.proto.trace.v1.Status; -import io.opencensus.proto.trace.v1.TraceConfig; -import io.opencensus.proto.trace.v1.TruncatableString; -import io.opencensus.trace.Annotation; -import io.opencensus.trace.MessageEvent.Type; -import io.opencensus.trace.Sampler; -import io.opencensus.trace.Span.Kind; -import io.opencensus.trace.SpanContext; -import io.opencensus.trace.SpanId; -import io.opencensus.trace.TraceId; -import io.opencensus.trace.config.TraceParams; -import io.opencensus.trace.export.SpanData; -import io.opencensus.trace.export.SpanData.TimedEvent; -import io.opencensus.trace.export.SpanData.TimedEvents; -import io.opencensus.trace.samplers.Samplers; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/*>>> -import org.checkerframework.checker.nullness.qual.Nullable; -*/ - -/** - * Utilities for converting the Tracing data models in OpenCensus Java to/from OpenCensus Proto. - * - * @since 0.17 - */ -public final class TraceProtoUtils { - - // Constant functions for AttributeValue. - private static final Function stringAttributeValueFunction = - new Function() { - @Override - public AttributeValue apply(String stringValue) { - return AttributeValue.newBuilder() - .setStringValue(toTruncatableStringProto(stringValue)) - .build(); - } - }; - - private static final Function - booleanAttributeValueFunction = - new Function() { - @Override - public AttributeValue apply(Boolean booleanValue) { - return AttributeValue.newBuilder().setBoolValue(booleanValue).build(); - } - }; - - private static final Function longAttributeValueFunction = - new Function() { - @Override - public AttributeValue apply(Long longValue) { - return AttributeValue.newBuilder().setIntValue(longValue).build(); - } - }; - - private static final Function doubleAttributeValueFunction = - new Function() { - @Override - public AttributeValue apply(Double doubleValue) { - return AttributeValue.newBuilder().setDoubleValue(doubleValue).build(); - } - }; - - /** - * Converts {@link SpanData} to {@link Span} proto. - * - * @param spanData the {@code SpanData}. - * @return proto representation of {@code Span}. - * @since 0.17 - */ - @SuppressWarnings("DefaultCharset") - public static Span toSpanProto(SpanData spanData) { - SpanContext spanContext = spanData.getContext(); - TraceId traceId = spanContext.getTraceId(); - SpanId spanId = spanContext.getSpanId(); - Span.Builder spanBuilder = - Span.newBuilder() - .setTraceId(toByteString(traceId.getBytes())) - .setSpanId(toByteString(spanId.getBytes())) - .setTracestate(toTracestateProto(spanContext.getTracestate())) - .setName(toTruncatableStringProto(spanData.getName())) - .setStartTime(toTimestampProto(spanData.getStartTimestamp())) - .setAttributes(toAttributesProto(spanData.getAttributes())) - .setTimeEvents( - toTimeEventsProto(spanData.getAnnotations(), spanData.getMessageEvents())) - .setLinks(toLinksProto(spanData.getLinks())); - - Kind kind = spanData.getKind(); - if (kind != null) { - spanBuilder.setKind(toSpanKindProto(kind)); - } - - io.opencensus.trace.Status status = spanData.getStatus(); - if (status != null) { - spanBuilder.setStatus(toStatusProto(status)); - } - - Timestamp end = spanData.getEndTimestamp(); - if (end != null) { - spanBuilder.setEndTime(toTimestampProto(end)); - } - - Integer childSpanCount = spanData.getChildSpanCount(); - if (childSpanCount != null) { - spanBuilder.setChildSpanCount(UInt32Value.newBuilder().setValue(childSpanCount).build()); - } - - Boolean hasRemoteParent = spanData.getHasRemoteParent(); - if (hasRemoteParent != null) { - spanBuilder.setSameProcessAsParentSpan(BoolValue.of(!hasRemoteParent)); - } - - SpanId parentSpanId = spanData.getParentSpanId(); - if (parentSpanId != null && parentSpanId.isValid()) { - spanBuilder.setParentSpanId(toByteString(parentSpanId.getBytes())); - } - - return spanBuilder.build(); - } - - @VisibleForTesting - static ByteString toByteString(byte[] bytes) { - return ByteString.copyFrom(bytes); - } - - private static Tracestate toTracestateProto(io.opencensus.trace.Tracestate tracestate) { - return Tracestate.newBuilder().addAllEntries(toEntriesProto(tracestate.getEntries())).build(); - } - - private static List toEntriesProto(List entries) { - List entriesProto = new ArrayList(); - for (io.opencensus.trace.Tracestate.Entry entry : entries) { - entriesProto.add( - Entry.newBuilder().setKey(entry.getKey()).setValue(entry.getValue()).build()); - } - return entriesProto; - } - - private static SpanKind toSpanKindProto(Kind kind) { - switch (kind) { - case CLIENT: - return SpanKind.CLIENT; - case SERVER: - return SpanKind.SERVER; - } - return SpanKind.UNRECOGNIZED; - } - - private static Span.TimeEvents toTimeEventsProto( - TimedEvents annotationTimedEvents, - TimedEvents messageEventTimedEvents) { - Span.TimeEvents.Builder timeEventsBuilder = Span.TimeEvents.newBuilder(); - timeEventsBuilder.setDroppedAnnotationsCount(annotationTimedEvents.getDroppedEventsCount()); - for (TimedEvent annotation : annotationTimedEvents.getEvents()) { - timeEventsBuilder.addTimeEvent(toTimeAnnotationProto(annotation)); - } - timeEventsBuilder.setDroppedMessageEventsCount(messageEventTimedEvents.getDroppedEventsCount()); - for (TimedEvent networkEvent : - messageEventTimedEvents.getEvents()) { - timeEventsBuilder.addTimeEvent(toTimeMessageEventProto(networkEvent)); - } - return timeEventsBuilder.build(); - } - - private static TimeEvent toTimeAnnotationProto(TimedEvent timedEvent) { - TimeEvent.Builder timeEventBuilder = - TimeEvent.newBuilder().setTime(toTimestampProto(timedEvent.getTimestamp())); - Annotation annotation = timedEvent.getEvent(); - timeEventBuilder.setAnnotation( - TimeEvent.Annotation.newBuilder() - .setDescription(toTruncatableStringProto(annotation.getDescription())) - .setAttributes(toAttributesBuilderProto(annotation.getAttributes(), 0)) - .build()); - return timeEventBuilder.build(); - } - - private static TimeEvent toTimeMessageEventProto( - TimedEvent timedEvent) { - TimeEvent.Builder timeEventBuilder = - TimeEvent.newBuilder().setTime(toTimestampProto(timedEvent.getTimestamp())); - io.opencensus.trace.MessageEvent messageEvent = timedEvent.getEvent(); - timeEventBuilder.setMessageEvent( - TimeEvent.MessageEvent.newBuilder() - .setId(messageEvent.getMessageId()) - .setCompressedSize(messageEvent.getCompressedMessageSize()) - .setUncompressedSize(messageEvent.getUncompressedMessageSize()) - .setType(toMessageEventTypeProto(messageEvent)) - .build()); - return timeEventBuilder.build(); - } - - private static TimeEvent.MessageEvent.Type toMessageEventTypeProto( - io.opencensus.trace.MessageEvent messageEvent) { - if (messageEvent.getType() == Type.RECEIVED) { - return MessageEvent.Type.RECEIVED; - } else { - return MessageEvent.Type.SENT; - } - } - - private static Attributes toAttributesProto( - io.opencensus.trace.export.SpanData.Attributes attributes) { - Attributes.Builder attributesBuilder = - toAttributesBuilderProto( - attributes.getAttributeMap(), attributes.getDroppedAttributesCount()); - return attributesBuilder.build(); - } - - private static Attributes.Builder toAttributesBuilderProto( - Map attributes, int droppedAttributesCount) { - Attributes.Builder attributesBuilder = - Attributes.newBuilder().setDroppedAttributesCount(droppedAttributesCount); - for (Map.Entry label : attributes.entrySet()) { - AttributeValue value = toAttributeValueProto(label.getValue()); - if (value != null) { - attributesBuilder.putAttributeMap(label.getKey(), value); - } - } - return attributesBuilder; - } - - @javax.annotation.Nullable - private static AttributeValue toAttributeValueProto( - io.opencensus.trace.AttributeValue attributeValue) { - return attributeValue.match( - stringAttributeValueFunction, - booleanAttributeValueFunction, - longAttributeValueFunction, - doubleAttributeValueFunction, - Functions.returnNull()); - } - - private static Status toStatusProto(io.opencensus.trace.Status status) { - Status.Builder statusBuilder = Status.newBuilder().setCode(status.getCanonicalCode().value()); - if (status.getDescription() != null) { - statusBuilder.setMessage(status.getDescription()); - } - return statusBuilder.build(); - } - - @VisibleForTesting - static TruncatableString toTruncatableStringProto(String string) { - return TruncatableString.newBuilder().setValue(string).setTruncatedByteCount(0).build(); - } - - private static com.google.protobuf.Timestamp toTimestampProto(Timestamp timestamp) { - return com.google.protobuf.Timestamp.newBuilder() - .setSeconds(timestamp.getSeconds()) - .setNanos(timestamp.getNanos()) - .build(); - } - - private static Link.Type toLinkTypeProto(io.opencensus.trace.Link.Type type) { - if (type == io.opencensus.trace.Link.Type.PARENT_LINKED_SPAN) { - return Link.Type.PARENT_LINKED_SPAN; - } else { - return Link.Type.CHILD_LINKED_SPAN; - } - } - - @SuppressWarnings("DefaultCharset") - private static Link toLinkProto(io.opencensus.trace.Link link) { - return Link.newBuilder() - .setTraceId(toByteString(link.getTraceId().getBytes())) - .setSpanId(toByteString(link.getSpanId().getBytes())) - .setType(toLinkTypeProto(link.getType())) - .setAttributes(toAttributesBuilderProto(link.getAttributes(), 0)) - .build(); - } - - private static Links toLinksProto(io.opencensus.trace.export.SpanData.Links links) { - final Links.Builder linksBuilder = - Links.newBuilder().setDroppedLinksCount(links.getDroppedLinksCount()); - for (io.opencensus.trace.Link link : links.getLinks()) { - linksBuilder.addLink(toLinkProto(link)); - } - return linksBuilder.build(); - } - - /** - * Converts {@link TraceParams} to {@link TraceConfig}. - * - * @param traceParams the {@code TraceParams}. - * @return {@code TraceConfig}. - * @since 0.17 - */ - public static TraceConfig toTraceConfigProto(TraceParams traceParams) { - TraceConfig.Builder traceConfigProtoBuilder = TraceConfig.newBuilder(); - Sampler librarySampler = traceParams.getSampler(); - - if (Samplers.alwaysSample().equals(librarySampler)) { - traceConfigProtoBuilder.setConstantSampler( - ConstantSampler.newBuilder().setDecision(true).build()); - } else if (Samplers.neverSample().equals(librarySampler)) { - traceConfigProtoBuilder.setConstantSampler( - ConstantSampler.newBuilder().setDecision(false).build()); - } else { - // TODO: consider exposing the sampling probability of ProbabilitySampler. - double samplingProbability = parseSamplingProbability(librarySampler); - traceConfigProtoBuilder.setProbabilitySampler( - ProbabilitySampler.newBuilder().setSamplingProbability(samplingProbability).build()); - } // TODO: add support for RateLimitingSampler. - - return traceConfigProtoBuilder.build(); - } - - private static double parseSamplingProbability(Sampler sampler) { - String description = sampler.getDescription(); - // description follows format "ProbabilitySampler{%.6f}", samplingProbability. - int leftParenIndex = description.indexOf("{"); - int rightParenIndex = description.indexOf("}"); - return Double.parseDouble(description.substring(leftParenIndex + 1, rightParenIndex)); - } - - /** - * Converts {@link TraceConfig} to {@link TraceParams}. - * - * @param traceConfigProto {@code TraceConfig}. - * @param currentTraceParams current {@code TraceParams}. - * @return updated {@code TraceParams}. - * @since 0.17 - */ - public static TraceParams fromTraceConfigProto( - TraceConfig traceConfigProto, TraceParams currentTraceParams) { - TraceParams.Builder builder = currentTraceParams.toBuilder(); - if (traceConfigProto.hasConstantSampler()) { - ConstantSampler constantSampler = traceConfigProto.getConstantSampler(); - if (Boolean.TRUE.equals(constantSampler.getDecision())) { - builder.setSampler(Samplers.alwaysSample()); - } else { - builder.setSampler(Samplers.neverSample()); - } - } else if (traceConfigProto.hasProbabilitySampler()) { - builder.setSampler( - Samplers.probabilitySampler( - traceConfigProto.getProbabilitySampler().getSamplingProbability())); - } // TODO: add support for RateLimitingSampler. - return builder.build(); - } - - private TraceProtoUtils() {} -} diff --git a/contrib/opencensus_proto_util/src/test/java/io/opencensus/contrib/opencensus/proto/util/TraceProtoUtilsTest.java b/contrib/opencensus_proto_util/src/test/java/io/opencensus/contrib/opencensus/proto/util/TraceProtoUtilsTest.java deleted file mode 100644 index 37908f6b..00000000 --- a/contrib/opencensus_proto_util/src/test/java/io/opencensus/contrib/opencensus/proto/util/TraceProtoUtilsTest.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright 2018, OpenCensus 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.opencensus.contrib.opencensus.proto.util; - -import static com.google.common.truth.Truth.assertThat; -import static io.opencensus.contrib.opencensus.proto.util.TraceProtoUtils.toByteString; -import static io.opencensus.contrib.opencensus.proto.util.TraceProtoUtils.toTruncatableStringProto; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.protobuf.BoolValue; -import com.google.protobuf.UInt32Value; -import io.opencensus.common.Timestamp; -import io.opencensus.proto.trace.v1.AttributeValue; -import io.opencensus.proto.trace.v1.ConstantSampler; -import io.opencensus.proto.trace.v1.ProbabilitySampler; -import io.opencensus.proto.trace.v1.Span; -import io.opencensus.proto.trace.v1.Span.SpanKind; -import io.opencensus.proto.trace.v1.Span.TimeEvent; -import io.opencensus.proto.trace.v1.Span.TimeEvent.MessageEvent; -import io.opencensus.proto.trace.v1.TraceConfig; -import io.opencensus.trace.Annotation; -import io.opencensus.trace.Link; -import io.opencensus.trace.Sampler; -import io.opencensus.trace.Span.Kind; -import io.opencensus.trace.SpanContext; -import io.opencensus.trace.SpanId; -import io.opencensus.trace.Status; -import io.opencensus.trace.TraceId; -import io.opencensus.trace.TraceOptions; -import io.opencensus.trace.Tracestate; -import io.opencensus.trace.config.TraceParams; -import io.opencensus.trace.export.SpanData; -import io.opencensus.trace.export.SpanData.TimedEvent; -import io.opencensus.trace.export.SpanData.TimedEvents; -import io.opencensus.trace.samplers.Samplers; -import java.util.List; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Tests for {@link TraceProtoUtils}. */ -@RunWith(JUnit4.class) -public class TraceProtoUtilsTest { - - private static final TraceParams DEFAULT_PARAMS = TraceParams.DEFAULT; - - private static final Timestamp startTimestamp = Timestamp.create(123, 456); - private static final Timestamp eventTimestamp1 = Timestamp.create(123, 457); - private static final Timestamp eventTimestamp2 = Timestamp.create(123, 458); - private static final Timestamp eventTimestamp3 = Timestamp.create(123, 459); - private static final Timestamp endTimestamp = Timestamp.create(123, 460); - - private static final String TRACE_ID = "4bf92f3577b34da6a3ce929d0e0e4736"; - private static final String SPAN_ID = "24aa0b2d371f48c9"; - private static final String PARENT_SPAN_ID = "71da8d631536f5f1"; - private static final String SPAN_NAME = "MySpanName"; - private static final String ANNOTATION_TEXT = "MyAnnotationText"; - private static final String ATTRIBUTE_KEY_1 = "MyAttributeKey1"; - private static final String ATTRIBUTE_KEY_2 = "MyAttributeKey2"; - - private static final String FIRST_KEY = "key_1"; - private static final String SECOND_KEY = "key_2"; - private static final String FIRST_VALUE = "value.1"; - private static final String SECOND_VALUE = "value.2"; - private static final Tracestate multiValueTracestate = - Tracestate.builder().set(FIRST_KEY, FIRST_VALUE).set(SECOND_KEY, SECOND_VALUE).build(); - - private static final int DROPPED_ATTRIBUTES_COUNT = 1; - private static final int DROPPED_ANNOTATIONS_COUNT = 2; - private static final int DROPPED_NETWORKEVENTS_COUNT = 3; - private static final int DROPPED_LINKS_COUNT = 4; - private static final int CHILD_SPAN_COUNT = 13; - - private static final Annotation annotation = Annotation.fromDescription(ANNOTATION_TEXT); - private static final io.opencensus.trace.MessageEvent recvMessageEvent = - io.opencensus.trace.MessageEvent.builder(io.opencensus.trace.MessageEvent.Type.RECEIVED, 1) - .build(); - private static final io.opencensus.trace.MessageEvent sentMessageEvent = - io.opencensus.trace.MessageEvent.builder(io.opencensus.trace.MessageEvent.Type.SENT, 1) - .build(); - private static final Status status = Status.DEADLINE_EXCEEDED.withDescription("TooSlow"); - private static final SpanId parentSpanId = SpanId.fromLowerBase16(PARENT_SPAN_ID); - private static final SpanId spanId = SpanId.fromLowerBase16(SPAN_ID); - private static final TraceId traceId = TraceId.fromLowerBase16(TRACE_ID); - private static final TraceOptions traceOptions = TraceOptions.DEFAULT; - private static final SpanContext spanContext = - SpanContext.create(traceId, spanId, traceOptions, multiValueTracestate); - - private static final List> annotationsList = - ImmutableList.of( - SpanData.TimedEvent.create(eventTimestamp1, annotation), - SpanData.TimedEvent.create(eventTimestamp3, annotation)); - private static final List> networkEventsList = - ImmutableList.of( - SpanData.TimedEvent.create(eventTimestamp1, recvMessageEvent), - SpanData.TimedEvent.create(eventTimestamp2, sentMessageEvent)); - private static final List linksList = - ImmutableList.of(Link.fromSpanContext(spanContext, Link.Type.CHILD_LINKED_SPAN)); - - private static final SpanData.Attributes attributes = - SpanData.Attributes.create( - ImmutableMap.of( - ATTRIBUTE_KEY_1, - io.opencensus.trace.AttributeValue.longAttributeValue(10L), - ATTRIBUTE_KEY_2, - io.opencensus.trace.AttributeValue.booleanAttributeValue(true)), - DROPPED_ATTRIBUTES_COUNT); - private static final TimedEvents annotations = - TimedEvents.create(annotationsList, DROPPED_ANNOTATIONS_COUNT); - private static final TimedEvents messageEvents = - TimedEvents.create(networkEventsList, DROPPED_NETWORKEVENTS_COUNT); - private static final SpanData.Links links = SpanData.Links.create(linksList, DROPPED_LINKS_COUNT); - - @SuppressWarnings("DefaultCharset") - @Test - public void toSpanProto() { - SpanData spanData = - SpanData.create( - spanContext, - parentSpanId, - /* hasRemoteParent= */ false, - SPAN_NAME, - Kind.CLIENT, - startTimestamp, - attributes, - annotations, - messageEvents, - links, - CHILD_SPAN_COUNT, - status, - endTimestamp); - TimeEvent annotationTimeEvent1 = - TimeEvent.newBuilder() - .setAnnotation( - TimeEvent.Annotation.newBuilder() - .setDescription(toTruncatableStringProto(ANNOTATION_TEXT)) - .setAttributes(Span.Attributes.newBuilder().build()) - .build()) - .setTime( - com.google.protobuf.Timestamp.newBuilder() - .setSeconds(eventTimestamp1.getSeconds()) - .setNanos(eventTimestamp1.getNanos()) - .build()) - .build(); - TimeEvent annotationTimeEvent2 = - TimeEvent.newBuilder() - .setAnnotation( - TimeEvent.Annotation.newBuilder() - .setDescription(toTruncatableStringProto(ANNOTATION_TEXT)) - .setAttributes(Span.Attributes.newBuilder().build()) - .build()) - .setTime( - com.google.protobuf.Timestamp.newBuilder() - .setSeconds(eventTimestamp3.getSeconds()) - .setNanos(eventTimestamp3.getNanos()) - .build()) - .build(); - - TimeEvent sentTimeEvent = - TimeEvent.newBuilder() - .setMessageEvent( - TimeEvent.MessageEvent.newBuilder() - .setType(MessageEvent.Type.SENT) - .setId(sentMessageEvent.getMessageId())) - .setTime( - com.google.protobuf.Timestamp.newBuilder() - .setSeconds(eventTimestamp2.getSeconds()) - .setNanos(eventTimestamp2.getNanos()) - .build()) - .build(); - TimeEvent recvTimeEvent = - TimeEvent.newBuilder() - .setMessageEvent( - TimeEvent.MessageEvent.newBuilder() - .setType(MessageEvent.Type.RECEIVED) - .setId(recvMessageEvent.getMessageId())) - .setTime( - com.google.protobuf.Timestamp.newBuilder() - .setSeconds(eventTimestamp1.getSeconds()) - .setNanos(eventTimestamp1.getNanos()) - .build()) - .build(); - - Span.Links spanLinks = - Span.Links.newBuilder() - .setDroppedLinksCount(DROPPED_LINKS_COUNT) - .addLink( - Span.Link.newBuilder() - .setType(Span.Link.Type.CHILD_LINKED_SPAN) - .setTraceId(toByteString(traceId.getBytes())) - .setSpanId(toByteString(spanId.getBytes())) - .setAttributes(Span.Attributes.newBuilder().build()) - .build()) - .build(); - - io.opencensus.proto.trace.v1.Status spanStatus = - io.opencensus.proto.trace.v1.Status.newBuilder() - .setCode(com.google.rpc.Code.DEADLINE_EXCEEDED.getNumber()) - .setMessage("TooSlow") - .build(); - - com.google.protobuf.Timestamp startTime = - com.google.protobuf.Timestamp.newBuilder() - .setSeconds(startTimestamp.getSeconds()) - .setNanos(startTimestamp.getNanos()) - .build(); - com.google.protobuf.Timestamp endTime = - com.google.protobuf.Timestamp.newBuilder() - .setSeconds(endTimestamp.getSeconds()) - .setNanos(endTimestamp.getNanos()) - .build(); - - Span span = TraceProtoUtils.toSpanProto(spanData); - assertThat(span.getName()).isEqualTo(toTruncatableStringProto(SPAN_NAME)); - assertThat(span.getTraceId()).isEqualTo(toByteString(traceId.getBytes())); - assertThat(span.getSpanId()).isEqualTo(toByteString(spanId.getBytes())); - assertThat(span.getParentSpanId()).isEqualTo(toByteString(parentSpanId.getBytes())); - assertThat(span.getStartTime()).isEqualTo(startTime); - assertThat(span.getEndTime()).isEqualTo(endTime); - assertThat(span.getKind()).isEqualTo(SpanKind.CLIENT); - assertThat(span.getAttributes().getDroppedAttributesCount()) - .isEqualTo(DROPPED_ATTRIBUTES_COUNT); - // The generated attributes map contains more values (e.g. agent). We only test what we added. - assertThat(span.getAttributes().getAttributeMapMap()) - .containsEntry(ATTRIBUTE_KEY_1, AttributeValue.newBuilder().setIntValue(10L).build()); - assertThat(span.getAttributes().getAttributeMapMap()) - .containsEntry(ATTRIBUTE_KEY_2, AttributeValue.newBuilder().setBoolValue(true).build()); - assertThat(span.getTimeEvents().getDroppedMessageEventsCount()) - .isEqualTo(DROPPED_NETWORKEVENTS_COUNT); - assertThat(span.getTimeEvents().getDroppedAnnotationsCount()) - .isEqualTo(DROPPED_ANNOTATIONS_COUNT); - assertThat(span.getTimeEvents().getTimeEventList()) - .containsAllOf(annotationTimeEvent1, annotationTimeEvent2, sentTimeEvent, recvTimeEvent); - assertThat(span.getLinks()).isEqualTo(spanLinks); - assertThat(span.getStatus()).isEqualTo(spanStatus); - assertThat(span.getSameProcessAsParentSpan()).isEqualTo(BoolValue.of(true)); - assertThat(span.getChildSpanCount()) - .isEqualTo(UInt32Value.newBuilder().setValue(CHILD_SPAN_COUNT).build()); - } - - @Test - public void toTraceConfigProto_AlwaysSampler() { - assertThat(TraceProtoUtils.toTraceConfigProto(getTraceParams(Samplers.alwaysSample()))) - .isEqualTo( - TraceConfig.newBuilder() - .setConstantSampler(ConstantSampler.newBuilder().setDecision(true).build()) - .build()); - } - - @Test - public void toTraceConfigProto_NeverSampler() { - assertThat(TraceProtoUtils.toTraceConfigProto(getTraceParams(Samplers.neverSample()))) - .isEqualTo( - TraceConfig.newBuilder() - .setConstantSampler(ConstantSampler.newBuilder().setDecision(false).build()) - .build()); - } - - @Test - public void toTraceConfigProto_ProbabilitySampler() { - assertThat(TraceProtoUtils.toTraceConfigProto(getTraceParams(Samplers.probabilitySampler(0.5)))) - .isEqualTo( - TraceConfig.newBuilder() - .setProbabilitySampler( - ProbabilitySampler.newBuilder().setSamplingProbability(0.5).build()) - .build()); - } - - @Test - public void fromTraceConfigProto_AlwaysSampler() { - TraceConfig traceConfig = - TraceConfig.newBuilder() - .setConstantSampler(ConstantSampler.newBuilder().setDecision(true).build()) - .build(); - assertThat(TraceProtoUtils.fromTraceConfigProto(traceConfig, DEFAULT_PARAMS).getSampler()) - .isEqualTo(Samplers.alwaysSample()); - } - - @Test - public void fromTraceConfigProto_NeverSampler() { - TraceConfig traceConfig = - TraceConfig.newBuilder() - .setConstantSampler(ConstantSampler.newBuilder().setDecision(false).build()) - .build(); - assertThat(TraceProtoUtils.fromTraceConfigProto(traceConfig, DEFAULT_PARAMS).getSampler()) - .isEqualTo(Samplers.neverSample()); - } - - @Test - public void fromTraceConfigProto_ProbabilitySampler() { - TraceConfig traceConfig = - TraceConfig.newBuilder() - .setProbabilitySampler( - ProbabilitySampler.newBuilder().setSamplingProbability(0.01).build()) - .build(); - assertThat(TraceProtoUtils.fromTraceConfigProto(traceConfig, DEFAULT_PARAMS).getSampler()) - .isEqualTo(Samplers.probabilitySampler(0.01)); - } - - private static TraceParams getTraceParams(Sampler sampler) { - return DEFAULT_PARAMS.toBuilder().setSampler(sampler).build(); - } -} diff --git a/exporters/trace/ocagent/src/main/java/io/opencensus/exporter/trace/ocagent/TraceProtoUtils.java b/exporters/trace/ocagent/src/main/java/io/opencensus/exporter/trace/ocagent/TraceProtoUtils.java new file mode 100644 index 00000000..26bae0ac --- /dev/null +++ b/exporters/trace/ocagent/src/main/java/io/opencensus/exporter/trace/ocagent/TraceProtoUtils.java @@ -0,0 +1,382 @@ +/* + * Copyright 2018, OpenCensus 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.opencensus.exporter.trace.ocagent; + +import com.google.common.annotations.VisibleForTesting; +import com.google.protobuf.BoolValue; +import com.google.protobuf.ByteString; +import com.google.protobuf.UInt32Value; +import io.opencensus.common.Function; +import io.opencensus.common.Functions; +import io.opencensus.common.Timestamp; +import io.opencensus.proto.trace.v1.AttributeValue; +import io.opencensus.proto.trace.v1.ConstantSampler; +import io.opencensus.proto.trace.v1.ProbabilitySampler; +import io.opencensus.proto.trace.v1.Span; +import io.opencensus.proto.trace.v1.Span.Attributes; +import io.opencensus.proto.trace.v1.Span.Link; +import io.opencensus.proto.trace.v1.Span.Links; +import io.opencensus.proto.trace.v1.Span.SpanKind; +import io.opencensus.proto.trace.v1.Span.TimeEvent; +import io.opencensus.proto.trace.v1.Span.TimeEvent.MessageEvent; +import io.opencensus.proto.trace.v1.Span.Tracestate; +import io.opencensus.proto.trace.v1.Span.Tracestate.Entry; +import io.opencensus.proto.trace.v1.Status; +import io.opencensus.proto.trace.v1.TraceConfig; +import io.opencensus.proto.trace.v1.TruncatableString; +import io.opencensus.trace.Annotation; +import io.opencensus.trace.MessageEvent.Type; +import io.opencensus.trace.Sampler; +import io.opencensus.trace.Span.Kind; +import io.opencensus.trace.SpanContext; +import io.opencensus.trace.SpanId; +import io.opencensus.trace.TraceId; +import io.opencensus.trace.config.TraceParams; +import io.opencensus.trace.export.SpanData; +import io.opencensus.trace.export.SpanData.TimedEvent; +import io.opencensus.trace.export.SpanData.TimedEvents; +import io.opencensus.trace.samplers.Samplers; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/*>>> +import org.checkerframework.checker.nullness.qual.Nullable; +*/ + +/** + * Utilities for converting the Tracing data models in OpenCensus Java to/from OpenCensus Proto. + * + * @since 0.17 + */ +public final class TraceProtoUtils { + + // Constant functions for AttributeValue. + private static final Function stringAttributeValueFunction = + new Function() { + @Override + public AttributeValue apply(String stringValue) { + return AttributeValue.newBuilder() + .setStringValue(toTruncatableStringProto(stringValue)) + .build(); + } + }; + + private static final Function + booleanAttributeValueFunction = + new Function() { + @Override + public AttributeValue apply(Boolean booleanValue) { + return AttributeValue.newBuilder().setBoolValue(booleanValue).build(); + } + }; + + private static final Function longAttributeValueFunction = + new Function() { + @Override + public AttributeValue apply(Long longValue) { + return AttributeValue.newBuilder().setIntValue(longValue).build(); + } + }; + + private static final Function doubleAttributeValueFunction = + new Function() { + @Override + public AttributeValue apply(Double doubleValue) { + return AttributeValue.newBuilder().setDoubleValue(doubleValue).build(); + } + }; + + /** + * Converts {@link SpanData} to {@link Span} proto. + * + * @param spanData the {@code SpanData}. + * @return proto representation of {@code Span}. + * @since 0.17 + */ + @SuppressWarnings("DefaultCharset") + public static Span toSpanProto(SpanData spanData) { + SpanContext spanContext = spanData.getContext(); + TraceId traceId = spanContext.getTraceId(); + SpanId spanId = spanContext.getSpanId(); + Span.Builder spanBuilder = + Span.newBuilder() + .setTraceId(toByteString(traceId.getBytes())) + .setSpanId(toByteString(spanId.getBytes())) + .setTracestate(toTracestateProto(spanContext.getTracestate())) + .setName(toTruncatableStringProto(spanData.getName())) + .setStartTime(toTimestampProto(spanData.getStartTimestamp())) + .setAttributes(toAttributesProto(spanData.getAttributes())) + .setTimeEvents( + toTimeEventsProto(spanData.getAnnotations(), spanData.getMessageEvents())) + .setLinks(toLinksProto(spanData.getLinks())); + + Kind kind = spanData.getKind(); + if (kind != null) { + spanBuilder.setKind(toSpanKindProto(kind)); + } + + io.opencensus.trace.Status status = spanData.getStatus(); + if (status != null) { + spanBuilder.setStatus(toStatusProto(status)); + } + + Timestamp end = spanData.getEndTimestamp(); + if (end != null) { + spanBuilder.setEndTime(toTimestampProto(end)); + } + + Integer childSpanCount = spanData.getChildSpanCount(); + if (childSpanCount != null) { + spanBuilder.setChildSpanCount(UInt32Value.newBuilder().setValue(childSpanCount).build()); + } + + Boolean hasRemoteParent = spanData.getHasRemoteParent(); + if (hasRemoteParent != null) { + spanBuilder.setSameProcessAsParentSpan(BoolValue.of(!hasRemoteParent)); + } + + SpanId parentSpanId = spanData.getParentSpanId(); + if (parentSpanId != null && parentSpanId.isValid()) { + spanBuilder.setParentSpanId(toByteString(parentSpanId.getBytes())); + } + + return spanBuilder.build(); + } + + @VisibleForTesting + static ByteString toByteString(byte[] bytes) { + return ByteString.copyFrom(bytes); + } + + private static Tracestate toTracestateProto(io.opencensus.trace.Tracestate tracestate) { + return Tracestate.newBuilder().addAllEntries(toEntriesProto(tracestate.getEntries())).build(); + } + + private static List toEntriesProto(List entries) { + List entriesProto = new ArrayList(); + for (io.opencensus.trace.Tracestate.Entry entry : entries) { + entriesProto.add( + Entry.newBuilder().setKey(entry.getKey()).setValue(entry.getValue()).build()); + } + return entriesProto; + } + + private static SpanKind toSpanKindProto(Kind kind) { + switch (kind) { + case CLIENT: + return SpanKind.CLIENT; + case SERVER: + return SpanKind.SERVER; + } + return SpanKind.UNRECOGNIZED; + } + + private static Span.TimeEvents toTimeEventsProto( + TimedEvents annotationTimedEvents, + TimedEvents messageEventTimedEvents) { + Span.TimeEvents.Builder timeEventsBuilder = Span.TimeEvents.newBuilder(); + timeEventsBuilder.setDroppedAnnotationsCount(annotationTimedEvents.getDroppedEventsCount()); + for (TimedEvent annotation : annotationTimedEvents.getEvents()) { + timeEventsBuilder.addTimeEvent(toTimeAnnotationProto(annotation)); + } + timeEventsBuilder.setDroppedMessageEventsCount(messageEventTimedEvents.getDroppedEventsCount()); + for (TimedEvent networkEvent : + messageEventTimedEvents.getEvents()) { + timeEventsBuilder.addTimeEvent(toTimeMessageEventProto(networkEvent)); + } + return timeEventsBuilder.build(); + } + + private static TimeEvent toTimeAnnotationProto(TimedEvent timedEvent) { + TimeEvent.Builder timeEventBuilder = + TimeEvent.newBuilder().setTime(toTimestampProto(timedEvent.getTimestamp())); + Annotation annotation = timedEvent.getEvent(); + timeEventBuilder.setAnnotation( + TimeEvent.Annotation.newBuilder() + .setDescription(toTruncatableStringProto(annotation.getDescription())) + .setAttributes(toAttributesBuilderProto(annotation.getAttributes(), 0)) + .build()); + return timeEventBuilder.build(); + } + + private static TimeEvent toTimeMessageEventProto( + TimedEvent timedEvent) { + TimeEvent.Builder timeEventBuilder = + TimeEvent.newBuilder().setTime(toTimestampProto(timedEvent.getTimestamp())); + io.opencensus.trace.MessageEvent messageEvent = timedEvent.getEvent(); + timeEventBuilder.setMessageEvent( + TimeEvent.MessageEvent.newBuilder() + .setId(messageEvent.getMessageId()) + .setCompressedSize(messageEvent.getCompressedMessageSize()) + .setUncompressedSize(messageEvent.getUncompressedMessageSize()) + .setType(toMessageEventTypeProto(messageEvent)) + .build()); + return timeEventBuilder.build(); + } + + private static TimeEvent.MessageEvent.Type toMessageEventTypeProto( + io.opencensus.trace.MessageEvent messageEvent) { + if (messageEvent.getType() == Type.RECEIVED) { + return MessageEvent.Type.RECEIVED; + } else { + return MessageEvent.Type.SENT; + } + } + + private static Attributes toAttributesProto( + io.opencensus.trace.export.SpanData.Attributes attributes) { + Attributes.Builder attributesBuilder = + toAttributesBuilderProto( + attributes.getAttributeMap(), attributes.getDroppedAttributesCount()); + return attributesBuilder.build(); + } + + private static Attributes.Builder toAttributesBuilderProto( + Map attributes, int droppedAttributesCount) { + Attributes.Builder attributesBuilder = + Attributes.newBuilder().setDroppedAttributesCount(droppedAttributesCount); + for (Map.Entry label : attributes.entrySet()) { + AttributeValue value = toAttributeValueProto(label.getValue()); + if (value != null) { + attributesBuilder.putAttributeMap(label.getKey(), value); + } + } + return attributesBuilder; + } + + @javax.annotation.Nullable + private static AttributeValue toAttributeValueProto( + io.opencensus.trace.AttributeValue attributeValue) { + return attributeValue.match( + stringAttributeValueFunction, + booleanAttributeValueFunction, + longAttributeValueFunction, + doubleAttributeValueFunction, + Functions.returnNull()); + } + + private static Status toStatusProto(io.opencensus.trace.Status status) { + Status.Builder statusBuilder = Status.newBuilder().setCode(status.getCanonicalCode().value()); + if (status.getDescription() != null) { + statusBuilder.setMessage(status.getDescription()); + } + return statusBuilder.build(); + } + + @VisibleForTesting + static TruncatableString toTruncatableStringProto(String string) { + return TruncatableString.newBuilder().setValue(string).setTruncatedByteCount(0).build(); + } + + private static com.google.protobuf.Timestamp toTimestampProto(Timestamp timestamp) { + return com.google.protobuf.Timestamp.newBuilder() + .setSeconds(timestamp.getSeconds()) + .setNanos(timestamp.getNanos()) + .build(); + } + + private static Link.Type toLinkTypeProto(io.opencensus.trace.Link.Type type) { + if (type == io.opencensus.trace.Link.Type.PARENT_LINKED_SPAN) { + return Link.Type.PARENT_LINKED_SPAN; + } else { + return Link.Type.CHILD_LINKED_SPAN; + } + } + + @SuppressWarnings("DefaultCharset") + private static Link toLinkProto(io.opencensus.trace.Link link) { + return Link.newBuilder() + .setTraceId(toByteString(link.getTraceId().getBytes())) + .setSpanId(toByteString(link.getSpanId().getBytes())) + .setType(toLinkTypeProto(link.getType())) + .setAttributes(toAttributesBuilderProto(link.getAttributes(), 0)) + .build(); + } + + private static Links toLinksProto(io.opencensus.trace.export.SpanData.Links links) { + final Links.Builder linksBuilder = + Links.newBuilder().setDroppedLinksCount(links.getDroppedLinksCount()); + for (io.opencensus.trace.Link link : links.getLinks()) { + linksBuilder.addLink(toLinkProto(link)); + } + return linksBuilder.build(); + } + + /** + * Converts {@link TraceParams} to {@link TraceConfig}. + * + * @param traceParams the {@code TraceParams}. + * @return {@code TraceConfig}. + * @since 0.17 + */ + public static TraceConfig toTraceConfigProto(TraceParams traceParams) { + TraceConfig.Builder traceConfigProtoBuilder = TraceConfig.newBuilder(); + Sampler librarySampler = traceParams.getSampler(); + + if (Samplers.alwaysSample().equals(librarySampler)) { + traceConfigProtoBuilder.setConstantSampler( + ConstantSampler.newBuilder().setDecision(true).build()); + } else if (Samplers.neverSample().equals(librarySampler)) { + traceConfigProtoBuilder.setConstantSampler( + ConstantSampler.newBuilder().setDecision(false).build()); + } else { + // TODO: consider exposing the sampling probability of ProbabilitySampler. + double samplingProbability = parseSamplingProbability(librarySampler); + traceConfigProtoBuilder.setProbabilitySampler( + ProbabilitySampler.newBuilder().setSamplingProbability(samplingProbability).build()); + } // TODO: add support for RateLimitingSampler. + + return traceConfigProtoBuilder.build(); + } + + private static double parseSamplingProbability(Sampler sampler) { + String description = sampler.getDescription(); + // description follows format "ProbabilitySampler{%.6f}", samplingProbability. + int leftParenIndex = description.indexOf("{"); + int rightParenIndex = description.indexOf("}"); + return Double.parseDouble(description.substring(leftParenIndex + 1, rightParenIndex)); + } + + /** + * Converts {@link TraceConfig} to {@link TraceParams}. + * + * @param traceConfigProto {@code TraceConfig}. + * @param currentTraceParams current {@code TraceParams}. + * @return updated {@code TraceParams}. + * @since 0.17 + */ + public static TraceParams fromTraceConfigProto( + TraceConfig traceConfigProto, TraceParams currentTraceParams) { + TraceParams.Builder builder = currentTraceParams.toBuilder(); + if (traceConfigProto.hasConstantSampler()) { + ConstantSampler constantSampler = traceConfigProto.getConstantSampler(); + if (Boolean.TRUE.equals(constantSampler.getDecision())) { + builder.setSampler(Samplers.alwaysSample()); + } else { + builder.setSampler(Samplers.neverSample()); + } + } else if (traceConfigProto.hasProbabilitySampler()) { + builder.setSampler( + Samplers.probabilitySampler( + traceConfigProto.getProbabilitySampler().getSamplingProbability())); + } // TODO: add support for RateLimitingSampler. + return builder.build(); + } + + private TraceProtoUtils() {} +} diff --git a/exporters/trace/ocagent/src/test/java/io/opencensus/exporter/trace/ocagent/TraceProtoUtilsTest.java b/exporters/trace/ocagent/src/test/java/io/opencensus/exporter/trace/ocagent/TraceProtoUtilsTest.java new file mode 100644 index 00000000..4271fc79 --- /dev/null +++ b/exporters/trace/ocagent/src/test/java/io/opencensus/exporter/trace/ocagent/TraceProtoUtilsTest.java @@ -0,0 +1,318 @@ +/* + * Copyright 2018, OpenCensus 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.opencensus.exporter.trace.ocagent; + +import static com.google.common.truth.Truth.assertThat; +import static io.opencensus.exporter.trace.ocagent.TraceProtoUtils.toByteString; +import static io.opencensus.exporter.trace.ocagent.TraceProtoUtils.toTruncatableStringProto; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.protobuf.BoolValue; +import com.google.protobuf.UInt32Value; +import io.opencensus.common.Timestamp; +import io.opencensus.proto.trace.v1.AttributeValue; +import io.opencensus.proto.trace.v1.ConstantSampler; +import io.opencensus.proto.trace.v1.ProbabilitySampler; +import io.opencensus.proto.trace.v1.Span; +import io.opencensus.proto.trace.v1.Span.SpanKind; +import io.opencensus.proto.trace.v1.Span.TimeEvent; +import io.opencensus.proto.trace.v1.Span.TimeEvent.MessageEvent; +import io.opencensus.proto.trace.v1.TraceConfig; +import io.opencensus.trace.Annotation; +import io.opencensus.trace.Link; +import io.opencensus.trace.Sampler; +import io.opencensus.trace.Span.Kind; +import io.opencensus.trace.SpanContext; +import io.opencensus.trace.SpanId; +import io.opencensus.trace.Status; +import io.opencensus.trace.TraceId; +import io.opencensus.trace.TraceOptions; +import io.opencensus.trace.Tracestate; +import io.opencensus.trace.config.TraceParams; +import io.opencensus.trace.export.SpanData; +import io.opencensus.trace.export.SpanData.TimedEvent; +import io.opencensus.trace.export.SpanData.TimedEvents; +import io.opencensus.trace.samplers.Samplers; +import java.util.List; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link TraceProtoUtils}. */ +@RunWith(JUnit4.class) +public class TraceProtoUtilsTest { + + private static final TraceParams DEFAULT_PARAMS = TraceParams.DEFAULT; + + private static final Timestamp startTimestamp = Timestamp.create(123, 456); + private static final Timestamp eventTimestamp1 = Timestamp.create(123, 457); + private static final Timestamp eventTimestamp2 = Timestamp.create(123, 458); + private static final Timestamp eventTimestamp3 = Timestamp.create(123, 459); + private static final Timestamp endTimestamp = Timestamp.create(123, 460); + + private static final String TRACE_ID = "4bf92f3577b34da6a3ce929d0e0e4736"; + private static final String SPAN_ID = "24aa0b2d371f48c9"; + private static final String PARENT_SPAN_ID = "71da8d631536f5f1"; + private static final String SPAN_NAME = "MySpanName"; + private static final String ANNOTATION_TEXT = "MyAnnotationText"; + private static final String ATTRIBUTE_KEY_1 = "MyAttributeKey1"; + private static final String ATTRIBUTE_KEY_2 = "MyAttributeKey2"; + + private static final String FIRST_KEY = "key_1"; + private static final String SECOND_KEY = "key_2"; + private static final String FIRST_VALUE = "value.1"; + private static final String SECOND_VALUE = "value.2"; + private static final Tracestate multiValueTracestate = + Tracestate.builder().set(FIRST_KEY, FIRST_VALUE).set(SECOND_KEY, SECOND_VALUE).build(); + + private static final int DROPPED_ATTRIBUTES_COUNT = 1; + private static final int DROPPED_ANNOTATIONS_COUNT = 2; + private static final int DROPPED_NETWORKEVENTS_COUNT = 3; + private static final int DROPPED_LINKS_COUNT = 4; + private static final int CHILD_SPAN_COUNT = 13; + + private static final Annotation annotation = Annotation.fromDescription(ANNOTATION_TEXT); + private static final io.opencensus.trace.MessageEvent recvMessageEvent = + io.opencensus.trace.MessageEvent.builder(io.opencensus.trace.MessageEvent.Type.RECEIVED, 1) + .build(); + private static final io.opencensus.trace.MessageEvent sentMessageEvent = + io.opencensus.trace.MessageEvent.builder(io.opencensus.trace.MessageEvent.Type.SENT, 1) + .build(); + private static final Status status = Status.DEADLINE_EXCEEDED.withDescription("TooSlow"); + private static final SpanId parentSpanId = SpanId.fromLowerBase16(PARENT_SPAN_ID); + private static final SpanId spanId = SpanId.fromLowerBase16(SPAN_ID); + private static final TraceId traceId = TraceId.fromLowerBase16(TRACE_ID); + private static final TraceOptions traceOptions = TraceOptions.DEFAULT; + private static final SpanContext spanContext = + SpanContext.create(traceId, spanId, traceOptions, multiValueTracestate); + + private static final List> annotationsList = + ImmutableList.of( + SpanData.TimedEvent.create(eventTimestamp1, annotation), + SpanData.TimedEvent.create(eventTimestamp3, annotation)); + private static final List> networkEventsList = + ImmutableList.of( + SpanData.TimedEvent.create(eventTimestamp1, recvMessageEvent), + SpanData.TimedEvent.create(eventTimestamp2, sentMessageEvent)); + private static final List linksList = + ImmutableList.of(Link.fromSpanContext(spanContext, Link.Type.CHILD_LINKED_SPAN)); + + private static final SpanData.Attributes attributes = + SpanData.Attributes.create( + ImmutableMap.of( + ATTRIBUTE_KEY_1, + io.opencensus.trace.AttributeValue.longAttributeValue(10L), + ATTRIBUTE_KEY_2, + io.opencensus.trace.AttributeValue.booleanAttributeValue(true)), + DROPPED_ATTRIBUTES_COUNT); + private static final TimedEvents annotations = + TimedEvents.create(annotationsList, DROPPED_ANNOTATIONS_COUNT); + private static final TimedEvents messageEvents = + TimedEvents.create(networkEventsList, DROPPED_NETWORKEVENTS_COUNT); + private static final SpanData.Links links = SpanData.Links.create(linksList, DROPPED_LINKS_COUNT); + + @SuppressWarnings("DefaultCharset") + @Test + public void toSpanProto() { + SpanData spanData = + SpanData.create( + spanContext, + parentSpanId, + /* hasRemoteParent= */ false, + SPAN_NAME, + Kind.CLIENT, + startTimestamp, + attributes, + annotations, + messageEvents, + links, + CHILD_SPAN_COUNT, + status, + endTimestamp); + TimeEvent annotationTimeEvent1 = + TimeEvent.newBuilder() + .setAnnotation( + TimeEvent.Annotation.newBuilder() + .setDescription(toTruncatableStringProto(ANNOTATION_TEXT)) + .setAttributes(Span.Attributes.newBuilder().build()) + .build()) + .setTime( + com.google.protobuf.Timestamp.newBuilder() + .setSeconds(eventTimestamp1.getSeconds()) + .setNanos(eventTimestamp1.getNanos()) + .build()) + .build(); + TimeEvent annotationTimeEvent2 = + TimeEvent.newBuilder() + .setAnnotation( + TimeEvent.Annotation.newBuilder() + .setDescription(toTruncatableStringProto(ANNOTATION_TEXT)) + .setAttributes(Span.Attributes.newBuilder().build()) + .build()) + .setTime( + com.google.protobuf.Timestamp.newBuilder() + .setSeconds(eventTimestamp3.getSeconds()) + .setNanos(eventTimestamp3.getNanos()) + .build()) + .build(); + + TimeEvent sentTimeEvent = + TimeEvent.newBuilder() + .setMessageEvent( + TimeEvent.MessageEvent.newBuilder() + .setType(MessageEvent.Type.SENT) + .setId(sentMessageEvent.getMessageId())) + .setTime( + com.google.protobuf.Timestamp.newBuilder() + .setSeconds(eventTimestamp2.getSeconds()) + .setNanos(eventTimestamp2.getNanos()) + .build()) + .build(); + TimeEvent recvTimeEvent = + TimeEvent.newBuilder() + .setMessageEvent( + TimeEvent.MessageEvent.newBuilder() + .setType(MessageEvent.Type.RECEIVED) + .setId(recvMessageEvent.getMessageId())) + .setTime( + com.google.protobuf.Timestamp.newBuilder() + .setSeconds(eventTimestamp1.getSeconds()) + .setNanos(eventTimestamp1.getNanos()) + .build()) + .build(); + + Span.Links spanLinks = + Span.Links.newBuilder() + .setDroppedLinksCount(DROPPED_LINKS_COUNT) + .addLink( + Span.Link.newBuilder() + .setType(Span.Link.Type.CHILD_LINKED_SPAN) + .setTraceId(toByteString(traceId.getBytes())) + .setSpanId(toByteString(spanId.getBytes())) + .setAttributes(Span.Attributes.newBuilder().build()) + .build()) + .build(); + + io.opencensus.proto.trace.v1.Status spanStatus = + io.opencensus.proto.trace.v1.Status.newBuilder() + .setCode(com.google.rpc.Code.DEADLINE_EXCEEDED.getNumber()) + .setMessage("TooSlow") + .build(); + + com.google.protobuf.Timestamp startTime = + com.google.protobuf.Timestamp.newBuilder() + .setSeconds(startTimestamp.getSeconds()) + .setNanos(startTimestamp.getNanos()) + .build(); + com.google.protobuf.Timestamp endTime = + com.google.protobuf.Timestamp.newBuilder() + .setSeconds(endTimestamp.getSeconds()) + .setNanos(endTimestamp.getNanos()) + .build(); + + Span span = TraceProtoUtils.toSpanProto(spanData); + assertThat(span.getName()).isEqualTo(toTruncatableStringProto(SPAN_NAME)); + assertThat(span.getTraceId()).isEqualTo(toByteString(traceId.getBytes())); + assertThat(span.getSpanId()).isEqualTo(toByteString(spanId.getBytes())); + assertThat(span.getParentSpanId()).isEqualTo(toByteString(parentSpanId.getBytes())); + assertThat(span.getStartTime()).isEqualTo(startTime); + assertThat(span.getEndTime()).isEqualTo(endTime); + assertThat(span.getKind()).isEqualTo(SpanKind.CLIENT); + assertThat(span.getAttributes().getDroppedAttributesCount()) + .isEqualTo(DROPPED_ATTRIBUTES_COUNT); + // The generated attributes map contains more values (e.g. agent). We only test what we added. + assertThat(span.getAttributes().getAttributeMapMap()) + .containsEntry(ATTRIBUTE_KEY_1, AttributeValue.newBuilder().setIntValue(10L).build()); + assertThat(span.getAttributes().getAttributeMapMap()) + .containsEntry(ATTRIBUTE_KEY_2, AttributeValue.newBuilder().setBoolValue(true).build()); + assertThat(span.getTimeEvents().getDroppedMessageEventsCount()) + .isEqualTo(DROPPED_NETWORKEVENTS_COUNT); + assertThat(span.getTimeEvents().getDroppedAnnotationsCount()) + .isEqualTo(DROPPED_ANNOTATIONS_COUNT); + assertThat(span.getTimeEvents().getTimeEventList()) + .containsAllOf(annotationTimeEvent1, annotationTimeEvent2, sentTimeEvent, recvTimeEvent); + assertThat(span.getLinks()).isEqualTo(spanLinks); + assertThat(span.getStatus()).isEqualTo(spanStatus); + assertThat(span.getSameProcessAsParentSpan()).isEqualTo(BoolValue.of(true)); + assertThat(span.getChildSpanCount()) + .isEqualTo(UInt32Value.newBuilder().setValue(CHILD_SPAN_COUNT).build()); + } + + @Test + public void toTraceConfigProto_AlwaysSampler() { + assertThat(TraceProtoUtils.toTraceConfigProto(getTraceParams(Samplers.alwaysSample()))) + .isEqualTo( + TraceConfig.newBuilder() + .setConstantSampler(ConstantSampler.newBuilder().setDecision(true).build()) + .build()); + } + + @Test + public void toTraceConfigProto_NeverSampler() { + assertThat(TraceProtoUtils.toTraceConfigProto(getTraceParams(Samplers.neverSample()))) + .isEqualTo( + TraceConfig.newBuilder() + .setConstantSampler(ConstantSampler.newBuilder().setDecision(false).build()) + .build()); + } + + @Test + public void toTraceConfigProto_ProbabilitySampler() { + assertThat(TraceProtoUtils.toTraceConfigProto(getTraceParams(Samplers.probabilitySampler(0.5)))) + .isEqualTo( + TraceConfig.newBuilder() + .setProbabilitySampler( + ProbabilitySampler.newBuilder().setSamplingProbability(0.5).build()) + .build()); + } + + @Test + public void fromTraceConfigProto_AlwaysSampler() { + TraceConfig traceConfig = + TraceConfig.newBuilder() + .setConstantSampler(ConstantSampler.newBuilder().setDecision(true).build()) + .build(); + assertThat(TraceProtoUtils.fromTraceConfigProto(traceConfig, DEFAULT_PARAMS).getSampler()) + .isEqualTo(Samplers.alwaysSample()); + } + + @Test + public void fromTraceConfigProto_NeverSampler() { + TraceConfig traceConfig = + TraceConfig.newBuilder() + .setConstantSampler(ConstantSampler.newBuilder().setDecision(false).build()) + .build(); + assertThat(TraceProtoUtils.fromTraceConfigProto(traceConfig, DEFAULT_PARAMS).getSampler()) + .isEqualTo(Samplers.neverSample()); + } + + @Test + public void fromTraceConfigProto_ProbabilitySampler() { + TraceConfig traceConfig = + TraceConfig.newBuilder() + .setProbabilitySampler( + ProbabilitySampler.newBuilder().setSamplingProbability(0.01).build()) + .build(); + assertThat(TraceProtoUtils.fromTraceConfigProto(traceConfig, DEFAULT_PARAMS).getSampler()) + .isEqualTo(Samplers.probabilitySampler(0.01)); + } + + private static TraceParams getTraceParams(Sampler sampler) { + return DEFAULT_PARAMS.toBuilder().setSampler(sampler).build(); + } +} diff --git a/settings.gradle b/settings.gradle index 409d3147..bdf68bdc 100644 --- a/settings.gradle +++ b/settings.gradle @@ -23,7 +23,6 @@ include ":opencensus-contrib-http-util" include ":opencensus-contrib-log-correlation-log4j2" include ":opencensus-contrib-log-correlation-stackdriver" include ":opencensus-contrib-monitored-resource-util" -include ":opencensus-contrib-opencensus-proto-util" include ":opencensus-contrib-spring" include ":opencensus-contrib-spring-sleuth-v1x" @@ -45,8 +44,6 @@ project(':opencensus-contrib-log-correlation-stackdriver').projectDir = "$rootDir/contrib/log_correlation/stackdriver" as File project(':opencensus-contrib-monitored-resource-util').projectDir = "$rootDir/contrib/monitored_resource_util" as File -project(':opencensus-contrib-opencensus-proto-util').projectDir = - "$rootDir/contrib/opencensus_proto_util" as File project(':opencensus-contrib-spring').projectDir = "$rootDir/contrib/spring" as File project(':opencensus-contrib-spring-sleuth-v1x').projectDir = "$rootDir/contrib/spring_sleuth_v1x" as File -- cgit v1.2.3