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

fix: httpjson callables to trace attempts (started, failed) #3300

Merged
merged 30 commits into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
6635019
add test to confirm tracer attempts failed
diegomarquezp Oct 21, 2024
944e8d6
simplify test for retries
diegomarquezp Oct 21, 2024
1edf557
Merge remote-tracking branch 'origin/main' into fix-httpjson-retry-me…
diegomarquezp Oct 21, 2024
4db1d2b
extend tracer tests to every test
diegomarquezp Oct 21, 2024
9ab23d5
fix test vars initialization
diegomarquezp Oct 21, 2024
6364aab
add retrial exhaustion check
diegomarquezp Oct 21, 2024
ae1eb44
Merge branch 'main' into fix-httpjson-retry-metrics
diegomarquezp Oct 22, 2024
1ebc3a2
restore ApiException expected in test
diegomarquezp Oct 24, 2024
25e778f
Merge branch 'fix-httpjson-retry-metrics' of https://github.com/googl…
diegomarquezp Oct 24, 2024
b363a29
enable Disabled ITs
diegomarquezp Oct 24, 2024
5c11e10
try fixing multipleattempts test
diegomarquezp Oct 24, 2024
9b48dbe
Merge branch 'main' into fix-httpjson-retry-metrics
diegomarquezp Oct 24, 2024
c8e8a7d
fix multiple attempts httpjson test (thanks @lqiu96)
diegomarquezp Oct 25, 2024
af3adb5
Merge remote-tracking branch 'refs/remotes/origin/fix-httpjson-retry-…
diegomarquezp Oct 25, 2024
035be17
extract tracer factory to its own method
diegomarquezp Oct 25, 2024
8e2a58a
add comments
diegomarquezp Oct 25, 2024
8f3331e
Merge branch 'fix-httpjson-retry-metrics' of https://github.com/googl…
diegomarquezp Oct 25, 2024
f647320
Merge remote-tracking branch 'origin/main' into fix-httpjson-retry-me…
diegomarquezp Oct 25, 2024
2df2e9f
licence
diegomarquezp Oct 25, 2024
e7bc1c3
formalize tests
diegomarquezp Oct 30, 2024
e2385ad
rename vars, extend ApiTracer
diegomarquezp Oct 31, 2024
58e874a
move initialization to contained class
diegomarquezp Oct 31, 2024
87f807a
fix order of methods
diegomarquezp Oct 31, 2024
e57b4db
remove retries exhausted
diegomarquezp Nov 4, 2024
58a0daa
Revert "remove retries exhausted"
diegomarquezp Nov 4, 2024
325eba4
record attempt failed when retries are exhausted
diegomarquezp Nov 4, 2024
2120960
adjust retries count in retryingtest
diegomarquezp Nov 4, 2024
0630fdf
Merge branch 'main' into fix-httpjson-retry-metrics
diegomarquezp Nov 11, 2024
9697e8a
empty commit to retry tests
diegomarquezp Nov 11, 2024
065b01f
remove flaky tests
diegomarquezp Nov 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ static <RequestT, ResponseT> UnaryCallable<RequestT, ResponseT> createUnaryCalla
callable =
Callables.retrying(
callable, callSettings, clientContext, httpJsonCallSettings.getRequestMutator());
callable =
new TracedUnaryCallable<>(
callable,
clientContext.getTracerFactory(),
getSpanName(httpJsonCallSettings.getMethodDescriptor()));
return callable.withDefaultCallContext(clientContext.getDefaultCallContext());
}

Expand Down Expand Up @@ -136,12 +141,6 @@ public static <RequestT, ResponseT> UnaryCallable<RequestT, ResponseT> createUna
UnaryCallable<RequestT, ResponseT> innerCallable =
createDirectUnaryCallable(httpJsonCallSettings);

innerCallable =
new TracedUnaryCallable<>(
innerCallable,
clientContext.getTracerFactory(),
getSpanName(httpJsonCallSettings.getMethodDescriptor()));

