Skip to content

Commit f4ddd64

Browse files
committed
Update SQL span name for procedures
1 parent b2f42ec commit f4ddd64

File tree

9 files changed

+91
-50
lines changed

9 files changed

+91
-50
lines changed

Diff for: instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/db/SqlStatementInfo.java

+3-8
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,14 @@
66
package io.opentelemetry.instrumentation.api.db;
77

88
import com.google.auto.value.AutoValue;
9-
import java.util.function.Function;
109
import javax.annotation.Nullable;
1110

1211
@AutoValue
1312
public abstract class SqlStatementInfo {
1413

1514
public static SqlStatementInfo create(
16-
@Nullable String fullStatement, @Nullable String operation, @Nullable String table) {
17-
return new AutoValue_SqlStatementInfo(fullStatement, operation, table);
18-
}
19-
20-
public SqlStatementInfo mapTable(Function<String, String> mapper) {
21-
return SqlStatementInfo.create(getFullStatement(), getOperation(), mapper.apply(getTable()));
15+
@Nullable String fullStatement, @Nullable String operation, @Nullable String identifier) {
16+
return new AutoValue_SqlStatementInfo(fullStatement, operation, identifier);
2217
}
2318

2419
@Nullable
@@ -28,5 +23,5 @@ public SqlStatementInfo mapTable(Function<String, String> mapper) {
2823
public abstract String getOperation();
2924

3025
@Nullable
31-
public abstract String getTable();
26+
public abstract String getMainIdentifier();
3227
}

Diff for: instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/db/DbClientSpanNameExtractor.java

+12-11
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,12 @@ public static <REQUEST> SpanNameExtractor<REQUEST> create(
2525

2626
/**
2727
* Returns a {@link SpanNameExtractor} that constructs the span name according to DB semantic
28-
* conventions: {@code <db.operation> <db.name>.<table>}.
28+
* conventions: {@code <db.operation> <db.name>.<identifier>}.
2929
*
3030
* @see SqlStatementInfo#getOperation() used to extract {@code <db.operation>}.
3131
* @see DbClientAttributesGetter#name(Object) used to extract {@code <db.name>}.
32-
* @see SqlStatementInfo#getTable() used to extract {@code <db.table>}.
32+
* @see SqlStatementInfo#getMainIdentifier() used to extract {@code <db.table>} or stored
33+
* procedure name.
3334
*/
3435
public static <REQUEST> SpanNameExtractor<REQUEST> create(
3536
SqlClientAttributesGetter<REQUEST> getter) {
@@ -40,24 +41,24 @@ public static <REQUEST> SpanNameExtractor<REQUEST> create(
4041

4142
private DbClientSpanNameExtractor() {}
4243

43-
protected String computeSpanName(String dbName, String operation, String table) {
44+
protected String computeSpanName(String dbName, String operation, String identifier) {
4445
if (operation == null) {
4546
return dbName == null ? DEFAULT_SPAN_NAME : dbName;
4647
}
4748

4849
StringBuilder name = new StringBuilder(operation);
49-
if (dbName != null || table != null) {
50+
if (dbName != null || identifier != null) {
5051
name.append(' ');
5152
}
52-
// skip db name if table already has a db name prefixed to it
53-
if (dbName != null && (table == null || table.indexOf('.') == -1)) {
53+
// skip db name if identifier already has a db name prefixed to it
54+
if (dbName != null && (identifier == null || identifier.indexOf('.') == -1)) {
5455
name.append(dbName);
55-
if (table != null) {
56+
if (identifier != null) {
5657
name.append('.');
5758
}
5859
}
59-
if (table != null) {
60-
name.append(table);
60+
if (identifier != null) {
61+
name.append(identifier);
6162
}
6263
return name.toString();
6364
}
@@ -82,7 +83,7 @@ public String extract(REQUEST request) {
8283
private static final class SqlClientSpanNameExtractor<REQUEST>
8384
extends DbClientSpanNameExtractor<REQUEST> {
8485

85-
// a dedicated sanitizer just for extracting the operation and table name
86+
// a dedicated sanitizer just for extracting the operation and identifier name
8687
private static final SqlStatementSanitizer sanitizer = SqlStatementSanitizer.create(true);
8788

8889
private final SqlClientAttributesGetter<REQUEST> getter;
@@ -96,7 +97,7 @@ public String extract(REQUEST request) {
9697
String dbName = getter.name(request);
9798
SqlStatementInfo sanitizedStatement = sanitizer.sanitize(getter.rawStatement(request));
9899
return computeSpanName(
99-
dbName, sanitizedStatement.getOperation(), sanitizedStatement.getTable());
100+
dbName, sanitizedStatement.getOperation(), sanitizedStatement.getMainIdentifier());
100101
}
101102
}
102103
}

Diff for: instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/db/SqlClientAttributesExtractor.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ public static <REQUEST, RESPONSE> SqlClientAttributesExtractorBuilder<REQUEST, R
4343
return new SqlClientAttributesExtractorBuilder<>(getter);
4444
}
4545

46+
private static final String SQL_CALL = "CALL";
4647
private final AttributeKey<String> dbTableAttribute;
4748
private final SqlStatementSanitizer sanitizer;
4849

@@ -60,8 +61,11 @@ public void onStart(AttributesBuilder attributes, Context parentContext, REQUEST
6061
super.onStart(attributes, parentContext, request);
6162

6263
SqlStatementInfo sanitizedStatement = sanitizer.sanitize(getter.rawStatement(request));
64+
String operation = sanitizedStatement.getOperation();
6365
internalSet(attributes, SemanticAttributes.DB_STATEMENT, sanitizedStatement.getFullStatement());
64-
internalSet(attributes, SemanticAttributes.DB_OPERATION, sanitizedStatement.getOperation());
65-
internalSet(attributes, dbTableAttribute, sanitizedStatement.getTable());
66+
internalSet(attributes, SemanticAttributes.DB_OPERATION, operation);
67+
if (!SQL_CALL.equals(operation)) {
68+
internalSet(attributes, dbTableAttribute, sanitizedStatement.getMainIdentifier());
69+
}
6670
}
6771
}

Diff for: instrumentation-api-semconv/src/main/jflex/SqlSanitizer.jflex

+50-20
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,13 @@ WHITESPACE = [ \t\r\n]+
6363
}
6464

6565
/** @return text matched by current token without enclosing double quotes or backticks */
66-
private String readTableName() {
67-
String tableName = yytext();
68-
if (tableName != null && ((tableName.startsWith("\"") && tableName.endsWith("\""))
69-
|| (tableName.startsWith("`") && tableName.endsWith("`")))) {
70-
tableName = tableName.substring(1, tableName.length() - 1);
66+
private String readIdentifierName() {
67+
String identifierName = yytext();
68+
if (identifierName != null && ((identifierName.startsWith("\"") && identifierName.endsWith("\""))
69+
|| (identifierName.startsWith("`") && identifierName.endsWith("`")))) {
70+
identifierName = identifierName.substring(1, identifierName.length() - 1);
7171
}
72-
return tableName;
72+
return identifierName;
7373
}
7474

7575
// you can reference a table in the FROM clause in one of the following ways:
@@ -92,7 +92,7 @@ WHITESPACE = [ \t\r\n]+
9292
}
9393

9494
private static abstract class Operation {
95-
String mainTable = null;
95+
String mainIdentifier = null;
9696

9797
/** @return true if all statement info is gathered */
9898
boolean handleFrom() {
@@ -119,8 +119,13 @@ WHITESPACE = [ \t\r\n]+
119119
return false;
120120
}
121121

122+
/** @return true if all statement info is gathered */
123+
boolean handleNext() {
124+
return false;
125+
}
126+
122127
SqlStatementInfo getResult(String fullStatement) {
123-
return SqlStatementInfo.create(fullStatement, getClass().getSimpleName().toUpperCase(java.util.Locale.ROOT), mainTable);
128+
return SqlStatementInfo.create(fullStatement, getClass().getSimpleName().toUpperCase(java.util.Locale.ROOT), mainIdentifier);
124129
}
125130
}
126131

@@ -152,13 +157,13 @@ WHITESPACE = [ \t\r\n]+
152157
}
153158

154159
// subquery in WITH or SELECT clause, before main FROM clause; skipping
155-
mainTable = null;
160+
mainIdentifier = null;
156161
return true;
157162
}
158163

159164
boolean handleJoin() {
160165
// for SELECT statements with joined tables there's no main table
161-
mainTable = null;
166+
mainIdentifier = null;
162167
return true;
163168
}
164169

@@ -173,17 +178,17 @@ WHITESPACE = [ \t\r\n]+
173178

174179
// SELECT FROM (subquery) case
175180
if (parenLevel != 0) {
176-
mainTable = null;
181+
mainIdentifier = null;
177182
return true;
178183
}
179184

180185
// whenever >1 table is used there is no main table (e.g. unions)
181186
if (mainTableSetAlready) {
182-
mainTable = null;
187+
mainIdentifier = null;
183188
return true;
184189
}
185190

186-
mainTable = readTableName();
191+
mainIdentifier = readIdentifierName();
187192
mainTableSetAlready = true;
188193
expectingTableName = false;
189194
// start counting identifiers after encountering main from clause
@@ -199,7 +204,7 @@ WHITESPACE = [ \t\r\n]+
199204
// any other list that can appear later needs at least 4 idents)
200205
if (identifiersAfterMainFromClause > 0
201206
&& identifiersAfterMainFromClause <= FROM_TABLE_REF_MAX_IDENTIFIERS) {
202-
mainTable = null;
207+
mainIdentifier = null;
203208
return true;
204209
}
205210
return false;
@@ -219,7 +224,7 @@ WHITESPACE = [ \t\r\n]+
219224
return false;
220225
}
221226

222-
mainTable = readTableName();
227+
mainIdentifier = readIdentifierName();
223228
return true;
224229
}
225230
}
@@ -237,21 +242,33 @@ WHITESPACE = [ \t\r\n]+
237242
return false;
238243
}
239244

