Skip to content

Commit f1e37a6

Browse files
Mateusz RzeszutekRashmiRam
authored andcommitted
Split out DbClientAttributesGetter and SqlClientAttributesGetter (open-telemetry#5354)
* Split out DbClientAttributesGetter and SqlClientAttributesGetter * code review comments
1 parent cf3f4f4 commit f1e37a6

File tree

59 files changed

+942
-768
lines changed

Some content is hidden

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

59 files changed

+942
-768
lines changed

instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/AttributesExtractor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import io.opentelemetry.api.common.AttributeKey;
99
import io.opentelemetry.api.common.AttributesBuilder;
1010
import io.opentelemetry.context.Context;
11-
import io.opentelemetry.instrumentation.api.instrumenter.db.DbAttributesExtractor;
11+
import io.opentelemetry.instrumentation.api.instrumenter.db.DbClientAttributesExtractor;
1212
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
1313
import io.opentelemetry.instrumentation.api.instrumenter.net.NetServerAttributesExtractor;
1414
import javax.annotation.Nullable;
@@ -21,7 +21,7 @@
2121
* at each stage of a request's lifecycle. It is best to populate as much as possible in {@link
2222
* #onStart(AttributesBuilder, Context, Object)} to have it available during sampling.
2323
*
24-
* @see DbAttributesExtractor
24+
* @see DbClientAttributesExtractor
2525
* @see HttpClientAttributesExtractor
2626
* @see NetServerAttributesExtractor
2727
*/

instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/InstrumenterBuilder.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import io.opentelemetry.context.propagation.TextMapSetter;
1717
import io.opentelemetry.instrumentation.api.annotations.UnstableApi;
1818
import io.opentelemetry.instrumentation.api.config.Config;
19-
import io.opentelemetry.instrumentation.api.instrumenter.db.DbAttributesExtractor;
19+
import io.opentelemetry.instrumentation.api.instrumenter.db.DbClientAttributesExtractor;
2020
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
2121
import io.opentelemetry.instrumentation.api.instrumenter.messaging.MessagingAttributesExtractor;
2222
import io.opentelemetry.instrumentation.api.instrumenter.rpc.RpcAttributesExtractor;
@@ -169,8 +169,8 @@ public InstrumenterBuilder<REQUEST, RESPONSE> setDisabled(boolean disabled) {
169169
* <ul>
170170
* <li>CLIENT nested spans are suppressed depending on their type: {@linkplain
171171
* HttpClientAttributesExtractor HTTP}, {@linkplain RpcAttributesExtractor RPC} or
172-
* {@linkplain DbAttributesExtractor database} clients. If a span with the same type is
173-
* present in the parent context object, new span of the same type will not be started.
172+
* {@linkplain DbClientAttributesExtractor database} clients. If a span with the same type
173+
* is present in the parent context object, new span of the same type will not be started.
174174
* </ul>
175175
*
176176
* <p><strong>When disabled:</strong>

instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/SpanKeyExtractor.java

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

66
package io.opentelemetry.instrumentation.api.instrumenter;
77

8-
import io.opentelemetry.instrumentation.api.instrumenter.db.DbAttributesExtractor;
8+
import io.opentelemetry.instrumentation.api.instrumenter.db.DbClientAttributesExtractor;
99
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
1010
import io.opentelemetry.instrumentation.api.instrumenter.messaging.MessagingAttributesExtractor;
1111
import io.opentelemetry.instrumentation.api.instrumenter.rpc.RpcAttributesExtractor;
@@ -28,7 +28,7 @@ static Set<SpanKey> determineSpanKeys(
2828
spanKeys.add(SpanKey.HTTP_CLIENT);
2929
} else if (attributeExtractor instanceof RpcAttributesExtractor) {
3030
spanKeys.add(SpanKey.RPC_CLIENT);
31-
} else if (attributeExtractor instanceof DbAttributesExtractor) {
31+
} else if (attributeExtractor instanceof DbClientAttributesExtractor) {
3232
spanKeys.add(SpanKey.DB_CLIENT);
3333
} else if (attributeExtractor instanceof MessagingAttributesExtractor) {
3434
spanKeys.add(

instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/db/DbAttributesExtractor.java

Lines changed: 0 additions & 61 deletions
This file was deleted.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.api.instrumenter.db;
7+
8+
import io.opentelemetry.api.common.AttributesBuilder;
9+
import io.opentelemetry.context.Context;
10+
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
11+
12+
/**
13+
* Extractor of <a
14+
* href="https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/database.md">database
15+
* client attributes</a>.
16+
*
17+
* <p>This class delegates to a type-specific {@link DbClientAttributesGetter} for individual
18+
* attribute extraction from request/response objects.
19+
*/
20+
public final class DbClientAttributesExtractor<REQUEST, RESPONSE>
21+
extends DbClientCommonAttributesExtractor<
22+
REQUEST, RESPONSE, DbClientAttributesGetter<REQUEST>> {
23+
24+
/** Creates the database client attributes extractor with default configuration. */
25+
public static <REQUEST, RESPONSE> DbClientAttributesExtractor<REQUEST, RESPONSE> create(
26+
DbClientAttributesGetter<REQUEST> getter) {
27+
return new DbClientAttributesExtractor<>(getter);
28+
}
29+
30+
DbClientAttributesExtractor(DbClientAttributesGetter<REQUEST> getter) {
31+
super(getter);
32+
}
33+
34+
@Override
35+
public void onStart(AttributesBuilder attributes, Context parentContext, REQUEST request) {
36+
super.onStart(attributes, parentContext, request);
37+
38+
set(attributes, SemanticAttributes.DB_STATEMENT, getter.statement(request));
39+
set(attributes, SemanticAttributes.DB_OPERATION, getter.operation(request));
40+
}
41+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.api.instrumenter.db;
7+
8+
import javax.annotation.Nullable;
9+
10+
/**
11+
* An interface for getting database client attributes.
12+
*
13+
* <p>Instrumentation authors will create implementations of this interface for their specific
14+
* library/framework. It will be used by the {@link DbClientAttributesExtractor} to obtain the
15+
* various database client attributes in a type-generic way.
16+
*
17+
* <p>If an attribute is not available in this library, it is appropriate to return {@code null}
18+
* from the attribute methods, but implement as many as possible for best compliance with the
19+
* OpenTelemetry specification.
20+
*/
21+
public interface DbClientAttributesGetter<REQUEST> extends DbClientCommonAttributesGetter<REQUEST> {
22+
23+
@Nullable
24+
String statement(REQUEST request);
25+
26+
@Nullable
27+
String operation(REQUEST request);
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.api.instrumenter.db;
7+
8+
import io.opentelemetry.api.common.AttributesBuilder;
9+
import io.opentelemetry.context.Context;
10+
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
11+
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
12+
import javax.annotation.Nullable;
13+
14+
abstract class DbClientCommonAttributesExtractor<
15+
REQUEST, RESPONSE, GETTER extends DbClientCommonAttributesGetter<REQUEST>>
16+
implements AttributesExtractor<REQUEST, RESPONSE> {
17+
18+
final GETTER getter;
19+
20+
DbClientCommonAttributesExtractor(GETTER getter) {
21+
this.getter = getter;
22+
}
23+
24+
@Override
25+
public void onStart(AttributesBuilder attributes, Context parentContext, REQUEST request) {
26+
set(attributes, SemanticAttributes.DB_SYSTEM, getter.system(request));
27+
set(attributes, SemanticAttributes.DB_USER, getter.user(request));
28+
set(attributes, SemanticAttributes.DB_NAME, getter.name(request));
29+
set(attributes, SemanticAttributes.DB_CONNECTION_STRING, getter.connectionString(request));
30+
}
31+
32+
@Override
33+
public final void onEnd(
34+
AttributesBuilder attributes,
35+
Context context,
36+
REQUEST request,
37+
@Nullable RESPONSE response,
38+
@Nullable Throwable error) {}
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.api.instrumenter.db;
7+
8+
import javax.annotation.Nullable;
9+
10+
/** An interface for getting attributes common to database clients. */
11+
public interface DbClientCommonAttributesGetter<REQUEST> {
12+
13+
@Nullable
14+
String system(REQUEST request);
15+
16+
@Nullable
17+
String user(REQUEST request);
18+
19+
@Nullable
20+
String name(REQUEST request);
21+
22+
@Nullable
23+
String connectionString(REQUEST request);
24+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.api.instrumenter.db;
7+
8+
import io.opentelemetry.instrumentation.api.db.SqlStatementInfo;
9+
import io.opentelemetry.instrumentation.api.db.SqlStatementSanitizer;
10+
import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
11+
12+
public abstract class DbClientSpanNameExtractor<REQUEST> implements SpanNameExtractor<REQUEST> {
13+
14+
/**
15+
* Returns a {@link SpanNameExtractor} that constructs the span name according to DB semantic
16+
* conventions: {@code <db.operation> <db.name>}.
17+
*
18+
* @see DbClientAttributesGetter#operation(Object) used to extract {@code <db.operation>}.
19+
* @see DbClientAttributesGetter#name(Object) used to extract {@code <db.name>}.
20+
*/
21+
public static <REQUEST> SpanNameExtractor<REQUEST> create(
22+
DbClientAttributesGetter<REQUEST> getter) {
23+
return new GenericDbClientSpanNameExtractor<>(getter);
24+
}
25+
26+
/**
27+
* Returns a {@link SpanNameExtractor} that constructs the span name according to DB semantic
28+
* conventions: {@code <db.operation> <db.name>.<table>}.
29+
*
30+
* @see SqlStatementInfo#getOperation() used to extract {@code <db.operation>}.
31+
* @see DbClientAttributesGetter#name(Object) used to extract {@code <db.name>}.
32+
* @see SqlStatementInfo#getTable() used to extract {@code <db.table>}.
33+
*/
34+
public static <REQUEST> SpanNameExtractor<REQUEST> create(
35+
SqlClientAttributesGetter<REQUEST> getter) {
36+
return new SqlClientSpanNameExtractor<>(getter);
37+
}
38+
39+
private static final String DEFAULT_SPAN_NAME = "DB Query";
40+
41+
private DbClientSpanNameExtractor() {}
42+
43+
protected String computeSpanName(String dbName, String operation, String table) {
44+
if (operation == null) {
45+
return dbName == null ? DEFAULT_SPAN_NAME : dbName;
46+
}
47+
48+
StringBuilder name = new StringBuilder(operation);
49+
if (dbName != null || table != null) {
50+
name.append(' ');
51+
}
52+
// skip db name if table already has a db name prefixed to it
53+
if (dbName != null && (table == null || table.indexOf('.') == -1)) {
54+
name.append(dbName);
55+
if (table != null) {
56+
name.append('.');
57+
}
58+
}
59+
if (table != null) {
60+
name.append(table);
61+
}
62+
return name.toString();
63+
}
64+
65+
private static final class GenericDbClientSpanNameExtractor<REQUEST>
66+
extends DbClientSpanNameExtractor<REQUEST> {
67+
68+
private final DbClientAttributesGetter<REQUEST> getter;
69+
70+
private GenericDbClientSpanNameExtractor(DbClientAttributesGetter<REQUEST> getter) {
71+
this.getter = getter;
72+
}
73+
74+
@Override
75+
public String extract(REQUEST request) {
76+
String dbName = getter.name(request);
77+
String operation = getter.operation(request);
78+
return computeSpanName(dbName, operation, null);
79+
}
80+
}
81+
82+
private static final class SqlClientSpanNameExtractor<REQUEST>
83+
extends DbClientSpanNameExtractor<REQUEST> {
84+
85+
private final SqlClientAttributesGetter<REQUEST> getter;
86+
87+
private SqlClientSpanNameExtractor(SqlClientAttributesGetter<REQUEST> getter) {
88+
this.getter = getter;
89+
}
90+
91+
@Override
92+
public String extract(REQUEST request) {
93+
String dbName = getter.name(request);
94+
SqlStatementInfo sanitizedStatement =
95+
SqlStatementSanitizer.sanitize(getter.rawStatement(request));
96+
return computeSpanName(
97+
dbName, sanitizedStatement.getOperation(), sanitizedStatement.getTable());
98+
}
99+
}
100+
}

0 commit comments

Comments
 (0)