# Java APM tag external http request made with reactive webclient

**URL:** <https://discuss.elastic.co/t/java-apm-tag-external-http-request-made-with-reactive-webclient/324263>\
**Category:** APM\
**Tags:** java\
**Created:** [January 30, 2023, 6:09pm UTC](https://discuss.elastic.co/t/java-apm-tag-external-http-request-made-with-reactive-webclient/324263 "2023-01-30T18:09:01Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![mrodal](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/mrodal/32/116446_2.png) [@mrodal](https://discuss.elastic.co/u/mrodal)\
**Post date:** [January 30, 2023, 6:09pm UTC](https://discuss.elastic.co/t/java-apm-tag-external-http-request-made-with-reactive-webclient/324263/1 "2023-01-30T18:09:01Z")

</div>

**Kibana version** : 8.6

**Elasticsearch version** : 8.6

**APM Server version** : 8.6

**APM Agent language and version** : 1.35.0

**Browser version** : -

**Original install method (e.g. download page, yum, deb, from source, etc.) and version**: Download page

**Fresh install or upgraded from other version?** : Fresh

**Is there anything special in your setup?** No

**Description of the problem including expected versus actual behavior. Please include screenshots (if relevant)**:  
Im trying to tag external http requests made with webclient. Based on [this issue](https://discuss.elastic.co/t/java-apm-agent-doesnt-capture-text-or-json-body/324064/4), im trying to use a webclient filter to get the current span and add a tag, but the current span I get is the parent one, not the external request span.

Looks like the external span is not started when the filter is executed, the filter executes before [this method](https://github.com/elastic/apm-agent-java/blob/main/apm-agent-plugins/apm-spring-webflux/apm-spring-webclient-plugin/src/main/java/co/elastic/apm/agent/springwebclient/WebClientExchangeFunctionInstrumentation.java#L76).

I believe the span should be started before in the call stack to allow this customization, [here](https://github.com/spring-projects/spring-framework/blob/main/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java#L454) perhaps.

---

<div class="post-metadata">

**Author:** ![carly.richmond](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/carly.richmond/32/104935_2.png) [@carly.richmond](https://discuss.elastic.co/u/carly.richmond)\
**Post date:** [January 31, 2023, 11:04am UTC](https://discuss.elastic.co/t/java-apm-tag-external-http-request-made-with-reactive-webclient/324263/2 "2023-01-31T11:04:28Z")

</div>

Hi mrodal,

Thanks for the details. Had a chat with the team and they are taking a look. We'll keep you posted!

---

<div class="post-metadata">

**Author:** ![Jonas\_Kunz](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/jonas_kunz/32/110740_2.png) [@Jonas\_Kunz](https://discuss.elastic.co/u/Jonas_Kunz)\
**Post date:** [January 31, 2023, 11:37am UTC](https://discuss.elastic.co/t/java-apm-tag-external-http-request-made-with-reactive-webclient/324263/3 "2023-01-31T11:37:31Z")

</div>

Hi @mrodal,  
Could you please share a snippet of how you use the spring webclient?  
Unfortunately the reactive nature of the webclient makes it very hard to propagate the context to every possible location.

I tried locally, the span should be available within the lambda passed to the `exchange` methods:

```auto
client.get().uri(uri).exchangeToFlux(response -> {
                            Span span = ElasticApm.currentSpan(); //should be the correct span here
                            return response.bodyToFlux(String.class);
                        }
                    )
                    .blockLast();

```

---

<div class="post-metadata">

**Author:** ![mrodal](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/mrodal/32/116446_2.png) [@mrodal](https://discuss.elastic.co/u/mrodal)\
**Post date:** [January 31, 2023, 3:58pm UTC](https://discuss.elastic.co/t/java-apm-tag-external-http-request-made-with-reactive-webclient/324263/4 "2023-01-31T15:58:51Z")

</div>

Hi @Jonas_Kunz ,  
The idea wat to apply a similar approach to the interceptors with restTemplate (which work as expected) using webclient filter functions to apply the span transformations to all subsequent requests.

I had not tried your approach getting the span on the exchange function, it would require to add the label on each request, but it could work as last resort. The issue is that I also get the parent transaction there, heres my code:

```auto
WebClient client = WebClient.builder()
        .filter((clientRequest, next) -> {
            ElasticApm.currentSpan().setLabel("label1", "from weblcient filter");
            return next.exchange(clientRequest);
        })
        .build();

String response = client.post()
        .uri("https://httpbin.org/post")
        .body(BodyInserters.fromValue("test body"))
        .exchangeToMono(response -> {
                    Span span = ElasticApm.currentSpan().setLabel("label2", "from exchangeToMono");
                    return response.bodyToMono(String.class);
                }
        )
        .block();

```

I apply a label on the filter function and another one on exchangeToMono, but I get both applied to the parent transaction:

 ![image](https://us1.discourse-cdn.com/elastic/original/3X/7/d/7dd9c442130b16bab6c3ab83ab6e407906c4c76e.png)

---

<div class="post-metadata">

**Author:** ![Jonas\_Kunz](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/jonas_kunz/32/110740_2.png) [@Jonas\_Kunz](https://discuss.elastic.co/u/Jonas_Kunz)\
**Post date:** [February 1, 2023, 9:49am UTC](https://discuss.elastic.co/t/java-apm-tag-external-http-request-made-with-reactive-webclient/324263/5 "2023-02-01T09:49:45Z")

</div>

I was able to reproduce the behaviour you described. I think I initially missed this because I had the webflux instrumentation disabled.

Anyway, I think I found a solution which should work in your case:

```auto
    private static class SpanAwareExchangeFunction implements ExchangeFunction {

        private final ExchangeFunction delegate;

        private final Consumer<Span> actions;

        public SpanAwareExchangeFunction(ExchangeFunction delegate, Consumer<Span> actions) {
            this.delegate = delegate;
            this.actions = actions;
        }

        @Override
        public Mono<ClientResponse> exchange(ClientRequest request) {
            actions.accept(ElasticApm.currentSpan());
            return delegate.exchange(request);
        }
    }

    private static void doWebclientRequest() {
        WebClient client = WebClient.builder()
                .filter((clientRequest, next) ->
                    new SpanAwareExchangeFunction(next, span -> {
                        span.setLabel("label1", "from webclient filter");
                    }).exchange(clientRequest)
                )
                .build();

        String response = client.get()
                .uri("https://httpbin.org/get")
                .exchangeToMono(response -> response.bodyToMono(String.class))
                .block();
    }

```

Why does this work? Our webclient instrumentation targets classes implementing the spring `ExchangeFunction` interface which also have `ExchangeFunction` in their name. This means in the code above the span is already started within `SpanAwareExchangeFunction` and therefore is accessible to you. It is important that `SpanAwareExchangeFunction` is not a lambda, so that the name contains "ExchangeFunction", because otherwise it will not be instrumented.

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/elastic/original/3X/1/a/1ac57faf039f6b580b3f104ef42a2a89e41014de.png) [@system](https://discuss.elastic.co/u/system)\
**Post date:** [February 22, 2023, 5:50am UTC](https://discuss.elastic.co/t/java-apm-tag-external-http-request-made-with-reactive-webclient/324263/6 "2023-02-22T05:50:31Z")

</div>

This topic was automatically closed 20 days after the last reply. New replies are no longer allowed.