240-
mainTable = readTableName();
245+
mainIdentifier = readIdentifierName();
241246
return true;
242247
}
243248
}
244249

245250
private class Update extends Operation {
246251
boolean handleIdentifier() {
247-
mainTable = readTableName();
252+
mainIdentifier = readIdentifierName();
253+
return true;
254+
}
255+
}
256+
257+
private class Call extends Operation {
258+
boolean handleIdentifier() {
259+
mainIdentifier = readIdentifierName();
260+
return true;
261+
}
262+
263+
boolean handleNext() {
264+
mainIdentifier = null;
248265
return true;
249266
}
250267
}
251268

252269
private class Merge extends Operation {
253270
boolean handleIdentifier() {
254-
mainTable = readTableName();
271+
mainIdentifier = readIdentifierName();
255272
return true;
256273
}
257274
}
@@ -298,14 +315,20 @@ WHITESPACE = [ \t\r\n]+
298315
appendCurrentFragment();
299316
if (isOverLimit()) return YYEOF;
300317
}
318+
"CALL" {
319+
if (!insideComment) {
320+
setOperation(new Call());
321+
}
322+
appendCurrentFragment();
323+
if (isOverLimit()) return YYEOF;
324+
}
301325
"MERGE" {
302326
if (!insideComment) {
303327
setOperation(new Merge());
304328
}
305329
appendCurrentFragment();
306330
if (isOverLimit()) return YYEOF;
307331
}
308-
309332
"FROM" {
310333
if (!insideComment && !extractionDone) {
311334
if (operation == NoOp.INSTANCE) {
@@ -332,6 +355,13 @@ WHITESPACE = [ \t\r\n]+
332355
appendCurrentFragment();
333356
if (isOverLimit()) return YYEOF;
334357
}
358+
"NEXT" {
359+
if (!insideComment && !extractionDone) {
360+
extractionDone = operation.handleNext();
361+
}
362+
appendCurrentFragment();
363+
if (isOverLimit()) return YYEOF;
364+
}
335365
{COMMA} {
336366
if (!insideComment && !extractionDone) {
337367
extractionDone = operation.handleComma();
@@ -407,4 +437,4 @@ WHITESPACE = [ \t\r\n]+
407437
appendCurrentFragment();
408438
if (isOverLimit()) return YYEOF;
409439
}
410-
}
440+
}

Diff for: instrumentation-api-semconv/src/test/java/io/opentelemetry/instrumentation/api/db/SqlStatementSanitizerTest.java

+12-4
Original file line numberDiff line numberDiff line change
@@ -232,12 +232,13 @@ public Stream<? extends Arguments> provideArguments(ExtensionContext context) th
232232

233233
static class SimplifyArgs implements ArgumentsProvider {
234234

235-
static Function<String, SqlStatementInfo> expect(String operation, String table) {
236-
return sql -> SqlStatementInfo.create(sql, operation, table);
235+
static Function<String, SqlStatementInfo> expect(String operation, String identifier) {
236+
return sql -> SqlStatementInfo.create(sql, operation, identifier);
237237
}
238238

239-
static Function<String, SqlStatementInfo> expect(String sql, String operation, String table) {
240-
return ignored -> SqlStatementInfo.create(sql, operation, table);
239+
static Function<String, SqlStatementInfo> expect(
240+
String sql, String operation, String identifier) {
241+
return ignored -> SqlStatementInfo.create(sql, operation, identifier);
241242
}
242243

243244
@Override
@@ -275,6 +276,7 @@ public Stream<? extends Arguments> provideArguments(ExtensionContext context) th
275276
Arguments.of("/* update comment */ select * from table1", expect("SELECT", "table1")),
276277
Arguments.of("select /*((*/abc from table", expect("SELECT", "table")),
277278
Arguments.of("SeLeCT * FrOm TAblE", expect("SELECT", "table")),
279+
Arguments.of("select next value in hibernate_sequence", expect("SELECT", null)),
278280

279281
// hibernate/jpa
280282
Arguments.of("FROM schema.table", expect("SELECT", "schema.table")),
@@ -308,6 +310,12 @@ public Stream<? extends Arguments> provideArguments(ExtensionContext context) th
308310
expect("update \"my table\" set answer=?", "UPDATE", "my table")),
309311
Arguments.of("update /*table", expect("UPDATE", null)),
310312

313+
// Call
314+
Arguments.of("call test_proc()", expect("CALL", "test_proc")),
315+
Arguments.of("call test_proc", expect("CALL", "test_proc")),
316+
Arguments.of("call next value in hibernate_sequence", expect("CALL", null)),
317+
Arguments.of("call db.test_proc", expect("CALL", "db.test_proc")),
318+
311319
// Merge
312320
Arguments.of("merge into table", expect("MERGE", "table")),
313321
Arguments.of("merge into `my table`", expect("MERGE", "my table")),

Diff for: instrumentation/hibernate/hibernate-4.0/javaagent/src/test/groovy/SpringJpaTest.groovy

+2-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ class SpringJpaTest extends AgentInstrumentationSpecification {
112112
}
113113
if (!isHibernate4) {
114114
span(2) {
115-
name "test"
115+
name "CALL test"
116116
kind CLIENT
117117
childOf span(1)
118118
attributes {
@@ -121,6 +121,7 @@ class SpringJpaTest extends AgentInstrumentationSpecification {
121121
"$SemanticAttributes.DB_USER" "sa"
122122
"$SemanticAttributes.DB_STATEMENT" "call next value for hibernate_sequence"
123123
"$SemanticAttributes.DB_CONNECTION_STRING" "hsqldb:mem:"
124+
"$SemanticAttributes.DB_OPERATION" "CALL"
124125
}
125126
}
126127
span(3) {

Diff for: instrumentation/hibernate/hibernate-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hibernate/OperationNameUtil.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ public static String getOperationNameForQuery(String query) {
2222
SqlStatementInfo info = sanitizer.sanitize(query);
2323
if (info.getOperation() != null) {
2424
operation = info.getOperation();
25-
if (info.getTable() != null) {
26-
operation += " " + info.getTable();
25+
if (info.getMainIdentifier() != null) {
26+
operation += " " + info.getMainIdentifier();
2727
}
2828
}
2929
return operation;

Diff for: instrumentation/hibernate/hibernate-procedure-call-4.3/javaagent/src/test/groovy/ProcedureCallTest.groovy

+2-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ class ProcedureCallTest extends AgentInstrumentationSpecification {
104104
}
105105
}
106106
span(2) {
107-
name "test"
107+
name "CALL test.TEST_PROC"
108108
kind CLIENT
109109
childOf span(1)
110110
attributes {
@@ -113,6 +113,7 @@ class ProcedureCallTest extends AgentInstrumentationSpecification {
113113
"$SemanticAttributes.DB_USER" "sa"
114114
"$SemanticAttributes.DB_STATEMENT" "{call TEST_PROC()}"
115115
"$SemanticAttributes.DB_CONNECTION_STRING" "hsqldb:mem:"
116+
"$SemanticAttributes.DB_OPERATION" "CALL"
116117
}
117118
}
118119
span(3) {

Diff for: instrumentation/spring/spring-data/spring-data-common/testing/src/main/groovy/AbstractSpringJpaTest.groovy

+2-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ abstract class AbstractSpringJpaTest<ENTITY, REPOSITORY extends JpaRepository<EN
111111
if (!isHibernate4) {
112112
offset = 1
113113
span(1) {
114-
name "test"
114+
name "CALL test"
115115
kind CLIENT
116116
childOf span(0)
117117
attributes {
@@ -120,6 +120,7 @@ abstract class AbstractSpringJpaTest<ENTITY, REPOSITORY extends JpaRepository<EN
120120
"$SemanticAttributes.DB_USER" "sa"
121121
"$SemanticAttributes.DB_CONNECTION_STRING" "hsqldb:mem:"
122122
"$SemanticAttributes.DB_STATEMENT" ~/^call next value for /
123+
"$SemanticAttributes.DB_OPERATION" "CALL"
123124
}
124125
}
125126
}

0 commit comments

Comments
 (0)