Skip to content

Commit 328fd2b

Browse files
committed
ft: add instrumentation to dynamodb
Signed-off-by: Cagri Yonca <[email protected]>
1 parent 05e798a commit 328fd2b

File tree

5 files changed

+433
-35
lines changed

5 files changed

+433
-35
lines changed

src/instana/instrumentation/aws/boto3.py

Lines changed: 31 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
# (c) Copyright IBM Corp. 2025
2+
try:
3+
from typing import TYPE_CHECKING, Any, Callable, Dict, Sequence, Tuple, Type
24

3-
from typing import TYPE_CHECKING, Any, Callable, Dict, Sequence, Tuple, Type
5+
from opentelemetry.semconv.trace import SpanAttributes
46

5-
from opentelemetry.semconv.trace import SpanAttributes
7+
from instana.instrumentation.aws.dynamodb import create_dynamodb_span
8+
from instana.instrumentation.aws.s3 import create_s3_span
69

7-
if TYPE_CHECKING:
8-
from botocore.auth import SigV4Auth
9-
from botocore.client import BaseClient
10+
if TYPE_CHECKING:
11+
from botocore.auth import SigV4Auth
12+
from botocore.client import BaseClient
1013

11-
from instana.span.span import InstanaSpan
14+
from instana.span.span import InstanaSpan
1215

13-
try:
1416
import json
1517

1618
import wrapt
@@ -69,37 +71,34 @@ def make_api_call_with_instana(
6971

7072
parent_context = parent_span.get_span_context() if parent_span else None
7173

72-
try:
74+
if instance.meta.service_model.service_name == "dynamodb":
75+
create_dynamodb_span(wrapped, instance, args, kwargs, parent_context)
76+
elif instance.meta.service_model.service_name == "s3":
77+
create_s3_span(wrapped, instance, args, kwargs, parent_context)
78+
else:
7379
with tracer.start_as_current_span(
7480
"boto3", span_context=parent_context
7581
) as span:
76-
try:
77-
operation = args[0]
78-
payload = args[1]
82+
operation = args[0]
83+
payload = args[1]
7984

80-
span.set_attribute("op", operation)
81-
span.set_attribute("ep", instance._endpoint.host)
82-
span.set_attribute("reg", instance._client_config.region_name)
85+
span.set_attribute("op", operation)
86+
span.set_attribute("ep", instance._endpoint.host)
87+
span.set_attribute("reg", instance._client_config.region_name)
8388

84-
span.set_attribute(
85-
SpanAttributes.HTTP_URL,
86-
instance._endpoint.host + ":443/" + args[0],
87-
)
88-
span.set_attribute(SpanAttributes.HTTP_METHOD, "POST")
89+
span.set_attribute(
90+
SpanAttributes.HTTP_URL,
91+
instance._endpoint.host + ":443/" + args[0],
92+
)
93+
span.set_attribute(SpanAttributes.HTTP_METHOD, "POST")
8994

90-
# Don't collect payload for SecretsManager
91-
if not hasattr(instance, "get_secret_value"):
92-
span.set_attribute("payload", payload)
95+
# Don't collect payload for SecretsManager
96+
if not hasattr(instance, "get_secret_value"):
97+
span.set_attribute("payload", payload)
9398

94-
# Inject context when invoking lambdas
95-
if "lambda" in instance._endpoint.host and operation == "Invoke":
96-
lambda_inject_context(payload, span)
97-
98-
except Exception:
99-
logger.debug(
100-
"make_api_call_with_instana: collect error",
101-
exc_info=True,
102-
)
99+
# Inject context when invoking lambdas
100+
if "lambda" in instance._endpoint.host and operation == "Invoke":
101+
lambda_inject_context(payload, span)
103102

104103
try:
105104
result = wrapped(*args, **kwargs)
@@ -117,10 +116,7 @@ def make_api_call_with_instana(
117116
except Exception as exc:
118117
span.mark_as_errored({"error": exc})
119118
raise
120-
except Exception:
121-
logger.debug("make_api_call_with_instana: collect error", exc_info=True)
122-
else:
123-
return wrapped(*args, **kwargs)
119+
return wrapped(*args, **kwargs)
124120

125121
except ImportError:
126122
pass
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# (c) Copyright IBM Corp. 2025
2+
3+
from typing import TYPE_CHECKING, Any, Callable, Dict, Sequence, Type
4+
5+
if TYPE_CHECKING:
6+
from botocore.client import BaseClient
7+
8+
from instana.log import logger
9+
from instana.singletons import tracer
10+
from instana.span_context import SpanContext
11+
12+
13+
def create_dynamodb_span(
14+
wrapped: Callable[..., Dict[str, Any]],
15+
instance: Type["BaseClient"],
16+
args: Sequence[Dict[str, Any]],
17+
kwargs: Dict[str, Any],
18+
parent_context: SpanContext,
19+
) -> None:
20+
with tracer.start_as_current_span("dynamodb", span_context=parent_context) as span:
21+
try:
22+
span.set_attribute("dynamodb.op", args[0])
23+
span.set_attribute("dynamodb.region", instance._client_config.region_name)
24+
if "TableName" in args[1].keys():
25+
span.set_attribute("dynamodb.table", args[1]["TableName"])
26+
except Exception as exc:
27+
span.record_exception(exc)
28+
logger.debug("create_dynamodb_span: collect error", exc_info=True)
29+
30+
31+
logger.debug("Instrumenting DynamoDB")

src/instana/span/kind.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"cassandra",
4141
"celery-client",
4242
"couchbase",
43+
"dynamodb",
4344
"log",
4445
"memcache",
4546
"mongo",
@@ -49,6 +50,7 @@
4950
"redis",
5051
"rpc-client",
5152
"sqlalchemy",
53+
"s3",
5254
"tornado-client",
5355
"urllib3",
5456
"pymongo",

src/instana/span/registered_span.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,13 @@ def _populate_exit_span_data(self, span: "InstanaSpan") -> None:
229229
)
230230
self.data["couchbase"]["sql"] = span.attributes.pop("couchbase.sql", None)
231231

232+
elif span.name == "dynamodb":
233+
self.data["dynamodb"]["op"] = span.attributes.pop("dynamodb.op", None)
234+
self.data["dynamodb"]["region"] = span.attributes.pop(
235+
"dynamodb.region", None
236+
)
237+
self.data["dynamodb"]["table"] = span.attributes.pop("dynamodb.table", None)
238+
232239
elif span.name == "rabbitmq":
233240
self.data["rabbitmq"]["exchange"] = span.attributes.pop("exchange", None)
234241
self.data["rabbitmq"]["queue"] = span.attributes.pop("queue", None)
@@ -253,6 +260,10 @@ def _populate_exit_span_data(self, span: "InstanaSpan") -> None:
253260
# self.data["rpc"]["baggage"] = span.attributes.pop("rpc.baggage", None)
254261
self.data["rpc"]["error"] = span.attributes.pop("rpc.error", None)
255262

263+
elif span.name == "s3":
264+
self.data["s3"]["op"] = span.attributes.pop("s3.op", None)
265+
self.data["s3"]["bucket"] = span.attributes.pop("s3.bucket", None)
266+
256267
elif span.name == "sqlalchemy":
257268
self.data["sqlalchemy"]["sql"] = span.attributes.pop("sqlalchemy.sql", None)
258269
self.data["sqlalchemy"]["eng"] = span.attributes.pop("sqlalchemy.eng", None)

0 commit comments

Comments
 (0)