Skip to content

Commit 0c5f924

Browse files
authored
Fix NPE when async ES client is nested within Hibernate search (#1531)
1 parent 1cbed06 commit 0c5f924

File tree

3 files changed

+38
-32
lines changed

3 files changed

+38
-32
lines changed

CHANGELOG.asciidoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ endif::[]
2929
[float]
3030
===== Bug fixes
3131
* Fix small memory allocation regression introduced with tracestate header {pull}1508[#1508]
32+
* Fix `NullPointerException` from `WeakConcurrentMap.put` through the Elasticsearch client instrumentation - {pull}1531[1531]
3233
3334
[float]
3435
===== Refactors

apm-agent-plugins/apm-es-restclient-plugin/apm-es-restclient-plugin-5_6/src/main/java/co/elastic/apm/agent/es/restclient/v5_6/ElasticsearchClientAsyncInstrumentation.java

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,11 @@
2424
*/
2525
package co.elastic.apm.agent.es.restclient.v5_6;
2626

27-
import co.elastic.apm.agent.bci.VisibleForAdvice;
2827
import co.elastic.apm.agent.es.restclient.ElasticsearchRestClientInstrumentation;
2928
import co.elastic.apm.agent.es.restclient.ElasticsearchRestClientInstrumentationHelper;
3029
import co.elastic.apm.agent.impl.ElasticApmTracer;
3130
import co.elastic.apm.agent.impl.transaction.Span;
3231
import co.elastic.apm.agent.sdk.advice.AssignTo;
33-
import co.elastic.apm.agent.sdk.state.GlobalThreadLocal;
3432
import net.bytebuddy.asm.Advice;
3533
import net.bytebuddy.description.method.MethodDescription;
3634
import net.bytebuddy.description.type.TypeDescription;
@@ -77,32 +75,37 @@ public ElementMatcher<? super MethodDescription> getMethodMatcher() {
7775

7876

7977
public static class ElasticsearchRestClientAsyncAdvice {
80-
@VisibleForAdvice
81-
public static final GlobalThreadLocal<Span> spanTls = GlobalThreadLocal.get(ElasticsearchRestClientAsyncAdvice.class, "spanTls");
82-
@AssignTo.Argument(5)
78+
79+
@Nullable
80+
@AssignTo.Argument(index = 1, value = 5)
8381
@Advice.OnMethodEnter(suppress = Throwable.class)
84-
public static ResponseListener onBeforeExecute(@Advice.Argument(0) String method,
85-
@Advice.Argument(1) String endpoint,
86-
@Advice.Argument(3) @Nullable HttpEntity entity,
87-
@Advice.Argument(5) ResponseListener responseListener) {
82+
public static Object[] onBeforeExecute(@Advice.Argument(0) String method,
83+
@Advice.Argument(1) String endpoint,
84+
@Advice.Argument(3) @Nullable HttpEntity entity,
85+
@Advice.Argument(5) ResponseListener responseListener) {
8886

8987
ElasticsearchRestClientInstrumentationHelper<HttpEntity, Response, ResponseListener> helper = esClientInstrHelperManager.getForClassLoaderOfClass(Response.class);
9088
if (helper != null) {
9189
Span span = helper.createClientSpan(method, endpoint, entity);
92-
spanTls.set(span);
9390
if (span != null) {
94-
return helper.<ResponseListener>wrapResponseListener(responseListener, span);
91+
Object[] ret = new Object[2];
92+
ret[0] = span;
93+
ret[1] = helper.<ResponseListener>wrapResponseListener(responseListener, span);
94+
return ret;
9595
}
9696
}
97-
return responseListener;
97+
return null;
9898
}
9999

100100
@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
101-
public static void onAfterExecute(@Advice.Thrown @Nullable Throwable t) {
102-
final Span span = spanTls.getAndRemove();
103-
if (span != null) {
104-
// Deactivate in this thread. Span will be ended and reported by the listener
105-
span.deactivate();
101+
public static void onAfterExecute(@Advice.Thrown @Nullable Throwable t,
102+
@Advice.Enter @Nullable Object[] entryArgs) {
103+
if (entryArgs != null) {
104+
final Span span = (Span) entryArgs[0];
105+
if (span != null) {
106+
// Deactivate in this thread. Span will be ended and reported by the listener
107+
span.deactivate();
108+
}
106109
}
107110
}
108111
}

apm-agent-plugins/apm-es-restclient-plugin/apm-es-restclient-plugin-6_4/src/main/java/co/elastic/apm/agent/es/restclient/v6_4/ElasticsearchClientAsyncInstrumentation.java

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,11 @@
2424
*/
2525
package co.elastic.apm.agent.es.restclient.v6_4;
2626

27-
import co.elastic.apm.agent.bci.VisibleForAdvice;
2827
import co.elastic.apm.agent.es.restclient.ElasticsearchRestClientInstrumentation;
2928
import co.elastic.apm.agent.es.restclient.ElasticsearchRestClientInstrumentationHelper;
3029
import co.elastic.apm.agent.impl.ElasticApmTracer;
3130
import co.elastic.apm.agent.impl.transaction.Span;
3231
import co.elastic.apm.agent.sdk.advice.AssignTo;
33-
import co.elastic.apm.agent.sdk.state.GlobalThreadLocal;
3432
import net.bytebuddy.asm.Advice;
3533
import net.bytebuddy.description.method.MethodDescription;
3634
import net.bytebuddy.description.type.TypeDescription;
@@ -71,30 +69,34 @@ public ElementMatcher<? super MethodDescription> getMethodMatcher() {
7169
}
7270

7371
public static class ElasticsearchRestClientAsyncAdvice {
74-
@VisibleForAdvice
75-
public static final GlobalThreadLocal<Span> spanTls = GlobalThreadLocal.get(ElasticsearchRestClientAsyncAdvice.class, "spanTls");
7672

77-
@AssignTo.Argument(1)
73+
@Nullable
74+
@AssignTo.Argument(index = 1, value = 1)
7875
@Advice.OnMethodEnter(suppress = Throwable.class)
79-
public static ResponseListener onBeforeExecute(@Advice.Argument(0) Request request,
80-
@Advice.Argument(1) ResponseListener responseListener) {
76+
public static Object[] onBeforeExecute(@Advice.Argument(0) Request request,
77+
@Advice.Argument(1) ResponseListener responseListener) {
8178
ElasticsearchRestClientInstrumentationHelper<HttpEntity, Response, ResponseListener> helper = esClientInstrHelperManager.getForClassLoaderOfClass(Request.class);
8279
if (helper != null) {
8380
Span span = helper.createClientSpan(request.getMethod(), request.getEndpoint(), request.getEntity());
8481
if (span != null) {
85-
spanTls.set(span);
86-
return helper.<ResponseListener>wrapResponseListener(responseListener, span);
82+
Object[] ret = new Object[2];
83+
ret[0] = span;
84+
ret[1] = helper.<ResponseListener>wrapResponseListener(responseListener, span);
85+
return ret;
8786
}
8887
}
89-
return responseListener;
88+
return null;
9089
}
9190

9291
@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
93-
public static void onAfterExecute(@Advice.Thrown @Nullable Throwable t) {
94-
final Span span = spanTls.getAndRemove();
95-
if (span != null) {
96-
// Deactivate in this thread. Span will be ended and reported by the listener
97-
span.deactivate();
92+
public static void onAfterExecute(@Advice.Thrown @Nullable Throwable t,
93+
@Advice.Enter @Nullable Object[] entryArgs) {
94+
if (entryArgs != null) {
95+
final Span span = (Span) entryArgs[0];
96+
if (span != null) {
97+
// Deactivate in this thread. Span will be ended and reported by the listener
98+
span.deactivate();
99+
}
98100
}
99101
}
100102
}

0 commit comments

Comments
 (0)