Skip to content

Commit

Permalink
Add meaningful tests for OTEL client (airbytehq#13831)
Browse files Browse the repository at this point in the history
* Add meaningful tests for OTEL client

* PR comment fix

* code clean ups
  • Loading branch information
xiaohansong authored Jun 16, 2022
1 parent 40d58cc commit 9d060a9
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 20 deletions.
2 changes: 2 additions & 0 deletions airbyte-metrics/metrics-lib/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ dependencies {
implementation project(':airbyte-db:db-lib')

implementation libs.otel.semconv
implementation libs.otel.sdk
implementation libs.otel.sdk.testing
implementation platform(libs.otel.bom)
implementation("io.opentelemetry:opentelemetry-api")
implementation("io.opentelemetry:opentelemetry-sdk")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import static io.opentelemetry.api.common.AttributeKey.stringKey;
import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.SERVICE_NAME;

import com.google.common.annotations.VisibleForTesting;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;
Expand All @@ -20,6 +21,7 @@
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import io.opentelemetry.sdk.metrics.export.MetricExporter;
import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
Expand All @@ -28,6 +30,7 @@
public class OpenTelemetryMetricClient implements MetricClient {

private Meter meter;
private SdkMeterProvider meterProvider;

@Override
public void count(MetricsRegistry metric, long val, String... tags) {
Expand Down Expand Up @@ -75,9 +78,19 @@ public void initialize(MetricEmittingApp metricEmittingApp, String otelEndpoint)
.build())
.setResource(resource)
.build();
OtlpGrpcMetricExporter metricExporter = OtlpGrpcMetricExporter.builder()
MetricExporter metricExporter = OtlpGrpcMetricExporter.builder()
.setEndpoint(otelEndpoint).build();
SdkMeterProvider meterProvider = SdkMeterProvider.builder()
initialize(metricEmittingApp, metricExporter, sdkTracerProvider, resource);
}

@VisibleForTesting
SdkMeterProvider getSdkMeterProvider() {
return meterProvider;
}

@VisibleForTesting
void initialize(MetricEmittingApp metricEmittingApp, MetricExporter metricExporter, SdkTracerProvider sdkTracerProvider, Resource resource) {
meterProvider = SdkMeterProvider.builder()
.registerMetricReader(PeriodicMetricReader.builder(metricExporter).build())
.setResource(resource)
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,43 @@

package io.airbyte.metrics.lib;

import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.SERVICE_NAME;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;

import com.google.common.collect.Iterables;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import io.opentelemetry.sdk.metrics.data.MetricData;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.testing.exporter.InMemoryMetricExporter;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import java.util.List;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

class OpenTelemetryMetricClientTest {

OpenTelemetryMetricClient openTelemetryMetricClient;
private final static String EXPORTER_ENDPOINT = "http://localhost:4322";
private final static String TAG = "tag1";

private final static MetricEmittingApp METRIC_EMITTING_APP = MetricEmittingApps.WORKER;
private InMemoryMetricExporter metricExporter;
private SdkMeterProvider metricProvider;

@BeforeEach
void setUp() {
openTelemetryMetricClient = new OpenTelemetryMetricClient();
openTelemetryMetricClient.initialize(MetricEmittingApps.WORKER, EXPORTER_ENDPOINT);

Resource resource = Resource.getDefault().toBuilder().put(SERVICE_NAME, METRIC_EMITTING_APP.getApplicationName()).build();
metricExporter = InMemoryMetricExporter.create();
SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder()
.setResource(resource)
.build();
openTelemetryMetricClient.initialize(METRIC_EMITTING_APP, metricExporter, sdkTracerProvider, resource);

metricProvider = openTelemetryMetricClient.getSdkMeterProvider();
}

@AfterEach
Expand All @@ -27,27 +49,63 @@ void tearDown() {
}

@Test
@DisplayName("there should be no exception if we attempt to emit metrics while publish is false")
public void testPublishTrueNoEmitError() {
Assertions.assertDoesNotThrow(() -> {
openTelemetryMetricClient.gauge(OssMetricsRegistry.KUBE_POD_PROCESS_CREATE_TIME_MILLISECS, 1);
});
@DisplayName("Should send out count metric with correct metric name, description and value")
public void testCountSuccess() {
openTelemetryMetricClient.count(OssMetricsRegistry.KUBE_POD_PROCESS_CREATE_TIME_MILLISECS, 1);

metricProvider.forceFlush();
List<MetricData> metricDataList = metricExporter.getFinishedMetricItems();
MetricData data = Iterables.getOnlyElement(metricDataList);

assertThat(data.getName()).isEqualTo(OssMetricsRegistry.KUBE_POD_PROCESS_CREATE_TIME_MILLISECS.getMetricName());
assertThat(data.getDescription()).isEqualTo(OssMetricsRegistry.KUBE_POD_PROCESS_CREATE_TIME_MILLISECS.getMetricDescription());
assertThat(data.getLongSumData().getPoints().stream().anyMatch(longPointData -> longPointData.getValue() == 1L));
}

@Test
@DisplayName("there should be no exception if we attempt to emit metrics while publish is true")
public void testPublishFalseNoEmitError() {
Assertions.assertDoesNotThrow(() -> {
openTelemetryMetricClient.gauge(OssMetricsRegistry.KUBE_POD_PROCESS_CREATE_TIME_MILLISECS, 1);
});
@DisplayName("Tags should be passed into metrics")
public void testCountWithTagSuccess() {
openTelemetryMetricClient.count(OssMetricsRegistry.KUBE_POD_PROCESS_CREATE_TIME_MILLISECS, 1, TAG);

metricProvider.forceFlush();
List<MetricData> metricDataList = metricExporter.getFinishedMetricItems();
MetricData data = Iterables.getOnlyElement(metricDataList);

assertThat(data.getName()).isEqualTo(OssMetricsRegistry.KUBE_POD_PROCESS_CREATE_TIME_MILLISECS.getMetricName());
assertThat(data.getDescription()).isEqualTo(OssMetricsRegistry.KUBE_POD_PROCESS_CREATE_TIME_MILLISECS.getMetricDescription());
assertThat(data.getLongSumData().getPoints().stream()
.anyMatch(
longPointData -> longPointData.getValue() == 1L && longPointData.getAttributes().get(AttributeKey.stringKey(TAG)).equals(TAG)));
}

@Test
@DisplayName("there should be no exception if we attempt to emit metrics without initializing")
public void testNoInitializeNoEmitError() {
Assertions.assertDoesNotThrow(() -> {
openTelemetryMetricClient.gauge(OssMetricsRegistry.KUBE_POD_PROCESS_CREATE_TIME_MILLISECS, 1);
});
@DisplayName("Should send out gauge metric with correct metric name, description and value")
public void testGaugeSuccess() throws Exception {
openTelemetryMetricClient.gauge(OssMetricsRegistry.KUBE_POD_PROCESS_CREATE_TIME_MILLISECS, 1);

metricProvider.forceFlush();
List<MetricData> metricDataList = metricExporter.getFinishedMetricItems();
MetricData data = Iterables.getOnlyElement(metricDataList);

assertThat(data.getName()).isEqualTo(OssMetricsRegistry.KUBE_POD_PROCESS_CREATE_TIME_MILLISECS.getMetricName());
assertThat(data.getDescription()).isEqualTo(OssMetricsRegistry.KUBE_POD_PROCESS_CREATE_TIME_MILLISECS.getMetricDescription());
assertThat(data.getDoubleGaugeData().getPoints().stream().anyMatch(doublePointData -> doublePointData.getValue() == 1.0));
}

@Test
@DisplayName("Should send out histogram metric with correct metric name, description and value")
public void testHistogramSuccess() {
openTelemetryMetricClient.distribution(OssMetricsRegistry.KUBE_POD_PROCESS_CREATE_TIME_MILLISECS, 10);
openTelemetryMetricClient.distribution(OssMetricsRegistry.KUBE_POD_PROCESS_CREATE_TIME_MILLISECS, 30);

metricProvider.forceFlush();
List<MetricData> metricDataList = metricExporter.getFinishedMetricItems();
MetricData data = Iterables.getOnlyElement(metricDataList);

assertThat(data.getName()).isEqualTo(OssMetricsRegistry.KUBE_POD_PROCESS_CREATE_TIME_MILLISECS.getMetricName());
assertThat(data.getDescription()).isEqualTo(OssMetricsRegistry.KUBE_POD_PROCESS_CREATE_TIME_MILLISECS.getMetricDescription());
assertThat(data.getHistogramData().getPoints().stream().anyMatch(histogramPointData -> histogramPointData.getMax() == 30.0));
assertThat(data.getHistogramData().getPoints().stream().anyMatch(histogramPointData -> histogramPointData.getMin() == 10.0));
}

}
2 changes: 2 additions & 0 deletions deps.toml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ findsecbugs-plugin = { module = "com.h3xstream.findsecbugs:findsecbugs-plugin",
spotbugs-annotations = { module = "com.github.spotbugs:spotbugs-annotations", version = "4.6.0" }
otel-bom = {module = "io.opentelemetry:opentelemetry-bom", version = "1.14.0"}
otel-semconv = {module = "io.opentelemetry:opentelemetry-semconv", version = "1.14.0-alpha"}
otel-sdk = {module = "io.opentelemetry:opentelemetry-sdk-metrics", version = "1.14.0"}
otel-sdk-testing = {module = "io.opentelemetry:opentelemetry-sdk-metrics-testing", version = "1.13.0-alpha"}

[bundles]
jackson = ["jackson-databind", "jackson-annotations", "jackson-dataformat", "jackson-datatype"]
Expand Down

0 comments on commit 9d060a9

Please sign in to comment.