return createUnaryCallable(innerCallable, callSettings, httpJsonCallSettings, clientContext);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import com.google.api.core.ApiFutures;
import com.google.api.gax.core.FakeApiClock;
import com.google.api.gax.core.RecordingScheduler;
import com.google.api.gax.httpjson.testing.TestApiTracerFactory;
import com.google.api.gax.retrying.RetrySettings;
import com.google.api.gax.rpc.ApiCallContext;
import com.google.api.gax.rpc.ApiException;
Expand Down Expand Up @@ -80,6 +81,7 @@ class RetryingTest {

private final Integer initialRequest = 1;
private final Integer modifiedRequest = 0;
private TestApiTracerFactory tracerFactory;

private final HttpJsonCallSettings<Integer, Integer> httpJsonCallSettings =
HttpJsonCallSettings.<Integer, Integer>newBuilder()
Expand Down Expand Up @@ -115,8 +117,11 @@ class RetryingTest {
void resetClock() {
fakeClock = new FakeApiClock(System.nanoTime());
executor = RecordingScheduler.create(fakeClock);
tracerFactory = new TestApiTracerFactory();
clientContext =
ClientContext.newBuilder()
// we use a custom tracer to confirm whether the retrials are being recorded.
.setTracerFactory(tracerFactory)
.setExecutor(executor)
.setClock(fakeClock)
.setDefaultCallContext(HttpJsonCallContext.createDefault())
Expand All @@ -130,6 +135,7 @@ void teardown() {

@Test
void retry() {
// set a retriable that will fail 3 times before returning "2"
ImmutableSet<StatusCode.Code> retryable = ImmutableSet.of(Code.UNAVAILABLE);
Mockito.when(callInt.futureCall((Integer) any(), (ApiCallContext) any()))
.thenReturn(ApiFutures.<Integer>immediateFailedFuture(HTTP_SERVICE_UNAVAILABLE_EXCEPTION))
Expand All @@ -143,6 +149,10 @@ void retry() {
HttpJsonCallableFactory.createUnaryCallable(
callInt, callSettings, httpJsonCallSettings, clientContext);
assertThat(callable.call(initialRequest)).isEqualTo(2);
assertThat(tracerFactory.getTracerAttemptsFailed().get()).isEqualTo(3);
assertThat(tracerFactory.getTracerAttempts().get()).isEqualTo(4);
assertThat(tracerFactory.getTracerOperationFailed().get()).isEqualTo(false);
assertThat(tracerFactory.getTracerFailedRetriesExhausted().get()).isEqualTo(false);

// Capture the argument passed to futureCall
ArgumentCaptor<Integer> argumentCaptor = ArgumentCaptor.forClass(Integer.class);
Expand Down Expand Up @@ -180,6 +190,9 @@ void retryTotalTimeoutExceeded() {
HttpJsonCallableFactory.createUnaryCallable(
callInt, callSettings, httpJsonCallSettings, clientContext);
assertThrows(ApiException.class, () -> callable.call(initialRequest));
assertThat(tracerFactory.getTracerAttempts().get()).isEqualTo(1);
assertThat(tracerFactory.getTracerAttemptsFailed().get()).isEqualTo(0);
assertThat(tracerFactory.getTracerOperationFailed().get()).isEqualTo(true);
// Capture the argument passed to futureCall
ArgumentCaptor<Integer> argumentCaptor = ArgumentCaptor.forClass(Integer.class);
verify(callInt, atLeastOnce()).futureCall(argumentCaptor.capture(), any(ApiCallContext.class));
Expand All @@ -200,6 +213,9 @@ void retryMaxAttemptsExceeded() {
HttpJsonCallableFactory.createUnaryCallable(
callInt, callSettings, httpJsonCallSettings, clientContext);
assertThrows(ApiException.class, () -> callable.call(initialRequest));
assertThat(tracerFactory.getTracerAttempts().get()).isEqualTo(2);
assertThat(tracerFactory.getTracerAttemptsFailed().get()).isEqualTo(1);
lqiu96 marked this conversation as resolved.
Show resolved Hide resolved
assertThat(tracerFactory.getTracerFailedRetriesExhausted().get()).isEqualTo(true);
// Capture the argument passed to futureCall
ArgumentCaptor<Integer> argumentCaptor = ArgumentCaptor.forClass(Integer.class);
verify(callInt, atLeastOnce()).futureCall(argumentCaptor.capture(), any(ApiCallContext.class));
Expand All @@ -220,6 +236,9 @@ void retryWithinMaxAttempts() {
HttpJsonCallableFactory.createUnaryCallable(
callInt, callSettings, httpJsonCallSettings, clientContext);
assertThat(callable.call(initialRequest)).isEqualTo(2);
assertThat(tracerFactory.getTracerAttempts().get()).isEqualTo(3);
assertThat(tracerFactory.getTracerAttemptsFailed().get()).isEqualTo(2);
assertThat(tracerFactory.getTracerOperationFailed().get()).isEqualTo(false);
lqiu96 marked this conversation as resolved.
Show resolved Hide resolved
// Capture the argument passed to futureCall
ArgumentCaptor<Integer> argumentCaptor = ArgumentCaptor.forClass(Integer.class);
verify(callInt, atLeastOnce()).futureCall(argumentCaptor.capture(), any(ApiCallContext.class));
Expand All @@ -246,6 +265,9 @@ void retryOnStatusUnknown() {
HttpJsonCallableFactory.createUnaryCallable(
callInt, callSettings, httpJsonCallSettings, clientContext);
assertThat(callable.call(initialRequest)).isEqualTo(2);
assertThat(tracerFactory.getTracerAttempts().get()).isEqualTo(4);
assertThat(tracerFactory.getTracerAttemptsFailed().get()).isEqualTo(3);
assertThat(tracerFactory.getTracerOperationFailed().get()).isEqualTo(false);
lqiu96 marked this conversation as resolved.
Show resolved Hide resolved
// Capture the argument passed to futureCall
ArgumentCaptor<Integer> argumentCaptor = ArgumentCaptor.forClass(Integer.class);
verify(callInt, atLeastOnce()).futureCall(argumentCaptor.capture(), any(ApiCallContext.class));
Expand All @@ -264,6 +286,9 @@ void retryOnUnexpectedException() {
HttpJsonCallableFactory.createUnaryCallable(
callInt, callSettings, httpJsonCallSettings, clientContext);
ApiException exception = assertThrows(ApiException.class, () -> callable.call(initialRequest));
assertThat(tracerFactory.getTracerAttempts().get()).isEqualTo(1);
assertThat(tracerFactory.getTracerAttemptsFailed().get()).isEqualTo(0);
assertThat(tracerFactory.getTracerOperationFailed().get()).isEqualTo(true);
lqiu96 marked this conversation as resolved.
Show resolved Hide resolved
assertThat(exception).hasCauseThat().isSameInstanceAs(throwable);
// Capture the argument passed to futureCall
ArgumentCaptor<Integer> argumentCaptor = ArgumentCaptor.forClass(Integer.class);
Expand Down Expand Up @@ -293,6 +318,9 @@ void retryNoRecover() {
HttpJsonCallableFactory.createUnaryCallable(
callInt, callSettings, httpJsonCallSettings, clientContext);
ApiException exception = assertThrows(ApiException.class, () -> callable.call(initialRequest));
assertThat(tracerFactory.getTracerAttempts().get()).isEqualTo(1);
assertThat(tracerFactory.getTracerAttemptsFailed().get()).isEqualTo(0);
assertThat(tracerFactory.getTracerOperationFailed().get()).isEqualTo(true);
lqiu96 marked this conversation as resolved.
Show resolved Hide resolved
assertThat(exception).isSameInstanceAs(apiException);
// Capture the argument passed to futureCall
ArgumentCaptor<Integer> argumentCaptor = ArgumentCaptor.forClass(Integer.class);
Expand All @@ -319,6 +347,13 @@ void retryKeepFailing() {

UncheckedExecutionException exception =
assertThrows(UncheckedExecutionException.class, () -> Futures.getUnchecked(future));
// the number of attempts varies. Here we just make sure that all of them except the last are
// considered as failed
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

qq, isn't the last one also considered a failed attempt? Why is the tracerAttemptsFailed != tracerAttempts?

Also, can we add the operationfailed == true check here as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the tracerAttemptsFailed != tracerAttempts?

I'm not sure and I agree they should be the same value since this test just fetches an exception until it can't retry anymore (retries exhausted).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from discussion with @blakeli0, @lqiu96 and @zhumin8, let's double check TestApiTracer, confirm with showcase.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

showcase has another tracer we can use to cross check TestApiTracer

// attempts and that the operation was considered as failed.
assertThat(tracerFactory.getTracerAttemptsFailed().get()).isGreaterThan(0);
assertThat(tracerFactory.getTracerAttemptsFailed().get())
.isEqualTo(tracerFactory.getTracerAttempts().get() - 1);
assertThat(tracerFactory.getTracerFailedRetriesExhausted().get()).isEqualTo(true);
assertThat(exception).hasCauseThat().isInstanceOf(ApiException.class);
assertThat(exception).hasCauseThat().hasMessageThat().contains("Unavailable");
// Capture the argument passed to futureCall
Expand Down Expand Up @@ -359,6 +394,9 @@ void testKnownStatusCode() {
callInt, callSettings, httpJsonCallSettings, clientContext);
ApiException exception =
assertThrows(FailedPreconditionException.class, () -> callable.call(initialRequest));
assertThat(tracerFactory.getTracerAttempts().get()).isEqualTo(1);
assertThat(tracerFactory.getTracerAttemptsFailed().get()).isEqualTo(0);
assertThat(tracerFactory.getTracerOperationFailed().get()).isEqualTo(true);
assertThat(exception.getStatusCode().getTransportCode())
.isEqualTo(HTTP_CODE_PRECONDITION_FAILED);
assertThat(exception).hasMessageThat().contains("precondition failed");
Expand All @@ -383,6 +421,9 @@ void testUnknownStatusCode() {
UnknownException exception =
assertThrows(UnknownException.class, () -> callable.call(initialRequest));
assertThat(exception).hasMessageThat().isEqualTo("java.lang.RuntimeException: unknown");
assertThat(tracerFactory.getTracerAttempts().get()).isEqualTo(1);
assertThat(tracerFactory.getTracerAttemptsFailed().get()).isEqualTo(0);
assertThat(tracerFactory.getTracerOperationFailed().get()).isEqualTo(true);
// Capture the argument passed to futureCall
ArgumentCaptor<Integer> argumentCaptor = ArgumentCaptor.forClass(Integer.class);
verify(callInt, atLeastOnce()).futureCall(argumentCaptor.capture(), any(ApiCallContext.class));
Expand Down
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of a test tracer in general. On the other hand, we should only implement what is needed for our use cases, so that we have lower chance to run into issues that are not related to our PR. For example, maybe we don't need to implement attemptFailedRetriesExhausted.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lqiu96 figured that the retries exhausted event records the missing failed attempt in our tests:

It looks like attempt_count is recorded when this is called:

metricsRecorder.recordAttemptCount(1, attributes);
. This seems like the number recorded in Otel should be correct.
I'm guessing your TestApiTracer would need to increment the attemptCount when attemptFailedRetriesExhausted is called as well to match behavior.

I'll keep this implementation and its retries exhausted flag.

Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright 2024 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.google.api.gax.httpjson.testing;

import com.google.api.gax.tracing.BaseApiTracer;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import org.threeten.bp.Duration;

/**
* Test tracer that keeps count of different events. See {@link TestApiTracerFactory} for more
* details.
*/
public class TestApiTracer extends BaseApiTracer {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should use the interface ApiTracer instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


private final AtomicInteger tracerAttempts;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think they can be called just attempts, same for the fields below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renamed to attemptsStarted, removed the tracer prefix from all fields

private final AtomicInteger tracerAttemptsFailed;
private final AtomicBoolean tracerOperationFailed;
private final AtomicBoolean tracerFailedRetriesExhausted;

public TestApiTracer(
AtomicInteger tracerAttempts,
AtomicInteger tracerAttemptsFailed,
AtomicBoolean tracerOperationFailed,
AtomicBoolean tracerFailedRetriesExhausted) {
this.tracerAttempts = tracerAttempts;
this.tracerAttemptsFailed = tracerAttemptsFailed;
this.tracerOperationFailed = tracerOperationFailed;
this.tracerFailedRetriesExhausted = tracerFailedRetriesExhausted;
}

@Override
public void attemptFailed(Throwable error, Duration delay) {
tracerAttemptsFailed.incrementAndGet();
super.attemptFailed(error, delay);
}

@Override
public void attemptStarted(int attemptNumber) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

tracerAttempts.incrementAndGet();
super.attemptStarted(attemptNumber);
}

@Override
public void operationFailed(Throwable error) {
tracerOperationFailed.set(true);
super.operationFailed(error);
}

@Override
public void attemptFailedRetriesExhausted(Throwable error) {
tracerFailedRetriesExhausted.set(true);
super.attemptFailedRetriesExhausted(error);
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright 2024 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.google.api.gax.httpjson.testing;

import com.google.api.gax.tracing.ApiTracer;
import com.google.api.gax.tracing.ApiTracerFactory;
import com.google.api.gax.tracing.SpanName;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

/**
* Produces a {@link TestApiTracer}, which keeps count of the attempts made and attempts
* made-and-failed. It also keeps count of the operations failed and when the retries have been
* exhausted.
*/
public class TestApiTracerFactory implements ApiTracerFactory {
private final AtomicInteger tracerAttempts = new AtomicInteger();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These can be initialized within the tracer for better encapsulation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to initialize them in the tracer itself. However the clients only expect tracer factories, so there is no way to have control over how the actual tracers are instantiated.
I'll double check on this.

clientContext =
ClientContext.newBuilder()
// we use a custom tracer to confirm whether the retrials are being recorded.
.setTracerFactory(tracerFactory)
.setExecutor(executor)
.setClock(fakeClock)
.setDefaultCallContext(HttpJsonCallContext.createDefault())
.build();

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah nvm, I realized that accessing the ApiTracer instance should be enough.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

private final AtomicInteger tracerAttemptsFailed = new AtomicInteger();
private final AtomicBoolean tracerOperationFailed = new AtomicBoolean(false);
private final AtomicBoolean tracerFailedRetriesExhausted = new AtomicBoolean(false);
private final TestApiTracer instance =
new TestApiTracer(
tracerAttempts,
tracerAttemptsFailed,
tracerOperationFailed,
tracerFailedRetriesExhausted);

public AtomicInteger getTracerAttempts() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better to get the tracer instance, and use the getters from the tracer in unit tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

return tracerAttempts;
}

public AtomicInteger getTracerAttemptsFailed() {
return tracerAttemptsFailed;
}

public AtomicBoolean getTracerOperationFailed() {
return tracerOperationFailed;
}

public AtomicBoolean getTracerFailedRetriesExhausted() {
return tracerFailedRetriesExhausted;
}

@Override
public ApiTracer newTracer(ApiTracer parent, SpanName spanName, OperationType operationType) {
return instance;
}
}
Loading
Loading