Skip to content

Commit 39bb6d8

Browse files
committed
Fix Elasticsearch REST stable DB operation names
1 parent 91368ad commit 39bb6d8

7 files changed

Lines changed: 216 additions & 9 deletions

File tree

instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v5_0/ElasticsearchRest5Test.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,20 @@
55

66
package io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.v5_0;
77

8+
import static io.opentelemetry.instrumentation.api.internal.SemconvStability.emitStableDatabaseSemconv;
89
import static io.opentelemetry.instrumentation.testing.junit.db.DbClientMetricsTestUtil.assertDurationMetric;
910
import static io.opentelemetry.instrumentation.testing.junit.db.SemconvStabilityUtil.maybeStable;
1011
import static io.opentelemetry.instrumentation.testing.junit.service.SemconvServiceStabilityUtil.maybeStablePeerService;
1112
import static io.opentelemetry.instrumentation.testing.util.TestLatestDeps.testLatestDeps;
1213
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
14+
import static io.opentelemetry.semconv.DbAttributes.DB_OPERATION_NAME;
1315
import static io.opentelemetry.semconv.HttpAttributes.HTTP_REQUEST_METHOD;
1416
import static io.opentelemetry.semconv.HttpAttributes.HTTP_RESPONSE_STATUS_CODE;
1517
import static io.opentelemetry.semconv.NetworkAttributes.NETWORK_PROTOCOL_VERSION;
1618
import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS;
1719
import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT;
1820
import static io.opentelemetry.semconv.UrlAttributes.URL_FULL;
21+
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_OPERATION;
1922
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_SYSTEM;
2023
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_SYSTEM_NAME;
2124
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DbSystemNameIncubatingValues.ELASTICSEARCH;
@@ -99,11 +102,14 @@ void elasticsearchStatus() throws IOException {
99102
trace ->
100103
trace.hasSpansSatisfyingExactly(
101104
span ->
102-
span.hasName("GET")
105+
span.hasName(emitStableDatabaseSemconv() ? "cluster.health" : "GET")
103106
.hasKind(SpanKind.CLIENT)
104107
.hasNoParent()
105108
.hasAttributesSatisfyingExactly(
106109
equalTo(maybeStable(DB_SYSTEM), ELASTICSEARCH),
110+
equalTo(
111+
maybeStable(DB_OPERATION),
112+
emitStableDatabaseSemconv() ? "cluster.health" : null),
107113
equalTo(HTTP_REQUEST_METHOD, "GET"),
108114
equalTo(SERVER_ADDRESS, httpHost.getHostName()),
109115
equalTo(SERVER_PORT, httpHost.getPort()),
@@ -125,6 +131,7 @@ void elasticsearchStatus() throws IOException {
125131
testing,
126132
"io.opentelemetry.elasticsearch-rest-5.0",
127133
DB_SYSTEM_NAME,
134+
DB_OPERATION_NAME,
128135
SERVER_ADDRESS,
129136
SERVER_PORT);
130137
}
@@ -174,11 +181,14 @@ public void onFailure(Exception e) {
174181
trace.hasSpansSatisfyingExactly(
175182
span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(),
176183
span ->
177-
span.hasName("GET")
184+
span.hasName(emitStableDatabaseSemconv() ? "cluster.health" : "GET")
178185
.hasKind(SpanKind.CLIENT)
179186
.hasParent(trace.getSpan(0))
180187
.hasAttributesSatisfyingExactly(
181188
equalTo(maybeStable(DB_SYSTEM), ELASTICSEARCH),
189+
equalTo(
190+
maybeStable(DB_OPERATION),
191+
emitStableDatabaseSemconv() ? "cluster.health" : null),
182192
equalTo(HTTP_REQUEST_METHOD, "GET"),
183193
equalTo(SERVER_ADDRESS, httpHost.getHostName()),
184194
equalTo(SERVER_PORT, httpHost.getPort()),

instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v6_4/ElasticsearchRest6Test.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,19 @@
55

66
package io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.v6_4;
77

8+
import static io.opentelemetry.instrumentation.api.internal.SemconvStability.emitStableDatabaseSemconv;
89
import static io.opentelemetry.instrumentation.testing.junit.db.DbClientMetricsTestUtil.assertDurationMetric;
910
import static io.opentelemetry.instrumentation.testing.junit.db.SemconvStabilityUtil.maybeStable;
1011
import static io.opentelemetry.instrumentation.testing.junit.service.SemconvServiceStabilityUtil.maybeStablePeerService;
1112
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
13+
import static io.opentelemetry.semconv.DbAttributes.DB_OPERATION_NAME;
1214
import static io.opentelemetry.semconv.HttpAttributes.HTTP_REQUEST_METHOD;
1315
import static io.opentelemetry.semconv.HttpAttributes.HTTP_RESPONSE_STATUS_CODE;
1416
import static io.opentelemetry.semconv.NetworkAttributes.NETWORK_PROTOCOL_VERSION;
1517
import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS;
1618
import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT;
1719
import static io.opentelemetry.semconv.UrlAttributes.URL_FULL;
20+
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_OPERATION;
1821
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_SYSTEM;
1922
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_SYSTEM_NAME;
2023
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DbSystemNameIncubatingValues.ELASTICSEARCH;
@@ -93,11 +96,14 @@ void elasticsearchStatus() throws IOException {
9396
trace ->
9497
trace.hasSpansSatisfyingExactly(
9598
span ->
96-
span.hasName("GET")
99+
span.hasName(emitStableDatabaseSemconv() ? "cluster.health" : "GET")
97100
.hasKind(SpanKind.CLIENT)
98101
.hasNoParent()
99102
.hasAttributesSatisfyingExactly(
100103
equalTo(maybeStable(DB_SYSTEM), ELASTICSEARCH),
104+
equalTo(
105+
maybeStable(DB_OPERATION),
106+
emitStableDatabaseSemconv() ? "cluster.health" : null),
101107
equalTo(HTTP_REQUEST_METHOD, "GET"),
102108
equalTo(SERVER_ADDRESS, httpHost.getHostName()),
103109
equalTo(SERVER_PORT, httpHost.getPort()),
@@ -119,6 +125,7 @@ void elasticsearchStatus() throws IOException {
119125
testing,
120126
"io.opentelemetry.elasticsearch-rest-6.4",
121127
DB_SYSTEM_NAME,
128+
DB_OPERATION_NAME,
122129
SERVER_ADDRESS,
123130
SERVER_PORT);
124131
}
@@ -168,11 +175,14 @@ public void onFailure(Exception e) {
168175
trace.hasSpansSatisfyingExactly(
169176
span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(),
170177
span ->
171-
span.hasName("GET")
178+
span.hasName(emitStableDatabaseSemconv() ? "cluster.health" : "GET")
172179
.hasKind(SpanKind.CLIENT)
173180
.hasParent(trace.getSpan(0))
174181
.hasAttributesSatisfyingExactly(
175182
equalTo(maybeStable(DB_SYSTEM), ELASTICSEARCH),
183+
equalTo(
184+
maybeStable(DB_OPERATION),
185+
emitStableDatabaseSemconv() ? "cluster.health" : null),
176186
equalTo(HTTP_REQUEST_METHOD, "GET"),
177187
equalTo(SERVER_ADDRESS, httpHost.getHostName()),
178188
equalTo(SERVER_PORT, httpHost.getPort()),

instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v7_0/ElasticsearchRest7Test.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,20 @@
55

66
package io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.v7_0;
77

8+
import static io.opentelemetry.instrumentation.api.internal.SemconvStability.emitStableDatabaseSemconv;
89
import static io.opentelemetry.instrumentation.testing.GlobalTraceUtil.runWithSpan;
910
import static io.opentelemetry.instrumentation.testing.junit.db.DbClientMetricsTestUtil.assertDurationMetric;
1011
import static io.opentelemetry.instrumentation.testing.junit.db.SemconvStabilityUtil.maybeStable;
1112
import static io.opentelemetry.instrumentation.testing.junit.service.SemconvServiceStabilityUtil.maybeStablePeerService;
1213
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
14+
import static io.opentelemetry.semconv.DbAttributes.DB_OPERATION_NAME;
1315
import static io.opentelemetry.semconv.HttpAttributes.HTTP_REQUEST_METHOD;
1416
import static io.opentelemetry.semconv.HttpAttributes.HTTP_RESPONSE_STATUS_CODE;
1517
import static io.opentelemetry.semconv.NetworkAttributes.NETWORK_PROTOCOL_VERSION;
1618
import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS;
1719
import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT;
1820
import static io.opentelemetry.semconv.UrlAttributes.URL_FULL;
21+
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_OPERATION;
1922
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_SYSTEM;
2023
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_SYSTEM_NAME;
2124
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DbSystemNameIncubatingValues.ELASTICSEARCH;
@@ -90,11 +93,14 @@ void elasticsearchStatus() throws IOException {
9093
trace ->
9194
trace.hasSpansSatisfyingExactly(
9295
span ->
93-
span.hasName("GET")
96+
span.hasName(emitStableDatabaseSemconv() ? "cluster.health" : "GET")
9497
.hasKind(SpanKind.CLIENT)
9598
.hasNoParent()
9699
.hasAttributesSatisfyingExactly(
97100
equalTo(maybeStable(DB_SYSTEM), ELASTICSEARCH),
101+
equalTo(
102+
maybeStable(DB_OPERATION),
103+
emitStableDatabaseSemconv() ? "cluster.health" : null),
98104
equalTo(HTTP_REQUEST_METHOD, "GET"),
99105
equalTo(SERVER_ADDRESS, httpHost.getHostName()),
100106
equalTo(SERVER_PORT, httpHost.getPort()),
@@ -116,6 +122,7 @@ void elasticsearchStatus() throws IOException {
116122
testing,
117123
"io.opentelemetry.elasticsearch-rest-7.0",
118124
DB_SYSTEM_NAME,
125+
DB_OPERATION_NAME,
119126
SERVER_ADDRESS,
120127
SERVER_PORT);
121128
}
@@ -166,11 +173,14 @@ public void onFailure(Exception e) {
166173
trace.hasSpansSatisfyingExactly(
167174
span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(),
168175
span ->
169-
span.hasName("GET")
176+
span.hasName(emitStableDatabaseSemconv() ? "cluster.health" : "GET")
170177
.hasKind(SpanKind.CLIENT)
171178
.hasParent(trace.getSpan(0))
172179
.hasAttributesSatisfyingExactly(
173180
equalTo(maybeStable(DB_SYSTEM), ELASTICSEARCH),
181+
equalTo(
182+
maybeStable(DB_OPERATION),
183+
emitStableDatabaseSemconv() ? "cluster.health" : null),
174184
equalTo(HTTP_REQUEST_METHOD, "GET"),
175185
equalTo(SERVER_ADDRESS, httpHost.getHostName()),
176186
equalTo(SERVER_PORT, httpHost.getPort()),

instrumentation/elasticsearch/elasticsearch-rest-7.0/library/src/test/java/io/opentelemetry/instrumentation/elasticsearch/rest/v7_0/ElasticsearchRest7Test.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55

66
package io.opentelemetry.instrumentation.elasticsearch.rest.v7_0;
77

8+
import static io.opentelemetry.instrumentation.api.internal.SemconvStability.emitStableDatabaseSemconv;
89
import static io.opentelemetry.instrumentation.testing.GlobalTraceUtil.runWithSpan;
910
import static io.opentelemetry.instrumentation.testing.junit.db.SemconvStabilityUtil.maybeStable;
1011
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
1112
import static io.opentelemetry.semconv.HttpAttributes.HTTP_REQUEST_METHOD;
1213
import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS;
1314
import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT;
1415
import static io.opentelemetry.semconv.UrlAttributes.URL_FULL;
16+
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_OPERATION;
1517
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_SYSTEM;
1618
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DbSystemNameIncubatingValues.ELASTICSEARCH;
1719
import static java.util.concurrent.TimeUnit.SECONDS;
@@ -87,11 +89,14 @@ void elasticsearchStatus() throws IOException {
8789
trace ->
8890
trace.hasSpansSatisfyingExactly(
8991
span ->
90-
span.hasName("GET")
92+
span.hasName(emitStableDatabaseSemconv() ? "cluster.health" : "GET")
9193
.hasKind(SpanKind.CLIENT)
9294
.hasNoParent()
9395
.hasAttributesSatisfyingExactly(
9496
equalTo(maybeStable(DB_SYSTEM), ELASTICSEARCH),
97+
equalTo(
98+
maybeStable(DB_OPERATION),
99+
emitStableDatabaseSemconv() ? "cluster.health" : null),
95100
equalTo(HTTP_REQUEST_METHOD, "GET"),
96101
equalTo(SERVER_ADDRESS, httpHost.getHostName()),
97102
equalTo(SERVER_PORT, httpHost.getPort()),
@@ -143,11 +148,14 @@ public void onFailure(Exception e) {
143148
trace.hasSpansSatisfyingExactly(
144149
span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(),
145150
span ->
146-
span.hasName("GET")
151+
span.hasName(emitStableDatabaseSemconv() ? "cluster.health" : "GET")
147152
.hasKind(SpanKind.CLIENT)
148153
.hasParent(trace.getSpan(0))
149154
.hasAttributesSatisfyingExactly(
150155
equalTo(maybeStable(DB_SYSTEM), ELASTICSEARCH),
156+
equalTo(
157+
maybeStable(DB_OPERATION),
158+
emitStableDatabaseSemconv() ? "cluster.health" : null),
151159
equalTo(HTTP_REQUEST_METHOD, "GET"),
152160
equalTo(SERVER_ADDRESS, httpHost.getHostName()),
153161
equalTo(SERVER_PORT, httpHost.getPort()),

instrumentation/elasticsearch/elasticsearch-rest-common-5.0/library/src/main/java/io/opentelemetry/instrumentation/elasticsearch/rest/common/v5_0/internal/ElasticsearchDbAttributesGetter.java

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,112 @@ public String getDbQueryText(ElasticsearchRestRequest request) {
7373
@Override
7474
@Nullable
7575
public String getDbOperationName(ElasticsearchRestRequest request) {
76+
ElasticsearchEndpointDefinition endpointDefinition = request.getEndpointDefinition();
77+
if (endpointDefinition != null) {
78+
return endpointDefinition.getEndpointName();
79+
}
80+
return inferOperationName(request.getMethod(), request.getEndpoint());
81+
}
82+
83+
@Deprecated // to be removed in 3.0
84+
@Override
85+
@Nullable
86+
public String getDbOperation(ElasticsearchRestRequest request) {
7687
ElasticsearchEndpointDefinition endpointDefinition = request.getEndpointDefinition();
7788
return endpointDefinition != null ? endpointDefinition.getEndpointName() : null;
7889
}
7990

91+
@Nullable
92+
static String inferOperationName(String method, String endpoint) {
93+
int queryStart = endpoint.indexOf('?');
94+
if (queryStart >= 0) {
95+
endpoint = endpoint.substring(0, queryStart);
96+
}
97+
98+
while (endpoint.startsWith("/")) {
99+
endpoint = endpoint.substring(1);
100+
}
101+
if (endpoint.isEmpty()) {
102+
return null;
103+
}
104+
105+
String[] segments = endpoint.split("/");
106+
if (segments[0].startsWith("_")) {
107+
return inferOperationNameFromApiSegments(method, segments, 0);
108+
}
109+
if (segments.length > 1 && segments[1].startsWith("_")) {
110+
return inferOperationNameFromApiSegments(method, segments, 1);
111+
}
112+
return null;
113+
}
114+
115+
@Nullable
116+
private static String inferOperationNameFromApiSegments(
117+
String method, String[] segments, int apiSegmentIndex) {
118+
String apiSegment = stripLeadingUnderscores(segments[apiSegmentIndex]);
119+
if (apiSegment.isEmpty()) {
120+
return null;
121+
}
122+
String documentOperation = inferDocumentOperationName(method, apiSegment);
123+
if (documentOperation != null) {
124+
return documentOperation;
125+
}
126+
if (isGroupedApi(apiSegment)
127+
&& segments.length > apiSegmentIndex + 1
128+
&& !segments[apiSegmentIndex + 1].startsWith("_")) {
129+
return apiSegment + "." + segments[apiSegmentIndex + 1];
130+
}
131+
return apiSegment;
132+
}
133+
134+
@Nullable
135+
private static String inferDocumentOperationName(String method, String apiSegment) {
136+
switch (apiSegment) {
137+
case "create":
138+
case "update":
139+
return apiSegment;
140+
case "doc":
141+
return inferDocOperationName(method);
142+
default:
143+
return null;
144+
}
145+
}
146+
147+
@Nullable
148+
private static String inferDocOperationName(String method) {
149+
switch (method) {
150+
case "DELETE":
151+
return "delete";
152+
case "GET":
153+
return "get";
154+
case "POST":
155+
case "PUT":
156+
return "index";
157+
default:
158+
return null;
159+
}
160+
}
161+
162+
private static boolean isGroupedApi(String apiSegment) {
163+
switch (apiSegment) {
164+
case "cat":
165+
case "cluster":
166+
case "nodes":
167+
case "snapshot":
168+
case "tasks":
169+
return true;
170+
default:
171+
return false;
172+
}
173+
}
174+
175+
private static String stripLeadingUnderscores(String value) {
176+
while (value.startsWith("_")) {
177+
value = value.substring(1);
178+
}
179+
return value;
180+
}
181+
80182
@Override
81183
@Nullable
82184
public String getErrorType(

instrumentation/elasticsearch/elasticsearch-rest-common-5.0/library/src/main/java/io/opentelemetry/instrumentation/elasticsearch/rest/common/v5_0/internal/ElasticsearchSpanNameExtractor.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
package io.opentelemetry.instrumentation.elasticsearch.rest.common.v5_0.internal;
77

8+
import static io.opentelemetry.instrumentation.api.internal.SemconvStability.emitStableDatabaseSemconv;
9+
810
import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
911

1012
/**
@@ -19,9 +21,13 @@ final class ElasticsearchSpanNameExtractor implements SpanNameExtractor<Elastics
1921
this.dbAttributesGetter = dbAttributesGetter;
2022
}
2123

24+
@SuppressWarnings("deprecation") // getDbOperation is used for old semconv span names
2225
@Override
2326
public String extract(ElasticsearchRestRequest elasticsearchRestRequest) {
24-
String name = dbAttributesGetter.getDbOperationName(elasticsearchRestRequest);
27+
String name =
28+
emitStableDatabaseSemconv()
29+
? dbAttributesGetter.getDbOperationName(elasticsearchRestRequest)
30+
: dbAttributesGetter.getDbOperation(elasticsearchRestRequest);
2531
return name != null ? name : elasticsearchRestRequest.getMethod();
2632
}
2733
}

0 commit comments

Comments
 (0)