|
1 | 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
2 | 2 | # SPDX-License-Identifier: Apache-2.0
|
| 3 | +import re |
3 | 4 | from logging import DEBUG, Logger, getLogger
|
4 |
| -from typing import Optional |
| 5 | +from typing import Match, Optional |
5 | 6 | from urllib.parse import ParseResult, urlparse
|
6 | 7 |
|
7 | 8 | from amazon.opentelemetry.distro._aws_attribute_keys import (
|
|
14 | 15 | )
|
15 | 16 | from amazon.opentelemetry.distro._aws_span_processing_util import (
|
16 | 17 | LOCAL_ROOT,
|
| 18 | + MAX_KEYWORD_LENGTH, |
| 19 | + SQL_KEYWORD_PATTERN, |
17 | 20 | UNKNOWN_OPERATION,
|
18 | 21 | UNKNOWN_REMOTE_OPERATION,
|
19 | 22 | UNKNOWN_REMOTE_SERVICE,
|
|
38 | 41 | # Pertinent OTEL attribute keys
|
39 | 42 | _SERVICE_NAME: str = ResourceAttributes.SERVICE_NAME
|
40 | 43 | _DB_OPERATION: str = SpanAttributes.DB_OPERATION
|
| 44 | +_DB_STATEMENT: str = SpanAttributes.DB_STATEMENT |
41 | 45 | _DB_SYSTEM: str = SpanAttributes.DB_SYSTEM
|
42 | 46 | _FAAS_INVOKED_NAME: str = SpanAttributes.FAAS_INVOKED_NAME
|
43 | 47 | _FAAS_TRIGGER: str = SpanAttributes.FAAS_TRIGGER
|
@@ -189,9 +193,12 @@ def _set_remote_service_and_operation(span: ReadableSpan, attributes: BoundedAtt
|
189 | 193 | elif is_key_present(span, _RPC_SERVICE) or is_key_present(span, _RPC_METHOD):
|
190 | 194 | remote_service = _normalize_service_name(span, _get_remote_service(span, _RPC_SERVICE))
|
191 | 195 | remote_operation = _get_remote_operation(span, _RPC_METHOD)
|
192 |
| - elif is_key_present(span, _DB_SYSTEM) or is_key_present(span, _DB_OPERATION): |
| 196 | + elif is_key_present(span, _DB_SYSTEM) or is_key_present(span, _DB_OPERATION) or is_key_present(span, _DB_STATEMENT): |
193 | 197 | remote_service = _get_remote_service(span, _DB_SYSTEM)
|
194 |
| - remote_operation = _get_remote_operation(span, _DB_OPERATION) |
| 198 | + if is_key_present(span, _DB_OPERATION): |
| 199 | + remote_operation = _get_remote_operation(span, _DB_OPERATION) |
| 200 | + else: |
| 201 | + remote_operation = _get_db_statement_remote_operation(span, _DB_STATEMENT) |
195 | 202 | elif is_key_present(span, _FAAS_INVOKED_NAME) or is_key_present(span, _FAAS_TRIGGER):
|
196 | 203 | remote_service = _get_remote_service(span, _FAAS_INVOKED_NAME)
|
197 | 204 | remote_operation = _get_remote_operation(span, _FAAS_TRIGGER)
|
@@ -232,6 +239,28 @@ def _get_remote_operation(span: ReadableSpan, remote_operation_key: str) -> str:
|
232 | 239 | return remote_operation
|
233 | 240 |
|
234 | 241 |
|
| 242 | +def _get_db_statement_remote_operation(span: ReadableSpan, statement_key: str) -> str: |
| 243 | + """ |
| 244 | + If no db.operation attribute provided in the span, |
| 245 | + we use db.statement to compute a valid remote operation in a best-effort manner. |
| 246 | + To do this, we take the first substring of the statement |
| 247 | + and compare to a regex list of known SQL keywords. |
| 248 | + The substring length is determined by the longest known SQL keywords. |
| 249 | + """ |
| 250 | + remote_operation: str = span.attributes.get(statement_key) |
| 251 | + |
| 252 | + if remote_operation is None: |
| 253 | + return UNKNOWN_REMOTE_OPERATION |
| 254 | + |
| 255 | + # Remove all whitespace and newline characters from the beginning of remote_operation |
| 256 | + # and retrieve the first MAX_KEYWORD_LENGTH characters |
| 257 | + remote_operation = remote_operation.lstrip()[:MAX_KEYWORD_LENGTH] |
| 258 | + match: Optional[Match[str]] = re.match(SQL_KEYWORD_PATTERN, remote_operation.upper()) |
| 259 | + remote_operation = match.group(0) if match else UNKNOWN_REMOTE_OPERATION |
| 260 | + |
| 261 | + return remote_operation |
| 262 | + |
| 263 | + |
235 | 264 | def _normalize_service_name(span: ReadableSpan, service_name: str) -> str:
|
236 | 265 | """
|
237 | 266 | TODO: Determine if problems in Java instrumentation are relevant here. Do we need normalization? If so, probably we
|
|
0 commit comments