Skip to content

Commit aaf4b3a

Browse files
rename AsyncOperationEndXX to AsyncEndXX, rename AttributeForReturnValue to AttributeReturnValue
1 parent 90c87bf commit aaf4b3a

File tree

43 files changed

+375
-391
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+375
-391
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1995,7 +1995,7 @@ too disruptive to adopt right away.
19951995
- `io.opentelemetry.instrumentation.graphql.GraphQLTelemetry`
19961996
`io.opentelemetry.instrumentation.graphql.v12_0.GraphQLTelemetry`
19971997
- `io.opentelemetry.instrumentation.guava.GuavaAsyncOperationEndStrategy`
1998-
`io.opentelemetry.instrumentation.guava.v10_0.GuavaAsyncOperationEndStrategy`
1998+
`io.opentelemetry.instrumentation.guava.v10_0.GuavaAsyncEndStrategy`
19991999
- `io.opentelemetry.instrumentation.hikaricp.HikariTelemetry`
20002000
`io.opentelemetry.instrumentation.hikaricp.v3_0.HikariTelemetry`
20012001
- `io.opentelemetry.instrumentation.kafkaclients.KafkaTelemetry`
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
*/
2727
@Target(ElementType.METHOD)
2828
@Retention(RetentionPolicy.RUNTIME)
29-
public @interface AttributeForReturnValue {
29+
public @interface AttributeReturnValue {
3030

3131
/**
3232
* Attribute name for the return value.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import javax.annotation.Nullable;
1010

1111
/** Callback that is called when async computation completes. */
12-
public interface AsyncOperationEndHandler<REQUEST, RESPONSE> {
12+
public interface AsyncEndHandler<REQUEST, RESPONSE> {
1313
void handle(
1414
Context context, REQUEST request, @Nullable RESPONSE response, @Nullable Throwable error);
1515
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.api.annotation.support.async;
7+
8+
import javax.annotation.Nullable;
9+
10+
/** A global registry of {@link AsyncEndStrategy} implementations. */
11+
public abstract class AsyncEndStrategies {
12+
private static volatile AsyncEndStrategies instance;
13+
14+
/**
15+
* Sets the actual strategies' registry implementation. The javaagent uses weak references to make
16+
* unloading strategy classes possible.
17+
*
18+
* <p>This is supposed to be only called by the javaagent. <b>Instrumentation must not call
19+
* this.</b>
20+
*/
21+
public static void internalSetStrategiesStorage(AsyncEndStrategies strategies) {
22+
instance = strategies;
23+
}
24+
25+
/** Obtain instance of the async strategy registry. */
26+
public static AsyncEndStrategies instance() {
27+
if (instance == null) {
28+
instance = new AsyncEndStrategiesImpl();
29+
}
30+
return instance;
31+
}
32+
33+
/** Add the passed {@code strategy} to the registry. */
34+
public abstract void registerStrategy(AsyncEndStrategy strategy);
35+
36+
/** Remove the passed {@code strategy} from the registry. */
37+
public abstract void unregisterStrategy(AsyncEndStrategy strategy);
38+
39+
/**
40+
* Returns an {@link AsyncEndStrategy} that is able to compose over {@code returnType}, or {@code
41+
* null} if passed type is not supported by any of the strategies stored in this registry.
42+
*/
43+
@Nullable
44+
public abstract AsyncEndStrategy resolveStrategy(Class<?> returnType);
45+
}
Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,27 +12,27 @@
1212
import javax.annotation.Nullable;
1313

1414
/** Default strategies' registry implementation that uses strong references. */
15-
final class AsyncOperationEndStrategiesImpl extends AsyncOperationEndStrategies {
16-
private final List<AsyncOperationEndStrategy> strategies = new CopyOnWriteArrayList<>();
15+
final class AsyncEndStrategiesImpl extends AsyncEndStrategies {
16+
private final List<AsyncEndStrategy> strategies = new CopyOnWriteArrayList<>();
1717

18-
AsyncOperationEndStrategiesImpl() {
19-
registerStrategy(Jdk8AsyncOperationEndStrategy.INSTANCE);
18+
AsyncEndStrategiesImpl() {
19+
registerStrategy(Jdk8AsyncEndStrategy.INSTANCE);
2020
}
2121

2222
@Override
23-
public void registerStrategy(AsyncOperationEndStrategy strategy) {
23+
public void registerStrategy(AsyncEndStrategy strategy) {
2424
strategies.add(requireNonNull(strategy));
2525
}
2626

2727
@Override
28-
public void unregisterStrategy(AsyncOperationEndStrategy strategy) {
28+
public void unregisterStrategy(AsyncEndStrategy strategy) {
2929
strategies.remove(strategy);
3030
}
3131

3232
@Nullable
3333
@Override
34-
public AsyncOperationEndStrategy resolveStrategy(Class<?> returnType) {
35-
for (AsyncOperationEndStrategy strategy : strategies) {
34+
public AsyncEndStrategy resolveStrategy(Class<?> returnType) {
35+
for (AsyncEndStrategy strategy : strategies) {
3636
if (strategy.supports(returnType)) {
3737
return strategy;
3838
}
Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212
* Implementations of this interface describe how to compose over {@linkplain #supports(Class)
1313
* supported} asynchronous computation types and delay marking the operation as ended by calling
1414
* {@link Instrumenter#end(Context, Object, Object, Throwable)} or {@link
15-
* AsyncOperationEndHandler#handle(Context, Object, Object, Throwable)}.
15+
* AsyncEndHandler#handle(Context, Object, Object, Throwable)}.
1616
*/
17-
public interface AsyncOperationEndStrategy {
17+
public interface AsyncEndStrategy {
1818

1919
/**
2020
* Returns true for every asynchronous computation type {@code asyncType} this strategy supports.
@@ -47,12 +47,12 @@ default <REQUEST, RESPONSE> Object end(
4747
}
4848

4949
/**
50-
* Composes over {@code asyncValue} and delays the {@link AsyncOperationEndHandler#handle(Context,
51-
* Object, Object, Throwable)} call until after the asynchronous operation represented by {@code
50+
* Composes over {@code asyncValue} and delays the {@link AsyncEndHandler#handle(Context, Object,
51+
* Object, Throwable)} call until after the asynchronous operation represented by {@code
5252
* asyncValue} completes.
5353
*
54-
* @param handler The {@link AsyncOperationEndHandler} to be used to end the operation stored in
55-
* the {@code context}.
54+
* @param handler The {@link AsyncEndHandler} to be used to end the operation stored in the {@code
55+
* context}.
5656
* @param asyncValue Return value from the instrumented method. Must be an instance of a {@code
5757
* asyncType} for which {@link #supports(Class)} returned true (in particular it must not be
5858
* {@code null}).
@@ -63,7 +63,7 @@ default <REQUEST, RESPONSE> Object end(
6363
* of completion.
6464
*/
6565
<REQUEST, RESPONSE> Object end(
66-
AsyncOperationEndHandler<REQUEST, RESPONSE> handler,
66+
AsyncEndHandler<REQUEST, RESPONSE> handler,
6767
Context context,
6868
REQUEST request,
6969
Object asyncValue,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.api.annotation.support.async;
7+
8+
import io.opentelemetry.context.Context;
9+
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
10+
import javax.annotation.Nullable;
11+
12+
/**
13+
* A wrapper over {@link AsyncEndHandler} that is able to defer {@link
14+
* AsyncEndHandler#handle(Context, Object, Object, Throwable)} until asynchronous computation
15+
* finishes.
16+
*/
17+
public final class AsyncEndSupport<REQUEST, RESPONSE> {
18+
19+
/**
20+
* Returns a new {@link AsyncEndSupport} that wraps over passed {@code instrumenter}, configured
21+
* for usage with asynchronous computations that are instances of {@code asyncType}. If the result
22+
* of the async computation ends up being an instance of {@code responseType} it will be passed as
23+
* the response to the {@code instrumenter} call; otherwise {@code null} value will be used as the
24+
* response.
25+
*/
26+
public static <REQUEST, RESPONSE> AsyncEndSupport<REQUEST, RESPONSE> create(
27+
Instrumenter<REQUEST, RESPONSE> instrumenter,
28+
Class<RESPONSE> responseType,
29+
Class<?> asyncType) {
30+
return new AsyncEndSupport<>(
31+
instrumenter::end,
32+
responseType,
33+
asyncType,
34+
AsyncEndStrategies.instance().resolveStrategy(asyncType));
35+
}
36+
37+
/**
38+
* Returns a new {@link AsyncEndSupport} that wraps over passed {@code handler}, configured for
39+
* usage with asynchronous computations that are instances of {@code asyncType}. If the result of
40+
* the async computation ends up being an instance of {@code responseType} it will be passed as
41+
* the response to the {@code handler} call; otherwise {@code null} value will be used as the
42+
* response.
43+
*/
44+
public static <REQUEST, RESPONSE> AsyncEndSupport<REQUEST, RESPONSE> create(
45+
AsyncEndHandler<REQUEST, RESPONSE> handler,
46+
Class<RESPONSE> responseType,
47+
Class<?> asyncType) {
48+
return new AsyncEndSupport<>(
49+
handler, responseType, asyncType, AsyncEndStrategies.instance().resolveStrategy(asyncType));
50+
}
51+
52+
private final AsyncEndHandler<REQUEST, RESPONSE> handler;
53+
private final Class<RESPONSE> responseType;
54+
private final Class<?> asyncType;
55+
@Nullable private final AsyncEndStrategy asyncEndStrategy;
56+
57+
private AsyncEndSupport(
58+
AsyncEndHandler<REQUEST, RESPONSE> handler,
59+
Class<RESPONSE> responseType,
60+
Class<?> asyncType,
61+
@Nullable AsyncEndStrategy asyncEndStrategy) {
62+
this.handler = handler;
63+
this.responseType = responseType;
64+
this.asyncType = asyncType;
65+
this.asyncEndStrategy = asyncEndStrategy;
66+
}
67+
68+
/**
69+
* Attempts to compose over passed {@code asyncValue} and delay the {@link
70+
* Instrumenter#end(Context, Object, Object, Throwable)} call until the async operation completes.
71+
*
72+
* <p>This method will end the operation immediately if {@code throwable} is passed, if there is
73+
* no {@link AsyncEndStrategy} for the {@code asyncType} used, or if there is a type mismatch
74+
* between passed {@code asyncValue} and the {@code asyncType} that was used to create this
75+
* object.
76+
*
77+
* <p>If the passed {@code asyncValue} is recognized as an asynchronous computation, the operation
78+
* won't be {@link Instrumenter#end(Context, Object, Object, Throwable) ended} until {@code
79+
* asyncValue} completes.
80+
*/
81+
@SuppressWarnings("unchecked")
82+
@Nullable
83+
public <ASYNC> ASYNC asyncEnd(
84+
Context context, REQUEST request, @Nullable ASYNC asyncValue, @Nullable Throwable throwable) {
85+
// we can end early if an exception was thrown
86+
if (throwable != null) {
87+
handler.handle(context, request, null, throwable);
88+
return asyncValue;
89+
}
90+
91+
// use the configured strategy to compose over the asyncValue
92+
if (asyncEndStrategy != null && asyncType.isInstance(asyncValue)) {
93+
return (ASYNC) asyncEndStrategy.end(handler, context, request, asyncValue, responseType);
94+
}
95+
96+
// fall back to sync end() if asyncValue type doesn't match
97+
handler.handle(context, request, tryToGetResponse(responseType, asyncValue), null);
98+
return asyncValue;
99+
}
100+
101+
@Nullable
102+
public static <RESPONSE> RESPONSE tryToGetResponse(
103+
Class<RESPONSE> responseType, @Nullable Object asyncValue) {
104+
if (responseType.isInstance(asyncValue)) {
105+
return responseType.cast(asyncValue);
106+
}
107+
return null;
108+
}
109+
}

instrumentation-annotations-support/src/main/java/io/opentelemetry/instrumentation/api/annotation/support/async/AsyncOperationEndStrategies.java

Lines changed: 0 additions & 46 deletions
This file was deleted.

0 commit comments

Comments
 (0)