Skip to content

Commit 8b92ae2

Browse files
committed
Update SQL span name for procedures
1 parent 8090ec1 commit 8b92ae2

File tree

6 files changed

+91
-41
lines changed

6 files changed

+91
-41
lines changed

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

+14-4
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@
1313
public abstract class SqlStatementInfo {
1414

1515
public static SqlStatementInfo create(
16-
@Nullable String fullStatement, @Nullable String operation, @Nullable String table) {
17-
return new AutoValue_SqlStatementInfo(fullStatement, operation, table);
16+
@Nullable String fullStatement, @Nullable String operation, @Nullable String identifier) {
17+
return new AutoValue_SqlStatementInfo(fullStatement, operation, identifier);
1818
}
1919

2020
public SqlStatementInfo mapTable(Function<String, String> mapper) {
21-
return SqlStatementInfo.create(getFullStatement(), getOperation(), mapper.apply(getTable()));
21+
return SqlStatementInfo.create(
22+
getFullStatement(), getOperation(), mapper.apply(getIdentifier()));
2223
}
2324

2425
@Nullable
@@ -28,5 +29,14 @@ public SqlStatementInfo mapTable(Function<String, String> mapper) {
2829
public abstract String getOperation();
2930

3031
@Nullable
31-
public abstract String getTable();
32+
public abstract String getIdentifier();
33+
34+
@Nullable
35+
public String getTable() {
36+
String operation = getOperation();
37+
if (operation != null && !operation.equals("CALL")) {
38+
return getIdentifier();
39+
}
40+
return null;
41+
}
3242
}

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

+11-11
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ 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#getIdentifier() used to extract {@code <db.identifier>}.
3333
*/
3434
public static <REQUEST> SpanNameExtractor<REQUEST> create(
3535
SqlClientAttributesGetter<REQUEST> getter) {
@@ -40,24 +40,24 @@ public static <REQUEST> SpanNameExtractor<REQUEST> create(
4040

4141
private DbClientSpanNameExtractor() {}
4242

43-
protected String computeSpanName(String dbName, String operation, String table) {
43+
protected String computeSpanName(String dbName, String operation, String identifier) {
4444
if (operation == null) {
4545
return dbName == null ? DEFAULT_SPAN_NAME : dbName;
4646
}
4747

4848
StringBuilder name = new StringBuilder(operation);
49-
if (dbName != null || table != null) {
49+
if (dbName != null || identifier != null) {
5050
name.append(' ');
5151
}
52-
// skip db name if table already has a db name prefixed to it
53-
if (dbName != null && (table == null || table.indexOf('.') == -1)) {
52+
// skip db name if identifier already has a db name prefixed to it
53+
if (dbName != null && (identifier == null || identifier.indexOf('.') == -1)) {
5454
name.append(dbName);
55-
if (table != null) {
55+
if (identifier != null) {
5656
name.append('.');
5757
}
5858
}
59-
if (table != null) {
60-
name.append(table);
59+
if (identifier != null) {
60+
name.append(identifier);
6161
}
6262
return name.toString();
6363
}
@@ -82,7 +82,7 @@ public String extract(REQUEST request) {
8282
private static final class SqlClientSpanNameExtractor<REQUEST>
8383
extends DbClientSpanNameExtractor<REQUEST> {
8484

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

8888
private final SqlClientAttributesGetter<REQUEST> getter;
@@ -96,7 +96,7 @@ public String extract(REQUEST request) {
9696
String dbName = getter.name(request);
9797
SqlStatementInfo sanitizedStatement = sanitizer.sanitize(getter.rawStatement(request));
9898
return computeSpanName(
99-
dbName, sanitizedStatement.getOperation(), sanitizedStatement.getTable());
99+
dbName, sanitizedStatement.getOperation(), sanitizedStatement.getIdentifier());
100100
}
101101
}
102102
}

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

+51-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,21 @@ WHITESPACE = [ \t\r\n]+
298315
appendCurrentFragment();
299316
if (isOverLimit()) return YYEOF;
300317
}
318+
"CALL" {
319+
if (!insideComment) {
320+
setOperation(new Call());
321+
}
322+
operation.handleIdentifier();
323+
appendCurrentFragment();
324+
if (isOverLimit()) return YYEOF;
325+
}
301326
"MERGE" {
302327
if (!insideComment) {
303328
setOperation(new Merge());
304329
}
305330
appendCurrentFragment();
306331
if (isOverLimit()) return YYEOF;
307332
}
308-
309333
"FROM" {
310334
if (!insideComment && !extractionDone) {
311335
if (operation == NoOp.INSTANCE) {
@@ -332,6 +356,13 @@ WHITESPACE = [ \t\r\n]+
332356
appendCurrentFragment();
333357
if (isOverLimit()) return YYEOF;
334358
}
359+
"NEXT" {
360+
if (!insideComment && !extractionDone) {
361+
extractionDone = operation.handleNext();
362+
}
363+
appendCurrentFragment();
364+
if (isOverLimit()) return YYEOF;
365+
}
335366
{COMMA} {
336367
if (!insideComment && !extractionDone) {
337368
extractionDone = operation.handleComma();
@@ -407,4 +438,4 @@ WHITESPACE = [ \t\r\n]+
407438
appendCurrentFragment();
408439
if (isOverLimit()) return YYEOF;
409440
}
410-
}
441+
}

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

+11-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
@@ -308,6 +309,12 @@ public Stream<? extends Arguments> provideArguments(ExtensionContext context) th
308309
expect("update \"my table\" set answer=?", "UPDATE", "my table")),
309310
Arguments.of("update /*table", expect("UPDATE", null)),
310311

312+
// Call
313+
Arguments.of("call test_proc()", expect("CALL", "test_proc")),
314+
Arguments.of("call test_proc", expect("CALL", "test_proc")),
315+
Arguments.of("call next value in hibernate_sequence", expect("CALL", null)),
316+
Arguments.of("call db.test_proc", expect("CALL", "db.test_proc")),
317+
311318
// Merge
312319
Arguments.of("merge into table", expect("MERGE", "table")),
313320
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-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) {

0 commit comments

Comments
 (0)