|
17 | 17 |
|
18 | 18 | import static io.opentelemetry.semconv.ResourceAttributes.SERVICE_NAME;
|
19 | 19 | import static io.opentelemetry.semconv.SemanticAttributes.DB_OPERATION;
|
| 20 | +import static io.opentelemetry.semconv.SemanticAttributes.DB_STATEMENT; |
20 | 21 | import static io.opentelemetry.semconv.SemanticAttributes.DB_SYSTEM;
|
21 | 22 | import static io.opentelemetry.semconv.SemanticAttributes.FAAS_INVOKED_NAME;
|
22 | 23 | import static io.opentelemetry.semconv.SemanticAttributes.FAAS_TRIGGER;
|
|
44 | 45 | import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_SPAN_KIND;
|
45 | 46 | import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_STREAM_NAME;
|
46 | 47 | import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_TABLE_NAME;
|
| 48 | +import static software.amazon.opentelemetry.javaagent.providers.AwsSpanProcessingUtil.MAX_KEYWORD_LENGTH; |
| 49 | +import static software.amazon.opentelemetry.javaagent.providers.AwsSpanProcessingUtil.SQL_DIALECT_PATTERN; |
47 | 50 | import static software.amazon.opentelemetry.javaagent.providers.AwsSpanProcessingUtil.UNKNOWN_OPERATION;
|
48 | 51 | import static software.amazon.opentelemetry.javaagent.providers.AwsSpanProcessingUtil.UNKNOWN_REMOTE_OPERATION;
|
49 | 52 | import static software.amazon.opentelemetry.javaagent.providers.AwsSpanProcessingUtil.UNKNOWN_REMOTE_SERVICE;
|
|
68 | 71 | import java.util.Optional;
|
69 | 72 | import java.util.logging.Level;
|
70 | 73 | import java.util.logging.Logger;
|
| 74 | +import java.util.regex.Matcher; |
71 | 75 | import javax.annotation.Nullable;
|
72 | 76 |
|
73 | 77 | /**
|
@@ -266,9 +270,15 @@ private static void setRemoteServiceAndOperation(SpanData span, AttributesBuilde
|
266 | 270 | } else if (isKeyPresent(span, RPC_SERVICE) || isKeyPresent(span, RPC_METHOD)) {
|
267 | 271 | remoteService = normalizeServiceName(span, getRemoteService(span, RPC_SERVICE));
|
268 | 272 | remoteOperation = getRemoteOperation(span, RPC_METHOD);
|
269 |
| - } else if (isKeyPresent(span, DB_SYSTEM) || isKeyPresent(span, DB_OPERATION)) { |
| 273 | + } else if (isKeyPresent(span, DB_SYSTEM) |
| 274 | + || isKeyPresent(span, DB_OPERATION) |
| 275 | + || isKeyPresent(span, DB_STATEMENT)) { |
270 | 276 | remoteService = getRemoteService(span, DB_SYSTEM);
|
271 |
| - remoteOperation = getRemoteOperation(span, DB_OPERATION); |
| 277 | + if (isKeyPresent(span, DB_OPERATION)) { |
| 278 | + remoteOperation = getRemoteOperation(span, DB_OPERATION); |
| 279 | + } else { |
| 280 | + remoteOperation = getDBStatementRemoteOperation(span, DB_STATEMENT); |
| 281 | + } |
272 | 282 | } else if (isKeyPresent(span, FAAS_INVOKED_NAME) || isKeyPresent(span, FAAS_TRIGGER)) {
|
273 | 283 | remoteService = getRemoteService(span, FAAS_INVOKED_NAME);
|
274 | 284 | remoteOperation = getRemoteOperation(span, FAAS_TRIGGER);
|
@@ -449,6 +459,36 @@ private static String getRemoteOperation(SpanData span, AttributeKey<String> rem
|
449 | 459 | return remoteOperation;
|
450 | 460 | }
|
451 | 461 |
|
| 462 | + /** |
| 463 | + * If no db.operation attribute provided in the span, we use db.statement to compute a valid |
| 464 | + * remote operation in a best-effort manner. To do this, we take the first substring of the |
| 465 | + * statement and compare to a regex list of known SQL keywords. The substring length is determined |
| 466 | + * by the longest known SQL keywords. |
| 467 | + */ |
| 468 | + private static String getDBStatementRemoteOperation( |
| 469 | + SpanData span, AttributeKey<String> remoteOperationKey) { |
| 470 | + String remoteOperation = span.getAttributes().get(remoteOperationKey); |
| 471 | + if (remoteOperation == null) { |
| 472 | + remoteOperation = UNKNOWN_REMOTE_OPERATION; |
| 473 | + } |
| 474 | + |
| 475 | + // Remove all whitespace and newline characters from the beginning of remote_operation |
| 476 | + // and retrieve the first MAX_KEYWORD_LENGTH characters |
| 477 | + remoteOperation = remoteOperation.stripLeading(); |
| 478 | + if (remoteOperation.length() > MAX_KEYWORD_LENGTH) { |
| 479 | + remoteOperation = remoteOperation.substring(0, MAX_KEYWORD_LENGTH); |
| 480 | + } |
| 481 | + |
| 482 | + Matcher matcher = SQL_DIALECT_PATTERN.matcher(remoteOperation.toUpperCase()); |
| 483 | + if (matcher.find() && !matcher.group(0).isEmpty()) { |
| 484 | + remoteOperation = matcher.group(0); |
| 485 | + } else { |
| 486 | + remoteOperation = UNKNOWN_REMOTE_OPERATION; |
| 487 | + } |
| 488 | + |
| 489 | + return remoteOperation; |
| 490 | + } |
| 491 | + |
452 | 492 | private static void logUnknownAttribute(AttributeKey<String> attributeKey, SpanData span) {
|
453 | 493 | String[] params = {
|
454 | 494 | attributeKey.getKey(), span.getKind().name(), span.getSpanContext().getSpanId()
|
|
0 commit comments