Skip to content

Commit

Permalink
Enhance OpenTelemetry's DropTargetsSampler
Browse files Browse the repository at this point in the history
This allows us to move effectively drop traces
belonging to SwaggerUI and other framework endpoints

Fixes: quarkusio#34376
  • Loading branch information
geoand committed Jul 4, 2023
1 parent f92ac9a commit b8b2c37
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,44 @@ public SamplingResult shouldSample(Context parentContext, String traceId, String

if (spanKind.equals(SpanKind.SERVER)) {
String target = attributes.get(SemanticAttributes.HTTP_TARGET);
// TODO - radcortez - Match /* endpoints
if (target != null && dropTargets.contains(target)) {
if (shouldDrop(target)) {
return SamplingResult.drop();
}
}

return sampler.shouldSample(parentContext, traceId, name, spanKind, attributes, parentLinks);
}

/**
* Determines whether a path should be dropped
* TODO: this can certainly be optimized if we find that it's a hot-path
*/
private boolean shouldDrop(String target) {
if ((target == null) || target.isEmpty()) {
return false;
}
if (safeContains(target)) { // check exact match
return true;
}
if (target.charAt(target.length() - 1) == '/') { // check if the path without the ending slash matched
if (safeContains(target.substring(0, target.length() - 1))) {
return true;
}
}
int lastSlashIndex = target.lastIndexOf('/');
if (lastSlashIndex != -1) {
if (safeContains(target.substring(0, lastSlashIndex) + "*")
|| safeContains(target.substring(0, lastSlashIndex) + "/*")) { // check if a wildcard matches
return true;
}
}
return false;
}

private boolean safeContains(String target) {
return dropTargets.contains(target);
}

@Override
public String getDescription() {
return sampler.getDescription();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package io.quarkus.opentelemetry.runtime.tracing;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

import org.junit.jupiter.api.Test;

import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.context.Context;
import io.opentelemetry.sdk.trace.data.LinkData;
import io.opentelemetry.sdk.trace.samplers.Sampler;
import io.opentelemetry.sdk.trace.samplers.SamplingResult;
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;

class DropTargetsSamplerTest {

@Test
void testDropTargets() {
CountingSampler countingSampler = new CountingSampler();
var sut = new DropTargetsSampler(countingSampler, List.of("/q/swagger-ui", "/q/swagger-ui*"));

assertEquals(SamplingResult.recordAndSample(), getShouldSample(sut, "/other"));
assertEquals(1, countingSampler.count.get());

assertEquals(SamplingResult.drop(), getShouldSample(sut, "/q/swagger-ui"));
assertEquals(1, countingSampler.count.get());

assertEquals(SamplingResult.drop(), getShouldSample(sut, "/q/swagger-ui/"));
assertEquals(1, countingSampler.count.get());

assertEquals(SamplingResult.drop(), getShouldSample(sut, "/q/swagger-ui/whatever"));
assertEquals(1, countingSampler.count.get());

assertEquals(SamplingResult.recordAndSample(), getShouldSample(sut, "/q/test"));
assertEquals(2, countingSampler.count.get());
}

private static SamplingResult getShouldSample(DropTargetsSampler sut, String target) {
return sut.shouldSample(null, null, null, SpanKind.SERVER,
Attributes.of(SemanticAttributes.HTTP_TARGET, target), null);
}

private static final class CountingSampler implements Sampler {

final AtomicLong count = new AtomicLong(0);

@Override
public SamplingResult shouldSample(Context parentContext, String traceId, String name, SpanKind spanKind,
Attributes attributes, List<LinkData> parentLinks) {
count.incrementAndGet();
return SamplingResult.recordAndSample();
}

@Override
public String getDescription() {
return "test";
}
}
}

0 comments on commit b8b2c37

Please sign in to comment.