Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4.x Associate tracer-level tags with Jaeger process level (instead of span level) #8764

Merged
merged 2 commits into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions tracing/providers/jaeger/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,12 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<!-- Separate the baggage prop test to avoid interference with other tests -->
<!-- Separate some of the tests to avoid interference with other tests -->
<executions>
<execution>
<id>default-test</id>
<configuration>
<excludes>**/JaegerBaggagePropagationTest.java</excludes>
<excludes>**/JaegerBaggagePropagationTest.java,**/JaegerTracerBuilderTest.java</excludes>
</configuration>
</execution>
<execution>
Expand All @@ -176,6 +176,20 @@
<includes>**/JaegerBaggagePropagationTest.java</includes>
</configuration>
</execution>
<execution>
<id>tracer-builder-tests</id>
<goals>
<goal>test</goal>
</goals>
<configuration>
<properties>
<configurationParameters>
junit.jupiter.extensions.autodetection.enabled = true
</configurationParameters>
</properties>
<includes>**/JaegerTracerBuilderTest.java</includes>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.lang.System.Logger.Level;
import java.time.Duration;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
Expand All @@ -37,6 +38,7 @@
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.context.propagation.ContextPropagators;
import io.opentelemetry.context.propagation.TextMapPropagator;
import io.opentelemetry.exporter.jaeger.JaegerGrpcSpanExporter;
Expand All @@ -46,6 +48,7 @@
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder;
import io.opentelemetry.sdk.trace.SpanProcessor;
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor;
Expand Down Expand Up @@ -179,6 +182,7 @@ public class JaegerTracerBuilder implements TracerBuilder<JaegerTracerBuilder> {
private int maxQueueSize = DEFAULT_MAX_QUEUE_SIZE;
private int maxExportBatchSize = DEFAULT_MAX_EXPORT_BATCH_SIZE;
private SpanProcessorType spanProcessorType = SpanProcessorType.BATCH;
private final List<SpanExporter> adHocExporters = new ArrayList<>(); // primarily for testing


/**
Expand Down Expand Up @@ -512,17 +516,25 @@ public Tracer build() {
: Sampler.alwaysOff();
};

Resource serviceName = Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, this.serviceName));
AttributesBuilder attributesBuilder = Attributes.builder()
.put(ResourceAttributes.SERVICE_NAME, serviceName);
tags.forEach(attributesBuilder::put);
Resource otelResource = Resource.create(attributesBuilder.build());

SdkTracerProviderBuilder sdkTracerProviderBuilder = SdkTracerProvider.builder()
.setSampler(sampler)
.setResource(otelResource)
.addSpanProcessor(spanProcessor(exporter));
adHocExporters.stream()
.map(this::spanProcessor)
.forEach(sdkTracerProviderBuilder::addSpanProcessor);

OpenTelemetry ot = OpenTelemetrySdk.builder()
.setTracerProvider(SdkTracerProvider.builder()
.addSpanProcessor(spanProcessor(exporter))
.setSampler(sampler)
.setResource(serviceName)
.build())
.setTracerProvider(sdkTracerProviderBuilder.build())
.setPropagators(ContextPropagators.create(TextMapPropagator.composite(createPropagators())))
.build();

result = HelidonOpenTelemetry.create(ot, ot.getTracer(this.serviceName), tags);
result = HelidonOpenTelemetry.create(ot, ot.getTracer(this.serviceName), Map.of());

if (global) {
GlobalOpenTelemetry.set(ot);
Expand Down Expand Up @@ -604,6 +616,12 @@ List<TextMapPropagator> createPropagators() {
.toList();
}

// Primarily for testing
JaegerTracerBuilder exporter(SpanExporter spanExporter) {
adHocExporters.add(spanExporter);
return this;
}

private SpanProcessor spanProcessor(SpanExporter exporter) {
return switch (spanProcessorType) {
case BATCH -> BatchSpanProcessor.builder(exporter)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2023 Oracle and/or its affiliates.
* Copyright (c) 2019, 2024 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -21,13 +21,18 @@
import java.util.Map;

import io.helidon.config.Config;
import io.helidon.tracing.Span;
import io.helidon.tracing.Tracer;
import io.helidon.tracing.TracerBuilder;
import io.helidon.tracing.providers.opentelemetry.HelidonOpenTelemetry;

import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.context.propagation.TextMapPropagator;
import io.opentelemetry.extension.trace.propagation.B3Propagator;
import io.opentelemetry.extension.trace.propagation.JaegerPropagator;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.trace.data.SpanData;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

Expand Down Expand Up @@ -126,4 +131,27 @@ void testFullHttp() {
assertThat(propagators.get(1), instanceOf(JaegerPropagator.class));
assertThat(propagators.get(2), instanceOf(W3CBaggagePropagator.class));
}

@Test
void testProcessTagHandling() {
TracerBuilder<?> builder = TracerBuilder.create(config.get("jaeger-defaults"));
builder.addTracerTag("tracerLevelTag", "val-1");
JaegerTracerBuilder jaegerTracerBuilder = builder.unwrap(JaegerTracerBuilder.class);
jaegerTracerBuilder.scheduleDelay(Duration.ofMillis(100)); // for faster test runs
jaegerTracerBuilder.exporter(new TestSpanExporterProvider().createExporter(null));
Tracer tracer = builder.build();

Span span = tracer.spanBuilder("testSpan").tag("spanLevelTag", "val-2").start();
span.end();

try (TestSpanExporter exporter = TestSpanExporterProvider.exporter()) {
List<SpanData> spanData = exporter.spanData(1);
assertThat("Expect span count", spanData.size(), is(1));
SpanData spanDataItem = spanData.get(0);
assertThat("Trace-level attribute tracerLevelTag",
spanDataItem.getResource().getAttributes().get(AttributeKey.stringKey("tracerLevelTag")),
is("val-1"));
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates.
*
* 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.helidon.tracing.providers.jaeger;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import io.helidon.common.testing.junit5.MatcherWithRetry;

import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.trace.data.SpanData;
import io.opentelemetry.sdk.trace.export.SpanExporter;

import static org.hamcrest.Matchers.iterableWithSize;

// Partially inspired by the MP Telemetry TCK InMemorySpanExporter.
public class TestSpanExporter implements SpanExporter {

private final List<SpanData> spanData = new CopyOnWriteArrayList<>();
private final System.Logger LOGGER = System.getLogger(TestSpanExporter.class.getName());

private final int RETRY_COUNT = Integer.getInteger(TestSpanExporter.class.getName() + ".test.retryCount", 120);
private final int RETRY_DELAY_MS = Integer.getInteger(TestSpanExporter.class.getName() + ".test.retryDelayMs", 500);


private enum State {READY, STOPPED}

private State state = State.READY;

@Override
public CompletableResultCode export(Collection<SpanData> collection) {
if (state == State.STOPPED) {
return CompletableResultCode.ofFailure();
}
spanData.addAll(collection);
return CompletableResultCode.ofSuccess();
}

@Override
public CompletableResultCode flush() {
return CompletableResultCode.ofSuccess();
}

@Override
public CompletableResultCode shutdown() {
state = State.STOPPED;
spanData.clear();
return CompletableResultCode.ofSuccess();
}

List<SpanData> spanData(int expectedCount) {
long startTime = 0;
if (LOGGER.isLoggable(System.Logger.Level.DEBUG)) {
startTime = System.currentTimeMillis();
}
var result = MatcherWithRetry.assertThatWithRetry("Expected span count",
() -> new ArrayList<>(spanData),
iterableWithSize(expectedCount),
RETRY_COUNT,
RETRY_DELAY_MS);
if (LOGGER.isLoggable(System.Logger.Level.DEBUG)) {
LOGGER.log(System.Logger.Level.DEBUG, "spanData waited "
+ (System.currentTimeMillis() - startTime)
+ " ms for expected spans to arrive.");
}
return result;
}

void clear() {
spanData.clear();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates.
*
* 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.helidon.tracing.providers.jaeger;

import io.helidon.common.LazyValue;

import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider;
import io.opentelemetry.sdk.trace.export.SpanExporter;

public class TestSpanExporterProvider implements ConfigurableSpanExporterProvider {

private static final LazyValue<TestSpanExporter> SPAN_EXPORTER = LazyValue.create(TestSpanExporter::new);

public TestSpanExporterProvider() {
System.err.println("provider ctor");
}

@Override
public SpanExporter createExporter(ConfigProperties configProperties) {
return SPAN_EXPORTER.get();
}

@Override
public String getName() {
return "in-memory";
}

static TestSpanExporter exporter() {
if (SPAN_EXPORTER.isLoaded()) {
return SPAN_EXPORTER.get();
}
throw new IllegalStateException("Attempt to retrieve TestSpanExporter before it has been created");
}
}