[ 
https://issues.apache.org/jira/browse/HTTPCLIENT-2438?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Arturo Bernal updated HTTPCLIENT-2438:
--------------------------------------
    Priority: Minor  (was: Major)

> AsyncIoByteCounterExec keeps tags from previous requests
> --------------------------------------------------------
>
>                 Key: HTTPCLIENT-2438
>                 URL: https://issues.apache.org/jira/browse/HTTPCLIENT-2438
>             Project: HttpComponents HttpClient
>          Issue Type: Bug
>    Affects Versions: 5.6.3, 5.6.4, 5.6.5
>            Reporter: seongsu shin
>            Priority: Minor
>          Time Spent: 10m
>  Remaining Estimate: 0h
>
> h2. Summary
> With the IO metric set on the async client, the request.bytes / 
> response.bytes counters can get tags from an earlier request. If one request 
> gets a tag that the others don't have, all requests after it are counted with 
> that tag too. The classic client is fine.
> h2. Cause
> AsyncIoByteCounterExec creates the two Counter.Builder instances once in the 
> constructor and keeps them in fields. record() then does this for every 
> request:
> {code:java}
> reqBuilder.tags(tags).tags(mc.commonTags).register(meterRegistry).increment(reqBytes);
> {code}
> Counter.Builder.tags() adds to the tags the builder already has, it doesn't 
> replace them. method and status are on every request so they just get 
> overwritten, but any other tag stays on the builder and is used for every 
> request after that.
> IoByteCounterExec creates a new builder on each call, and there is a comment 
> there saying it's done to avoid tag accumulation, so I guess the async one 
> was just missed.
> h2. Why it matters
> If you use a tagCustomizer that adds a tag only for some requests (tenant, 
> endpoint name, etc.), the byte counters for that tag end up including traffic 
> that has nothing to do with it. Nothing fails or gets logged, so the numbers 
> just look normal but are wrong.
> Also the same builder is shared across all requests of the client and 
> Counter.Builder isn't thread safe, so concurrent requests could mix their 
> tags as well. I didn't try to reproduce that part.
> h2. How to reproduce
> Async client, IO metric set, and a tagCustomizer that adds a tag only for /a:
> {code:java}
> ObservingOptions opts = ObservingOptions.builder()
>         .metrics(EnumSet.of(ObservingOptions.MetricSet.IO))
>         .tagCustomizer((tags, method, status, protocol, target, uri) -> {
>             List<Tag> out = new ArrayList<>(tags);
>             if (uri.startsWith("/a")) {
>                 out.add(Tag.of("only_for_a", "yes"));
>             }
>             return out;
>         })
>         .build();
> HttpClientObservationSupport.enable(builder, null, meterRegistry, opts, 
> MetricConfig.DEFAULT);
> {code}
> Send GET /a (200), then GET /b (404), and look at the response.bytes 
> counters. Did the same with the classic client to compare.
> h2. Observed
> {noformat}
> async:
>   total=4 [method=GET, only_for_a=yes, status=200]
>   total=2 [method=GET, only_for_a=yes, status=404]
> classic:
>   total=4 [method=GET, only_for_a=yes, status=200]
>   total=2 [method=GET, status=404]
> {noformat}
> /b has only_for_a=yes on the async client.
> h2. Expected
> /b should only have its own tags, same as classic.
> h2. Notes
> Creating the builders inside record() like IoByteCounterExec does should fix 
> it. I can open a PR with a test if that sounds ok.
> PR #920 also changes this class (uri tag) but not this part.



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to