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

HttpAttributesVisitor Not Invoked for Auto-Instrumented HTTP Calls #385

Open
1DevNawaf opened this issue Jan 27, 2025 · 1 comment
Open

Comments

@1DevNawaf
Copy link

Description

I’m using the Elastic APM Android SDK (auto-instrumentation) to capture HTTP calls in my Android application. According to the [official documentation](https://www.elastic.co/guide/en/apm/guide/current/), I can implement a custom HttpAttributesVisitor and add it to the HttpTraceConfiguration to modify or add attributes (e.g., rename spans to include the endpoint path). However, my custom visitor is never invoked during runtime, and no logs appear to show that it’s being accessed.


Steps to Reproduce

  1. Initialize the agent in Application.onCreate() (or a similar place) with enableHttpTracing(true):
    class ApmAttributesVisitor : HttpAttributesVisitor {
        override fun visit(builder: AttributesBuilder, request: HttpRequest) {
            Log.d("ApmAgentLogs", "Enter Visitor fun")
            val uri = Uri.parse(request.url.toString())
            val rawPath = uri.path ?: "/"
            builder.put("http.route", rawPath)
        }
    }
    
    val httpTraceConfig = HttpTraceConfiguration.builder()
        .addHttpAttributesVisitor(ApmAttributesVisitor())
        .build()
    
    val instrumentationsConfig = InstrumentationConfiguration.builder()
        .enableHttpTracing(true)
        .build()
    
    val elasticConfig = ElasticApmConfiguration.builder()
        .setHttpTraceConfiguration(httpTraceConfig)
        .setInstrumentationConfiguration(instrumentationsConfig)
        .setServiceName("MyServiceName")
        .build()
    
    ElasticApmAgent.initialize(application, elasticConfig)
  2. Make network calls using OkHttp or another supported library.
  3. Observe that the HTTP spans appear in APM (named HTTP GET or HTTP POST), but the custom visitor’s code never runs (no log statements, no custom attributes visible).

Expected Behavior

  • The HttpAttributesVisitor should be called for every auto-instrumented HTTP request.
  • My custom log (Log.d("MyTest", ...)) should appear in Logcat.
  • Additional attributes (e.g., "http.route") or custom data should be visible in the APM UI.

Actual Behavior

  • HTTP requests are auto-instrumented and show up in APM as HTTP GET or HTTP POST, but the custom visitor code is never triggered.
  • No logs from HttpAttributesVisitor.
  • No additional attributes in APM.

Workarounds Tried

  • Verified that the agent initializes before any network calls.
  • Attempted HttpFilter or different approaches to confirm instrumentation. Only the default BasicHttpAttributesVisitor output is visible.
  • Tried using various attributes (http.route, http.target) to see if any rename logic might appear.
  • Disabled auto-instrumentation and used manual instrumentation, which works but defeats the purpose of a HttpAttributesVisitor.

Request

  • Please confirm if HttpTraceConfiguration with a custom HttpAttributesVisitor is fully supported in this SDK version for auto-instrumented OkHttp calls.
  • If it is supported, is there additional configuration needed (e.g., a separate artifact or version mismatch)?
  • Any guidance on why the visitor might never be invoked would be very helpful.

Thanks in advance!

@LikeTheSalad
Copy link
Contributor

Hi @1DevNawaf

Thank you for describing your issue with this level of detail! By the time the HTTP attr visitor config was developed, we were using an in-house automatic instrumentation tool for OkHttp requests, which was later replaced by the OTel Android version which didn't support this kind of configurability. We're planning to work alongside the OTel community to make sure to add these kinds of options upstream, though at the moment our priority is releasing this agent's first stable version 1.0.0, so unfortunately we won't be able to contribute that change soon.

Having said that, I took some time to find a workaround that you could use in the meantime, and I think I have something that should help. This workaround consists of creating your own SpanProcessor where you can modify all spans created by your app, and the way to do so is by "injecting" said SpanProcessor to the Elastic Agent configuration via a wrapper SignalConfiguration. Here's an example of how that could work:

First, you'll need to create an implementation of SignalConfiguration like the following:

class MySignalConfiguration(private val delegate: SignalConfiguration) : SignalConfiguration {

    override fun getSpanProcessor(): SpanProcessor {
        return SpanProcessor.composite(MySpanProcessor(), delegate.spanProcessor)
    }

    override fun getLogProcessor(): LogRecordProcessor {
        return delegate.logProcessor
    }

    override fun getMetricReader(): MetricReader {
        return delegate.metricReader
    }

    class MySpanProcessor : SpanProcessor {

        override fun onStart(parentContext: Context, span: ReadWriteSpan) {
            if (span.getAttribute(AttributeKey.stringKey("url.full")) != null) {
                // This is an http span
                // TODO modify span
            }
        }

        override fun isStartRequired(): Boolean = true

        override fun onEnd(span: ReadableSpan) {
        }

        override fun isEndRequired(): Boolean = false

    }
}

After that, the next step is to use this MySignalConfiguration implementation when initializing ElasticApmAgent like so:

    override fun onCreate() {
        super.onCreate()
        ElasticApmAgent.initialize(
            this, ElasticApmConfiguration.builder()
                .setSignalConfiguration(MySignalConfiguration(SignalConfiguration.getDefault()))
                .build()
        )
    }

And that should do the trick for now. Please let me know if you have any questions and thanks for your patience. We're working to make these kinds of options easier to use and more flexible for our next version 1.0.0, I'll tag this issue as one of the required for 1.0.0 to make sure not to forget about this use case.

@LikeTheSalad LikeTheSalad self-assigned this Jan 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants