Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -83,7 +83,12 @@ public class OpenTelemetryForElasticsearch implements Instrumentation {
// Caching attributes keys to avoid unnecessary memory allocation
private static final Map<String, AttributeKey<String>> attributesKeyCache = new ConcurrentHashMap<>();

AttributeKeyTemplate<String> PATH_PART_PREFIX = AttributeKeyTemplate.stringKeyTemplate("db.elasticsearch.path_parts");
// The Elasticsearch semantic conventions renamed the "db.elasticsearch.path_parts.<key>" path parameter
// attributes to "db.operation.parameter.<key>". Following the OpenTelemetry "otel.semconv-stability.opt-in"
// migration mechanism, the old prefix is emitted by default, the new one when "database" is opted in, and both
// when "database/dup" is opted in.
AttributeKeyTemplate<String> OLD_PATH_PART_PREFIX = AttributeKeyTemplate.stringKeyTemplate("db.elasticsearch.path_parts");
AttributeKeyTemplate<String> NEW_PATH_PART_PREFIX = AttributeKeyTemplate.stringKeyTemplate("db.operation.parameter");

// these reflect the config options in the OTel Java agent
private static final boolean INSTRUMENTATION_ENABLED = Boolean.parseBoolean(
Expand All @@ -94,6 +99,24 @@ public class OpenTelemetryForElasticsearch implements Instrumentation {
ConfigUtil.getConfigOption("otel.instrumentation.elasticsearch.capture-search-query", "false")
);

private static final String SEMCONV_STABILITY_OPT_IN =
ConfigUtil.getConfigOption("otel.semconv-stability.opt-in", "");

private static final boolean EMIT_STABLE_DATABASE_ATTRIBUTES =
hasOptIn("database") || hasOptIn("database/dup");

private static final boolean EMIT_OLD_DATABASE_ATTRIBUTES =
!EMIT_STABLE_DATABASE_ATTRIBUTES || hasOptIn("database/dup");

private static boolean hasOptIn(String value) {
for (String token : SEMCONV_STABILITY_OPT_IN.split(",")) {
if (token.trim().equals(value)) {
return true;
}
}
return false;
}

private static final Log logger = LogFactory.getLog(OpenTelemetryForElasticsearch.class);

private final Tracer tracer;
Expand All @@ -110,6 +133,11 @@ public class OpenTelemetryForElasticsearch implements Instrumentation {
* {@code OTEL_INSTRUMENTATION_ELASTICSEARCH_CAPTURE_SEARCH_QUERY} environment variable: if {@code true} the request body
* of search requests will be captured. Defaults to {@code false}.
* </li>
* <li>{@code otel.semconv-stability.opt-in} system property or {@code OTEL_SEMCONV_STABILITY_OPT_IN}
* environment variable: controls the migration to the stable database semantic conventions.
* This flag only affects the path parameter attributes; the other database attributes emitted by this client
* already follow the stable conventions.
* </li>
* </ul>
*
* @return an instrumentation, or {@code null} if instrumentation is disabled or no OTel agent has been configured.
Expand Down Expand Up @@ -194,8 +222,14 @@ <TRequest> OTelContext(TRequest request, Endpoint<TRequest, ?, ?> endpoint) {
span.setAttribute(HTTP_REQUEST_METHOD, endpoint.method(request));

for (Map.Entry<String, String> pathParamEntry : endpoint.pathParameters(request).entrySet()) {
AttributeKey<String> attributeKey = PATH_PART_PREFIX.getAttributeKey(pathParamEntry.getKey());
span.setAttribute(attributeKey, pathParamEntry.getValue());
if (EMIT_OLD_DATABASE_ATTRIBUTES) {
span.setAttribute(OLD_PATH_PART_PREFIX.getAttributeKey(pathParamEntry.getKey()),
pathParamEntry.getValue());
}
if (EMIT_STABLE_DATABASE_ATTRIBUTES) {
span.setAttribute(NEW_PATH_PART_PREFIX.getAttributeKey(pathParamEntry.getKey()),
pathParamEntry.getValue());
}
}
}
} catch (RuntimeException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,10 @@ public void testGetRequest() throws IOException, InterruptedException {
Assertions.assertEquals(httpServer.getAddress().getHostString(), span.getAttributes().get(ServerAttributes.SERVER_ADDRESS));
Assertions.assertEquals(httpServer.getAddress().getPort(), span.getAttributes().get(ServerAttributes.SERVER_PORT));

// Path parts
// Path parts: by default (no otel.semconv-stability.opt-in) the deprecated prefix is emitted and the
// stable "db.operation.parameter.*" prefix is not, preserving backwards compatibility.
Assertions.assertEquals(DOC_ID, span.getAttributes().get(AttributeKey.stringKey("db.elasticsearch.path_parts.id")));
Assertions.assertNull(span.getAttributes().get(AttributeKey.stringKey("db.operation.parameter.id")));
}

@Test
Expand Down
Loading