Skip to content

Commit 7f85f7f

Browse files
committed
refactored instrumentation
Signed-off-by: Alexander Wert <[email protected]>
1 parent 73cab12 commit 7f85f7f

File tree

11 files changed

+211
-173
lines changed

11 files changed

+211
-173
lines changed

java-client/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ dependencies {
183183
// the Java API client coexists with a 7.x HLRC work fine
184184
val elasticsearchVersion = "7.17.7"
185185
val jacksonVersion = "2.13.3"
186-
val openTelemetryVersion = "1.26.0"
186+
val openTelemetryVersion = "1.27.0"
187187

188188
// Apache 2.0
189189
// https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-low.html

java-client/src/main/java/co/elastic/clients/transport/Endpoint.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,6 @@ public interface Endpoint<RequestT, ResponseT, ErrorT> {
5656
*/
5757
String requestUrl(RequestT request);
5858

59-
/**
60-
* Get the route for a request (i.e. URL pattern).
61-
*/
62-
String route(RequestT request);
63-
6459
/**
6560
* Get the path parameters for a request.
6661
*/
@@ -116,7 +111,6 @@ default BinaryEndpoint<RequestT> withBinaryResponse() {
116111
this.id(),
117112
this::method,
118113
this::requestUrl,
119-
this::route,
120114
this::pathParameters,
121115
this::queryParameters,
122116
this::headers,

java-client/src/main/java/co/elastic/clients/transport/endpoints/BinaryEndpoint.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ public BinaryEndpoint(
2828
String id,
2929
Function<RequestT, String> method,
3030
Function<RequestT, String> requestUrl,
31-
Function<RequestT, String> route,
3231
Function<RequestT,
3332
Map<String, String>> pathParameters,
3433
Function<RequestT,
@@ -37,14 +36,13 @@ public BinaryEndpoint(
3736
Function<RequestT, Object> body,
3837
Object ignored // same number of arguments as SimpleEndpoint
3938
) {
40-
super(id, method, requestUrl, route, pathParameters, queryParameters, headers, body);
39+
super(id, method, requestUrl, pathParameters, queryParameters, headers, body);
4140
}
4241

4342
public BinaryEndpoint(
4443
String id,
4544
Function<RequestT, String> method,
4645
Function<RequestT, String> requestUrl,
47-
Function<RequestT, String> route,
4846
Function<RequestT,
4947
Map<String, String>> pathParameters,
5048
Function<RequestT,
@@ -53,7 +51,7 @@ public BinaryEndpoint(
5351
boolean hasRequestBody,
5452
Object ignored // same number of arguments as SimpleEndpoint
5553
) {
56-
super(id, method, requestUrl, route, pathParameters, queryParameters, headers, hasRequestBody ? returnSelf() : returnNull());
54+
super(id, method, requestUrl, pathParameters, queryParameters, headers, hasRequestBody ? returnSelf() : returnNull());
5755
}
5856

5957
@Override

java-client/src/main/java/co/elastic/clients/transport/endpoints/BooleanEndpoint.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ public BooleanEndpoint(
2828
String id,
2929
Function<RequestT, String> method,
3030
Function<RequestT, String> requestUrl,
31-
Function<RequestT, String> route,
3231
Function<RequestT,
3332
Map<String, String>> pathParameters,
3433
Function<RequestT,
@@ -37,7 +36,7 @@ public BooleanEndpoint(
3736
boolean hasRequestBody,
3837
Object ignored // same number of arguments as SimpleEndpoint
3938
) {
40-
super(id, method, requestUrl, route, pathParameters, queryParameters, headers, hasRequestBody ? returnSelf() : returnNull());
39+
super(id, method, requestUrl, pathParameters, queryParameters, headers, hasRequestBody ? returnSelf() : returnNull());
4140
}
4241

4342
@Override

java-client/src/main/java/co/elastic/clients/transport/endpoints/DelegatingJsonEndpoint.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,6 @@ public String requestUrl(Req request) {
4848
return endpoint.requestUrl(request);
4949
}
5050

51-
@Override
52-
public String route(Req request) {
53-
return endpoint.route(request);
54-
}
55-
5651
@Override
5752
public Map<String, String> pathParameters(Req request) {
5853
return endpoint.pathParameters(request);

java-client/src/main/java/co/elastic/clients/transport/endpoints/EndpointBase.java

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ static <T, U> Function<T, U> returnSelf() {
6464
protected final String id;
6565
protected final Function<RequestT, String> method;
6666
protected final Function<RequestT, String> requestUrl;
67-
protected final Function<RequestT, String> route;
6867
protected final Function<RequestT, Map<String, String>> pathParameters;
6968
protected final Function<RequestT, Map<String, String>> queryParameters;
7069
protected final Function<RequestT, Map<String, String>> headers;
@@ -74,7 +73,6 @@ public EndpointBase(
7473
String id,
7574
Function<RequestT, String> method,
7675
Function<RequestT, String> requestUrl,
77-
Function<RequestT, String> route,
7876
Function<RequestT, Map<String, String>> pathParameters,
7977
Function<RequestT, Map<String, String>> queryParameters,
8078
Function<RequestT, Map<String, String>> headers,
@@ -83,7 +81,6 @@ public EndpointBase(
8381
this.id = id;
8482
this.method = method;
8583
this.requestUrl = requestUrl;
86-
this.route = route;
8784
this.pathParameters = pathParameters;
8885
this.queryParameters = queryParameters;
8986
this.headers = headers;
@@ -105,11 +102,6 @@ public String requestUrl(RequestT request) {
105102
return this.requestUrl.apply(request);
106103
}
107104

108-
@Override
109-
public String route(RequestT request) {
110-
return this.route.apply(request);
111-
}
112-
113105
@Override
114106
public Map<String, String> pathParameters(RequestT request) {
115107
return this.pathParameters.apply(request);
@@ -149,7 +141,6 @@ public <NewResponseT> SimpleEndpoint<RequestT, NewResponseT> withResponseDeseria
149141
id,
150142
method,
151143
requestUrl,
152-
route,
153144
pathParameters,
154145
queryParameters,
155146
headers,

java-client/src/main/java/co/elastic/clients/transport/endpoints/SimpleEndpoint.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,22 +36,20 @@ public SimpleEndpoint(
3636
String id,
3737
Function<RequestT, String> method,
3838
Function<RequestT, String> requestUrl,
39-
Function<RequestT, String> route,
4039
Function<RequestT, Map<String, String>> pathParameters,
4140
Function<RequestT, Map<String, String>> queryParameters,
4241
Function<RequestT, Map<String, String>> headers,
4342
Function<RequestT, Object> body,
4443
JsonpDeserializer<ResponseT> responseParser
4544
) {
46-
super(id, method, requestUrl, route, pathParameters, queryParameters, headers, body);
45+
super(id, method, requestUrl, pathParameters, queryParameters, headers, body);
4746
this.responseParser = responseParser;
4847
}
4948

5049
public SimpleEndpoint(
5150
String id,
5251
Function<RequestT, String> method,
5352
Function<RequestT, String> requestUrl,
54-
Function<RequestT, String> route,
5553
Function<RequestT, Map<String, String>> pathParameters,
5654
Function<RequestT, Map<String, String>> queryParameters,
5755
Function<RequestT, Map<String, String>> headers,
@@ -62,7 +60,6 @@ public SimpleEndpoint(
6260
id,
6361
method,
6462
requestUrl,
65-
route,
6663
pathParameters,
6764
queryParameters,
6865
headers,
@@ -88,7 +85,6 @@ public <NewResponseT> SimpleEndpoint<RequestT, NewResponseT> withResponseDeseria
8885
id,
8986
method,
9087
requestUrl,
91-
route,
9288
pathParameters,
9389
queryParameters,
9490
headers,

java-client/src/main/java/co/elastic/clients/transport/endpoints/SimpleJsonEndpoint.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ public SimpleJsonEndpoint(
3333
String id,
3434
Function<RequestT, String> method,
3535
Function<RequestT, String> requestUrl,
36-
Function<RequestT, String> route,
3736
Function<RequestT,
3837
Map<String, String>> pathParameters,
3938
Function<RequestT,
@@ -42,6 +41,6 @@ public SimpleJsonEndpoint(
4241
boolean hasRequestBody,
4342
JsonpDeserializer<ResponseT> responseParser
4443
) {
45-
super(id, method, requestUrl, route, pathParameters, queryParameters, headers, hasRequestBody, responseParser);
44+
super(id, method, requestUrl, pathParameters, queryParameters, headers, hasRequestBody, responseParser);
4645
}
4746
}
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package co.elastic.clients.transport.rest_client;
21+
22+
import co.elastic.clients.transport.Endpoint;
23+
import io.opentelemetry.api.GlobalOpenTelemetry;
24+
import io.opentelemetry.api.OpenTelemetry;
25+
import io.opentelemetry.api.common.AttributeKey;
26+
import io.opentelemetry.api.trace.Span;
27+
import io.opentelemetry.api.trace.SpanKind;
28+
import io.opentelemetry.api.trace.Tracer;
29+
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
30+
import org.apache.commons.logging.Log;
31+
import org.apache.commons.logging.LogFactory;
32+
import org.apache.http.HttpEntity;
33+
import org.apache.http.HttpHost;
34+
import org.elasticsearch.client.Response;
35+
36+
import javax.annotation.Nullable;
37+
import java.io.BufferedReader;
38+
import java.io.IOException;
39+
import java.io.InputStreamReader;
40+
import java.net.InetAddress;
41+
import java.nio.charset.StandardCharsets;
42+
import java.util.Arrays;
43+
import java.util.HashSet;
44+
import java.util.Locale;
45+
import java.util.Map;
46+
import java.util.Set;
47+
import java.util.stream.Collectors;
48+
49+
public class Instrumentation {
50+
51+
private static final Set<String> SEARCH_ENDPOINTS = new HashSet<>(Arrays.asList(
52+
"render_search_template",
53+
"terms_enum",
54+
"msearch_template",
55+
"eql.search",
56+
"msearch",
57+
"search_template",
58+
"async_search.submit",
59+
"search"));
60+
61+
62+
// these reflect the config options in the OTel Java agent
63+
private static final boolean INSTRUMENTATION_ENABLED =
64+
Boolean.parseBoolean(
65+
ConfigUtil.getConfigOption("otel.instrumentation.elasticsearch.enabled", "true"));
66+
67+
private static final boolean CAPTURE_SEARCH_BODY =
68+
Boolean.parseBoolean(
69+
ConfigUtil.getConfigOption("otel.instrumentation.elasticsearch.capture-search-query", "false"));
70+
71+
private static final Log logger = LogFactory.getLog(Instrumentation.class);
72+
73+
private final Tracer tracer;
74+
75+
public Instrumentation(@Nullable OpenTelemetry openTelemetry) {
76+
if (openTelemetry == null) {
77+
openTelemetry = GlobalOpenTelemetry.get();
78+
}
79+
80+
tracer = openTelemetry.getTracer("elasticsearch-api");
81+
}
82+
83+
public <RequestT, ResponseT, ErrorT> Span createSpanForRequest(RequestT request,
84+
Endpoint<RequestT, ResponseT, ErrorT> endpoint) {
85+
if (!INSTRUMENTATION_ENABLED) {
86+
return Span.getInvalid();
87+
}
88+
89+
Span span = tracer.spanBuilder(endpoint.id()).setSpanKind(SpanKind.CLIENT).startSpan();
90+
if (isInvalidSpan(span)) {
91+
span.setAttribute(OTelAttributes.DB_SYSTEM, "elasticsearch");
92+
span.setAttribute(OTelAttributes.DB_OPERATION, endpoint.id());
93+
span.setAttribute(OTelAttributes.HTTP_REQUEST_METHOD, endpoint.method(request));
94+
95+
for (Map.Entry<String, String> pathParamEntry : endpoint.pathParameters(request).entrySet()) {
96+
String attributeKey = OTelAttributes.PATH_PART_PREFIX + pathParamEntry.getKey();
97+
span.setAttribute(AttributeKey.stringKey(attributeKey), pathParamEntry.getValue());
98+
}
99+
}
100+
101+
return span;
102+
}
103+
104+
public void captureResponseInformation(@Nullable Span span, Response response) {
105+
if (isInvalidSpan(span)) {
106+
return;
107+
}
108+
109+
HttpHost host = response.getHost();
110+
String uri = response.getRequestLine().getUri();
111+
uri = uri.startsWith("/") ? uri : "/" + uri;
112+
String fullUrl = host.toURI() + uri;
113+
114+
span.setAttribute(OTelAttributes.URL_FULL, fullUrl);
115+
span.setAttribute(OTelAttributes.SERVER_PORT, host.getPort());
116+
117+
InetAddress hostAddress = response.getHost().getAddress();
118+
if (hostAddress != null) {
119+
span.setAttribute(OTelAttributes.SERVER_ADDRESS, hostAddress.getHostAddress());
120+
}
121+
}
122+
123+
public <RequestT> void captureBody(@Nullable Span span, Endpoint<RequestT, ?, ?> endpoint,
124+
HttpEntity httpEntity) {
125+
try {
126+
if (shouldCaptureBody(span, endpoint, httpEntity)) {
127+
128+
String body = new BufferedReader(
129+
new InputStreamReader(httpEntity.getContent(), StandardCharsets.UTF_8))
130+
.lines()
131+
.collect(Collectors.joining());
132+
133+
span.setAttribute(OTelAttributes.DB_STATEMENT, body);
134+
}
135+
} catch (IOException e) {
136+
logger.debug("Failed reading HTTP body content.", e);
137+
}
138+
}
139+
140+
private <RequestT> boolean shouldCaptureBody(@Nullable Span span, Endpoint<RequestT, ?, ?> endpoint, HttpEntity httpEntity) {
141+
return !isInvalidSpan(span)
142+
&& CAPTURE_SEARCH_BODY
143+
&& SEARCH_ENDPOINTS.contains(endpoint.id())
144+
&& httpEntity != null
145+
&& httpEntity.isRepeatable();
146+
}
147+
148+
private boolean isInvalidSpan(@Nullable Span span) {
149+
return !INSTRUMENTATION_ENABLED || span == null || !span.isRecording();
150+
}
151+
152+
private static final class OTelAttributes {
153+
private static final AttributeKey<String> DB_SYSTEM = SemanticAttributes.DB_SYSTEM;
154+
private static final AttributeKey<String> DB_OPERATION = SemanticAttributes.DB_OPERATION;
155+
private static final AttributeKey<String> DB_STATEMENT = SemanticAttributes.DB_STATEMENT;
156+
private static final AttributeKey<String> HTTP_REQUEST_METHOD = AttributeKey.stringKey("http.request.method");
157+
private static final AttributeKey<String> URL_FULL = AttributeKey.stringKey("url.full");
158+
private static final AttributeKey<String> SERVER_ADDRESS = AttributeKey.stringKey("server.address");
159+
private static final AttributeKey<Long> SERVER_PORT = AttributeKey.longKey("server.port");
160+
161+
private static final String PATH_PART_PREFIX = "db.elasticsearch.path_parts.";
162+
}
163+
164+
private static final class ConfigUtil {
165+
private static String getConfigOption(String key, String defaultValue) {
166+
String normalizedKey = normalizePropertyKey(key);
167+
String systemProperty =
168+
System.getProperties().entrySet().stream()
169+
.filter(entry -> normalizedKey.equals(normalizePropertyKey(entry.getKey().toString())))
170+
.map(entry -> entry.getValue().toString())
171+
.findFirst()
172+
.orElse(null);
173+
if (systemProperty != null) {
174+
return systemProperty;
175+
}
176+
return System.getenv().entrySet().stream()
177+
.filter(entry -> normalizedKey.equals(normalizeEnvironmentVariableKey(entry.getKey())))
178+
.map(Map.Entry::getValue)
179+
.findFirst()
180+
.orElse(defaultValue);
181+
}
182+
183+
/**
184+
* Normalize an environment variable key by converting to lower case and replacing "_" with ".".
185+
*/
186+
private static String normalizeEnvironmentVariableKey(String key) {
187+
return key.toLowerCase(Locale.ROOT).replace("_", ".");
188+
}
189+
190+
/**
191+
* Normalize a property key by converting to lower case and replacing "-" with ".".
192+
*/
193+
private static String normalizePropertyKey(String key) {
194+
return key.toLowerCase(Locale.ROOT).replace("-", ".");
195+
}
196+
}
197+
}

0 commit comments

Comments
 (0)