Skip to content

Define ignoreURLs generic use case and weigh different technical approaches #1686

@surbhiia

Description

@surbhiia

Use case

  • Ignore URLs matching a pattern from being traced by HTTP instrumentations.
  • If URL is ignored on the client side, server should also get the knowledge that this was ignored on client.

Techincal Approaches

1. Sampler (Exists)

val urlBlocklistSampler = object : Sampler {
    override fun shouldSample(
        parentContext: Context,
        traceId: String,
        name: String,
        spanKind: SpanKind,
        attributes: Attributes,
        parentLinks: List<LinkData>,
    ): SamplingResult {
        val url = attributes.get(AttributeKey.stringKey("url.full"))
        if (url != null && shouldIgnoreUrl(url)) { //shouldIgnoreUrl function uses ignoreURL pattern config provided by customer
            return SamplingResult.drop()
        }
        return Sampler.parentBased(Sampler.alwaysOn()).shouldSample(
            parentContext, traceId, name, spanKind, attributes, parentLinks,
        )
    }
    override fun getDescription(): String = "UrlBlocklistSampler"
}

// When building Opentelemetry Tracer provider, add the sampler
SdkTracerProvider.builder().setSampler(urlBlocklistSampler)

2. Instrumentation level configuration (Needs Implementation)

Upgrade the TracingInterceptor and ConnectionErrorInterceptor

2.1 ConnectionErrorInterceptor

@Override
public Response intercept(Chain chain) throws IOException {
    Request request = chain.request();
   
    //Add this if statement to support ignoreURLs use case
    if (shouldIgnoreUrl(request.url())) {
        return chain.proceed(request);
    }

    Context parentContext = Context.current();
    Response response = null;
    Throwable error = null;
    Instant startTime = Instant.now();
    try {
        response = chain.proceed(request);
        return response;
    } catch (Throwable t) {
        error = t;
        throw t;
    } finally {
        if (HttpClientRequestResendCount.get(parentContext) == 0) {
            if (instrumenter.shouldStart(parentContext, chain)) {
                InstrumenterUtil.startAndEnd(
                    instrumenter, parentContext, chain, response, error, startTime, Instant.now());
            }
        }
    }
}

2.2 TracingInterceptor

@Override
public Response intercept(Chain chain) throws IOException {
    Request request = chain.request();
    Context parentContext = Context.current();

   //Add this if statement to support ignoreURLs use case
    if (shouldIgnoreUrl(request.url())) { 
       <Generate a span id and propagate w3c traceparent context to server with sample flag as dropped even if url is ignored>    
        return chain.proceed(injected);
    }

    if (!instrumenter.shouldStart(parentContext, chain)) {
        return chain.proceed(chain.request());
    }
    Context context = instrumenter.start(parentContext, chain);
    request = injectContextToRequest(request, context);
    Response response;
    try (Scope ignored = context.makeCurrent()) {
        response = chain.proceed(request);
    } catch (Throwable t) {
        instrumenter.end(context, chain, null, t);
        throw t;
    }
    instrumenter.end(context, chain, response, null);
    return response;
}

Note - Using suppression context key is not an option as that would mean that all requests originating within that context independent of the URL will be ignored and that is not something we want.

Open Questions

  • Is use case complete? Is there more or less things we need to consider?
  • What approach is preferred and why?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions