diff --git a/build.gradle b/build.gradle index 134bb8e11fd..c6b56c11934 100644 --- a/build.gradle +++ b/build.gradle @@ -309,54 +309,55 @@ configure(opentelemetryProjects) { ] libraries = [ - auto_value : "com.google.auto.value:auto-value:${autoValueVersion}", - auto_value_annotation : "com.google.auto.value:auto-value-annotations:${autoValueVersion}", - disruptor : "com.lmax:disruptor:3.4.2", - errorprone_annotation : "com.google.errorprone:error_prone_annotations:${errorProneVersion}", - errorprone_core : "com.google.errorprone:error_prone_core:${errorProneVersion}", - errorprone_javac : "com.google.errorprone:javac:${errorProneJavacVersion}", - grpc_api : "io.grpc:grpc-api", - grpc_context : "io.grpc:grpc-context", - grpc_protobuf : "io.grpc:grpc-protobuf", - grpc_stub : "io.grpc:grpc-stub", - guava : "com.google.guava:guava", - javax_annotations : "javax.annotation:javax.annotation-api:1.3.2", - jmh_core : "org.openjdk.jmh:jmh-core:${jmhVersion}", - jmh_bytecode : "org.openjdk.jmh:jmh-generator-bytecode:${jmhVersion}", - jsr305 : "com.google.code.findbugs:jsr305:${findBugsJsr305Version}", - prometheus_client : "io.prometheus:simpleclient:${prometheusVersion}", - prometheus_client_common: "io.prometheus:simpleclient_common:${prometheusVersion}", - protobuf : "com.google.protobuf:protobuf-java", - protobuf_util : "com.google.protobuf:protobuf-java-util", - zipkin_reporter : "io.zipkin.reporter2:zipkin-reporter", - zipkin_okhttp : "io.zipkin.reporter2:zipkin-sender-okhttp3", + auto_value : "com.google.auto.value:auto-value:${autoValueVersion}", + auto_value_annotation : "com.google.auto.value:auto-value-annotations:${autoValueVersion}", + disruptor : "com.lmax:disruptor:3.4.2", + errorprone_annotation : "com.google.errorprone:error_prone_annotations:${errorProneVersion}", + errorprone_core : "com.google.errorprone:error_prone_core:${errorProneVersion}", + errorprone_javac : "com.google.errorprone:javac:${errorProneJavacVersion}", + grpc_api : "io.grpc:grpc-api", + grpc_context : "io.grpc:grpc-context", + grpc_protobuf : "io.grpc:grpc-protobuf", + grpc_stub : "io.grpc:grpc-stub", + guava : "com.google.guava:guava", + javax_annotations : "javax.annotation:javax.annotation-api:1.3.2", + jmh_core : "org.openjdk.jmh:jmh-core:${jmhVersion}", + jmh_bytecode : "org.openjdk.jmh:jmh-generator-bytecode:${jmhVersion}", + jsr305 : "com.google.code.findbugs:jsr305:${findBugsJsr305Version}", + prometheus_client : "io.prometheus:simpleclient:${prometheusVersion}", + prometheus_client_common : "io.prometheus:simpleclient_common:${prometheusVersion}", + protobuf : "com.google.protobuf:protobuf-java", + protobuf_util : "com.google.protobuf:protobuf-java-util", + zipkin_reporter : "io.zipkin.reporter2:zipkin-reporter", + zipkin_okhttp : "io.zipkin.reporter2:zipkin-sender-okhttp3", // Compatibility layer - opencensus_api : "io.opencensus:opencensus-api:${opencensusVersion}", - opencensus_impl : "io.opencensus:opencensus-impl:${opencensusVersion}", - opencensus_impl_core : "io.opencensus:opencensus-impl-core:${opencensusVersion}", - opentracing : "io.opentracing:opentracing-api:${opentracingVersion}", + opencensus_api : "io.opencensus:opencensus-api:${opencensusVersion}", + opencensus_impl : "io.opencensus:opencensus-impl:${opencensusVersion}", + opencensus_impl_core : "io.opencensus:opencensus-impl-core:${opencensusVersion}", + opencensus_metric_exporter : "io.opencensus:opencensus-exporter-metrics-util:${opencensusVersion}", + opentracing : "io.opentracing:opentracing-api:${opentracingVersion}", // Test dependencies. - assertj : "org.assertj:assertj-core:3.18.1", - guava_testlib : "com.google.guava:guava-testlib", - junit : 'junit:junit:4.13.1', - junit_pioneer : 'org.junit-pioneer:junit-pioneer:1.0.0', - junit_jupiter_api : 'org.junit.jupiter:junit-jupiter-api', - junit_jupiter_engine : 'org.junit.jupiter:junit-jupiter-engine', - junit_vintage_engine : 'org.junit.vintage:junit-vintage-engine', - mockito : "org.mockito:mockito-core:${mockitoVersion}", - mockito_junit_jupiter : "org.mockito:mockito-junit-jupiter:${mockitoVersion}", - okhttp : 'com.squareup.okhttp3:okhttp:3.14.9', - system_rules : 'com.github.stefanbirkner:system-rules:1.19.0', // env and system properties - slf4jsimple : 'org.slf4j:slf4j-simple:1.7.30', // Compatibility layer - awaitility : 'org.awaitility:awaitility:4.0.3', - testcontainers : 'org.testcontainers:junit-jupiter:1.15.0', - rest_assured : 'io.rest-assured:rest-assured:4.2.0', - jaeger_client : 'io.jaegertracing:jaeger-client:1.5.0', // Jaeger Client - zipkin_junit : "io.zipkin.zipkin2:zipkin-junit:${zipkinVersion}", // Zipkin JUnit rule - archunit : 'com.tngtech.archunit:archunit-junit4:0.14.1', //Architectural constraints - jqf : 'edu.berkeley.cs.jqf:jqf-fuzz:1.6', // fuzz testing + assertj : "org.assertj:assertj-core:3.18.1", + guava_testlib : "com.google.guava:guava-testlib", + junit : 'junit:junit:4.13.1', + junit_pioneer : 'org.junit-pioneer:junit-pioneer:1.0.0', + junit_jupiter_api : 'org.junit.jupiter:junit-jupiter-api', + junit_jupiter_engine : 'org.junit.jupiter:junit-jupiter-engine', + junit_vintage_engine : 'org.junit.vintage:junit-vintage-engine', + mockito : "org.mockito:mockito-core:${mockitoVersion}", + mockito_junit_jupiter : "org.mockito:mockito-junit-jupiter:${mockitoVersion}", + okhttp : 'com.squareup.okhttp3:okhttp:3.14.9', + system_rules : 'com.github.stefanbirkner:system-rules:1.19.0', // env and system properties + slf4jsimple : 'org.slf4j:slf4j-simple:1.7.30', // Compatibility layer + awaitility : 'org.awaitility:awaitility:4.0.3', + testcontainers : 'org.testcontainers:junit-jupiter:1.15.0', + rest_assured : 'io.rest-assured:rest-assured:4.2.0', + jaeger_client : 'io.jaegertracing:jaeger-client:1.5.0', // Jaeger Client + zipkin_junit : "io.zipkin.zipkin2:zipkin-junit:${zipkinVersion}", // Zipkin JUnit rule + archunit : 'com.tngtech.archunit:archunit-junit4:0.14.1', //Architectural constraints + jqf : 'edu.berkeley.cs.jqf:jqf-fuzz:1.6', // fuzz testing // Tooling android_signature : 'com.toasttab.android:gummy-bears-api-24:0.3.0:coreLib@signature' diff --git a/opencensus-shim/README.md b/opencensus-shim/README.md index 38eed4d08a7..347d595794e 100644 --- a/opencensus-shim/README.md +++ b/opencensus-shim/README.md @@ -4,24 +4,48 @@ The OpenCensus shim allows applications and libraries that are instrumented with OpenTelemetry, but depend on other libraries instrumented with OpenCensus, to export trace spans from both OpenTelemetry and OpenCensus with the correct -parent-child relationship. - -The shim maps all OpenCensus spans to OpenTelemetry spans, which are then exported -by any configured OpenTelemetry exporter. +parent-child relationship. It also allows OpenCensus metrics to be exported by +any configured OpenTelemetry metric exporter. ## Usage -To allow the shim to work, add the shim as a dependency. +### Traces + +To allow the shim to work for traces, add the shim as a dependency. + +Nothing else needs to be added to libraries for this to work. + +Applications only need to set up OpenTelemetry exporters, not OpenCensus. + +### Metrics + +To allow the shim to work for metrics, add the shim as a dependency. + +Applications also need to pass the configured metric exporter to the shim: + +``` +OpenTelemetryMetricsExporter exporter = + OpenTelemetryMetricsExporter.createAndRegister(metricExporter); +``` + +For example, if a logging exporter were configured, the following would be +added: + +``` +LoggingMetricExporter metricExporter = new LoggingMetricExporter(); +OpenTelemetryMetricsExporter exporter = + OpenTelemetryMetricsExporter.createAndRegister(metricExporter); +``` -Libraries do not need to do anything else for this to work. +The export interval can also be set: -Applications only need to be configured for OpenTelemetry, not OpenCensus. +``` +OpenTelemetryMetricsExporter exporter = + OpenTelemetryMetricsExporter.createAndRegister(metricExporter, + Duration.create(0, 500)); +``` ## Known Problems * OpenCensus links added after an OpenCensus span is created will not be exported, as OpenTelemetry only supports links added when a span is created. -* There is a 10-minute timeout, as well as a 10,000 entries limit in -the shim span cache. This means if an OpenCensus span is not ended within 10 -minutes, or if more than 10,000 active spans are created after the span, -the span will be deleted and will not be exported. diff --git a/opencensus-shim/build.gradle b/opencensus-shim/build.gradle index 28494e2fa3b..c2946242ce5 100644 --- a/opencensus-shim/build.gradle +++ b/opencensus-shim/build.gradle @@ -8,8 +8,10 @@ ext.moduleName = "io.opentelemetry.opencensusshim" dependencies { api project(':opentelemetry-api'), + project(':opentelemetry-sdk'), libraries.opencensus_api, - libraries.opencensus_impl_core + libraries.opencensus_impl_core, + libraries.opencensus_metric_exporter testImplementation project(':opentelemetry-sdk'), libraries.junit, diff --git a/opencensus-shim/src/main/java/io/opentelemetry/opencensusshim/OpenTelemetryMetricsExporter.java b/opencensus-shim/src/main/java/io/opentelemetry/opencensusshim/OpenTelemetryMetricsExporter.java new file mode 100644 index 00000000000..521fb36cf00 --- /dev/null +++ b/opencensus-shim/src/main/java/io/opentelemetry/opencensusshim/OpenTelemetryMetricsExporter.java @@ -0,0 +1,221 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.opencensusshim; + +import com.google.common.base.Joiner; +import io.opencensus.common.Duration; +import io.opencensus.exporter.metrics.util.IntervalMetricReader; +import io.opencensus.exporter.metrics.util.MetricExporter; +import io.opencensus.exporter.metrics.util.MetricReader; +import io.opencensus.metrics.Metrics; +import io.opencensus.metrics.export.Metric; +import io.opencensus.metrics.export.MetricDescriptor; +import io.opencensus.metrics.export.Point; +import io.opencensus.metrics.export.Summary; +import io.opencensus.metrics.export.Summary.Snapshot; +import io.opencensus.metrics.export.TimeSeries; +import io.opentelemetry.api.common.Labels; +import io.opentelemetry.api.common.LabelsBuilder; +import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.data.MetricData.DoublePoint; +import io.opentelemetry.sdk.metrics.data.MetricData.LongPoint; +import io.opentelemetry.sdk.metrics.data.MetricData.SummaryPoint; +import io.opentelemetry.sdk.metrics.data.MetricData.ValueAtPercentile; +import io.opentelemetry.sdk.resources.Resource; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; +import javax.annotation.Nonnull; + +public class OpenTelemetryMetricsExporter extends MetricExporter { + private static final Logger LOGGER = + Logger.getLogger(OpenTelemetryMetricsExporter.class.getName()); + + private static final String EXPORTER_NAME = "OpenTelemetryMetricExporter"; + private static final InstrumentationLibraryInfo INSTRUMENTATION_LIBRARY_INFO = + InstrumentationLibraryInfo.create("io.opentelemetry.opencensusshim", null); + + private final IntervalMetricReader intervalMetricReader; + private final io.opentelemetry.sdk.metrics.export.MetricExporter otelExporter; + + public static OpenTelemetryMetricsExporter createAndRegister( + io.opentelemetry.sdk.metrics.export.MetricExporter otelExporter) { + return new OpenTelemetryMetricsExporter(otelExporter, Duration.create(60, 0)); + } + + public static OpenTelemetryMetricsExporter createAndRegister( + io.opentelemetry.sdk.metrics.export.MetricExporter otelExporter, Duration exportInterval) { + return new OpenTelemetryMetricsExporter(otelExporter, exportInterval); + } + + private OpenTelemetryMetricsExporter( + io.opentelemetry.sdk.metrics.export.MetricExporter otelExporter, Duration exportInterval) { + this.otelExporter = otelExporter; + IntervalMetricReader.Options.Builder options = IntervalMetricReader.Options.builder(); + MetricReader reader = + MetricReader.create( + MetricReader.Options.builder() + .setMetricProducerManager(Metrics.getExportComponent().getMetricProducerManager()) + .setSpanName(EXPORTER_NAME) + .build()); + intervalMetricReader = + IntervalMetricReader.create( + this, reader, options.setExportInterval(exportInterval).build()); + } + + @Override + public void export(Collection metrics) { + List metricData = new ArrayList<>(); + Set unsupportedTypes = new HashSet<>(); + for (Metric metric : metrics) { + for (TimeSeries timeSeries : metric.getTimeSeriesList()) { + LabelsBuilder labelsBuilder = Labels.builder(); + for (int i = 0; i < metric.getMetricDescriptor().getLabelKeys().size(); i++) { + if (timeSeries.getLabelValues().get(i).getValue() != null) { + labelsBuilder.put( + metric.getMetricDescriptor().getLabelKeys().get(i).getKey(), + timeSeries.getLabelValues().get(i).getValue()); + } + } + Labels labels = labelsBuilder.build(); + List points = new ArrayList<>(); + MetricDescriptor.Type type = null; + for (Point point : timeSeries.getPoints()) { + type = mapAndAddPoint(unsupportedTypes, metric, labels, points, point); + } + MetricData.Type metricDataType = mapType(type); + if (metricDataType != null) { + metricData.add( + MetricData.create( + Resource.getDefault(), + INSTRUMENTATION_LIBRARY_INFO, + metric.getMetricDescriptor().getName(), + metric.getMetricDescriptor().getDescription(), + metric.getMetricDescriptor().getUnit(), + metricDataType, + points)); + } + } + } + if (!unsupportedTypes.isEmpty()) { + LOGGER.warning( + Joiner.on(",").join(unsupportedTypes) + + " not supported by OpenCensus to OpenTelemetry migrator."); + } + if (!metricData.isEmpty()) { + otelExporter.export(metricData); + } + } + + @Nonnull + private static MetricDescriptor.Type mapAndAddPoint( + Set unsupportedTypes, + Metric metric, + Labels labels, + List points, + Point point) { + long timestampNanos = + TimeUnit.SECONDS.toNanos(point.getTimestamp().getSeconds()) + + point.getTimestamp().getNanos(); + MetricDescriptor.Type type = metric.getMetricDescriptor().getType(); + switch (type) { + case GAUGE_INT64: + case CUMULATIVE_INT64: + points.add(mapLongPoint(labels, point, timestampNanos)); + break; + case GAUGE_DOUBLE: + case CUMULATIVE_DOUBLE: + points.add(mapDoublePoint(labels, point, timestampNanos)); + break; + case SUMMARY: + points.add(mapSummaryPoint(labels, point, timestampNanos)); + break; + default: + unsupportedTypes.add(type); + break; + } + return type; + } + + public void stop() { + intervalMetricReader.stop(); + } + + @Nonnull + private static SummaryPoint mapSummaryPoint(Labels labels, Point point, long timestampNanos) { + return SummaryPoint.create( + timestampNanos, + timestampNanos, + labels, + point + .getValue() + .match(arg -> null, arg -> null, arg -> null, Summary::getCount, arg -> null), + point.getValue().match(arg -> null, arg -> null, arg -> null, Summary::getSum, arg -> null), + point + .getValue() + .match( + arg -> null, + arg -> null, + arg -> null, + OpenTelemetryMetricsExporter::mapPercentiles, + arg -> null)); + } + + private static List mapPercentiles(Summary arg) { + List percentiles = new ArrayList<>(); + for (Snapshot.ValueAtPercentile percentile : arg.getSnapshot().getValueAtPercentiles()) { + percentiles.add(ValueAtPercentile.create(percentile.getPercentile(), percentile.getValue())); + } + return percentiles; + } + + @Nonnull + private static DoublePoint mapDoublePoint(Labels labels, Point point, long timestampNanos) { + return DoublePoint.create( + timestampNanos, + timestampNanos, + labels, + point + .getValue() + .match(arg -> arg, Long::doubleValue, arg -> null, arg -> null, arg -> null)); + } + + @Nonnull + private static LongPoint mapLongPoint(Labels labels, Point point, long timestampNanos) { + return LongPoint.create( + timestampNanos, + timestampNanos, + labels, + point + .getValue() + .match(Double::longValue, arg -> arg, arg -> null, arg -> null, arg -> null)); + } + + private static MetricData.Type mapType(MetricDescriptor.Type type) { + if (type == null) { + return null; + } + switch (type) { + case GAUGE_INT64: + return MetricData.Type.GAUGE_LONG; + case GAUGE_DOUBLE: + return MetricData.Type.GAUGE_DOUBLE; + case CUMULATIVE_INT64: + return MetricData.Type.MONOTONIC_LONG; + case CUMULATIVE_DOUBLE: + return MetricData.Type.MONOTONIC_DOUBLE; + case SUMMARY: + return MetricData.Type.SUMMARY; + default: + return null; + } + } +} diff --git a/opencensus-shim/src/test/java/io/opentelemetry/opencensusshim/FakeMetricExporter.java b/opencensus-shim/src/test/java/io/opentelemetry/opencensusshim/FakeMetricExporter.java new file mode 100644 index 00000000000..127d0991d53 --- /dev/null +++ b/opencensus-shim/src/test/java/io/opentelemetry/opencensusshim/FakeMetricExporter.java @@ -0,0 +1,80 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +// Includes work from: +/* + * 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.opentelemetry.opencensusshim; + +import com.google.errorprone.annotations.concurrent.GuardedBy; +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.export.MetricExporter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import javax.annotation.Nullable; + +class FakeMetricExporter implements MetricExporter { + + private final Object monitor = new Object(); + + @GuardedBy("monitor") + private List> exportedMetrics = new ArrayList<>(); + + /** + * Waits until export is called for numberOfExports times. Returns the list of exported lists of + * metrics + */ + @Nullable + List> waitForNumberOfExports(int numberOfExports) { + List> ret; + synchronized (monitor) { + while (exportedMetrics.size() < numberOfExports) { + try { + monitor.wait(); + } catch (InterruptedException e) { + // Preserve the interruption status as per guidance. + Thread.currentThread().interrupt(); + return null; + } + } + ret = exportedMetrics; + exportedMetrics = new ArrayList<>(); + } + return ret; + } + + @Override + public CompletableResultCode export(Collection metrics) { + synchronized (monitor) { + this.exportedMetrics.add(new ArrayList<>(metrics)); + monitor.notifyAll(); + } + return CompletableResultCode.ofSuccess(); + } + + @Override + public CompletableResultCode flush() { + return null; + } + + @Override + public void shutdown() {} +} diff --git a/opencensus-shim/src/test/java/io/opentelemetry/opencensusshim/MetricInteroperabilityTest.java b/opencensus-shim/src/test/java/io/opentelemetry/opencensusshim/MetricInteroperabilityTest.java new file mode 100644 index 00000000000..a57674ad08b --- /dev/null +++ b/opencensus-shim/src/test/java/io/opentelemetry/opencensusshim/MetricInteroperabilityTest.java @@ -0,0 +1,122 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.opencensusshim; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.google.common.collect.ImmutableList; +import io.opencensus.common.Duration; +import io.opencensus.common.Scope; +import io.opencensus.stats.Aggregation; +import io.opencensus.stats.BucketBoundaries; +import io.opencensus.stats.Measure.MeasureLong; +import io.opencensus.stats.Stats; +import io.opencensus.stats.StatsRecorder; +import io.opencensus.stats.View; +import io.opencensus.stats.View.Name; +import io.opencensus.stats.ViewManager; +import io.opencensus.tags.TagContext; +import io.opencensus.tags.TagKey; +import io.opencensus.tags.TagMetadata; +import io.opencensus.tags.TagMetadata.TagTtl; +import io.opencensus.tags.TagValue; +import io.opencensus.tags.Tagger; +import io.opencensus.tags.Tags; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.data.MetricData.LongPoint; +import io.opentelemetry.sdk.metrics.data.MetricData.Point; +import java.util.List; +import org.junit.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class MetricInteroperabilityTest { + + @Test + public void testSupportedMetricsExportedCorrectly() { + Tagger tagger = Tags.getTagger(); + MeasureLong latency = + MeasureLong.create("task_latency", "The task latency in milliseconds", "ms"); + StatsRecorder statsRecorder = Stats.getStatsRecorder(); + TagKey tagKey = TagKey.create("tagKey"); + TagValue tagValue = TagValue.create("tagValue"); + View view = + View.create( + Name.create("task_latency_sum"), + "The sum of the task latencies.", + latency, + Aggregation.Sum.create(), + ImmutableList.of(tagKey)); + ViewManager viewManager = Stats.getViewManager(); + viewManager.registerView(view); + FakeMetricExporter metricExporter = new FakeMetricExporter(); + OpenTelemetryMetricsExporter.createAndRegister(metricExporter, Duration.create(0, 500)); + + TagContext tagContext = + tagger + .emptyBuilder() + .put(tagKey, tagValue, TagMetadata.create(TagTtl.UNLIMITED_PROPAGATION)) + .build(); + try (Scope ss = tagger.withTagContext(tagContext)) { + statsRecorder.newMeasureMap().put(latency, 50).record(); + } + List metricData = metricExporter.waitForNumberOfExports(1).get(0); + assertThat(metricData.size()).isEqualTo(1); + MetricData metric = metricData.get(0); + assertThat(metric.getName()).isEqualTo("task_latency_sum"); + assertThat(metric.getDescription()).isEqualTo("The sum of the task latencies."); + assertThat(metric.getUnit()).isEqualTo("ms"); + assertThat(metric.getType()).isEqualTo(MetricData.Type.MONOTONIC_LONG); + assertThat(metric.getPoints().size()).isEqualTo(1); + Point point = metric.getPoints().iterator().next(); + assertThat(((LongPoint) point).getValue()).isEqualTo(50); + assertThat(point.getLabels().size()).isEqualTo(1); + assertThat(point.getLabels().get(tagKey.getName())).isEqualTo(tagValue.asString()); + } + + @Test + public void testUnsupportedMetricsDoesNotGetExported() throws InterruptedException { + Tagger tagger = Tags.getTagger(); + MeasureLong latency = + MeasureLong.create("task_latency_distribution", "The task latency in milliseconds", "ms"); + StatsRecorder statsRecorder = Stats.getStatsRecorder(); + TagKey tagKey = TagKey.create("tagKey"); + TagValue tagValue = TagValue.create("tagValue"); + View view = + View.create( + Name.create("task_latency_distribution"), + "The distribution of the task latencies.", + latency, + Aggregation.Distribution.create( + BucketBoundaries.create(ImmutableList.of(100.0, 150.0, 200.0))), + ImmutableList.of(tagKey)); + ViewManager viewManager = Stats.getViewManager(); + viewManager.registerView(view); + FakeMetricExporter metricExporter = new FakeMetricExporter(); + OpenTelemetryMetricsExporter.createAndRegister(metricExporter, Duration.create(0, 500)); + + TagContext tagContext = + tagger + .emptyBuilder() + .put(tagKey, tagValue, TagMetadata.create(TagTtl.UNLIMITED_PROPAGATION)) + .build(); + try (Scope ss = tagger.withTagContext(tagContext)) { + statsRecorder.newMeasureMap().put(latency, 50).record(); + } + // Sleep so that there is time for export() to be called. + Thread.sleep(2); + // This is 0 in case this test gets run first, or by itself. + // If other views have already been registered in other tests, they will produce metric data, so + // we are testing for the absence of this particular view's metric data. + List> allExports = metricExporter.waitForNumberOfExports(0); + if (!allExports.isEmpty()) { + for (MetricData metricData : allExports.get(allExports.size() - 1)) { + assertThat(metricData.getName()).isNotEqualTo("task_latency_distribution"); + } + } + } +} diff --git a/opencensus-shim/src/test/java/io/opentelemetry/opencensusshim/InteroperabilityTest.java b/opencensus-shim/src/test/java/io/opentelemetry/opencensusshim/TraceInteroperabilityTest.java similarity index 99% rename from opencensus-shim/src/test/java/io/opentelemetry/opencensusshim/InteroperabilityTest.java rename to opencensus-shim/src/test/java/io/opentelemetry/opencensusshim/TraceInteroperabilityTest.java index c85d2bce210..e9a01b085df 100644 --- a/opencensus-shim/src/test/java/io/opentelemetry/opencensusshim/InteroperabilityTest.java +++ b/opencensus-shim/src/test/java/io/opentelemetry/opencensusshim/TraceInteroperabilityTest.java @@ -34,7 +34,7 @@ import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) -class InteroperabilityTest { +class TraceInteroperabilityTest { private static final String NULL_SPAN_ID = "0000000000000000";