Skip to content

Commit e94d845

Browse files
authored
Merge branch 'main' into fix-add-missing-postgresql-tests
2 parents e1fdb2e + 4853f32 commit e94d845

File tree

3 files changed

+262
-127
lines changed

3 files changed

+262
-127
lines changed

newrelic/core/attribute.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"aws.requestId",
5050
"cloud.account.id",
5151
"cloud.region",
52+
"cloud.resource_id",
5253
"code.filepath",
5354
"code.function",
5455
"code.lineno",
@@ -57,6 +58,7 @@
5758
"db.instance",
5859
"db.operation",
5960
"db.statement",
61+
"db.system",
6062
"enduser.id",
6163
"error.class",
6264
"error.expected",

newrelic/hooks/external_botocore.py

Lines changed: 121 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
from botocore.response import StreamingBody
2424

25-
from newrelic.api.datastore_trace import datastore_trace
25+
from newrelic.api.datastore_trace import DatastoreTrace
2626
from newrelic.api.external_trace import ExternalTrace
2727
from newrelic.api.function_trace import FunctionTrace
2828
from newrelic.api.message_trace import MessageTrace, message_trace
@@ -841,6 +841,118 @@ def handle_chat_completion_event(transaction, bedrock_attrs):
841841
)
842842

843843

844+
def dynamodb_datastore_trace(
845+
product,
846+
target,
847+
operation,
848+
host=None,
849+
port_path_or_id=None,
850+
database_name=None,
851+
async_wrapper=None,
852+
):
853+
@function_wrapper
854+
def _nr_dynamodb_datastore_trace_wrapper_(wrapped, instance, args, kwargs):
855+
wrapper = async_wrapper if async_wrapper is not None else get_async_wrapper(wrapped)
856+
if not wrapper:
857+
parent = current_trace()
858+
if not parent:
859+
return wrapped(*args, **kwargs)
860+
else:
861+
parent = None
862+
863+
if callable(product):
864+
if instance is not None:
865+
_product = product(instance, *args, **kwargs)
866+
else:
867+
_product = product(*args, **kwargs)
868+
else:
869+
_product = product
870+
871+
if callable(target):
872+
if instance is not None:
873+
_target = target(instance, *args, **kwargs)
874+
else:
875+
_target = target(*args, **kwargs)
876+
else:
877+
_target = target
878+
879+
if callable(operation):
880+
if instance is not None:
881+
_operation = operation(instance, *args, **kwargs)
882+
else:
883+
_operation = operation(*args, **kwargs)
884+
else:
885+
_operation = operation
886+
887+
if callable(host):
888+
if instance is not None:
889+
_host = host(instance, *args, **kwargs)
890+
else:
891+
_host = host(*args, **kwargs)
892+
else:
893+
_host = host
894+
895+
if callable(port_path_or_id):
896+
if instance is not None:
897+
_port_path_or_id = port_path_or_id(instance, *args, **kwargs)
898+
else:
899+
_port_path_or_id = port_path_or_id(*args, **kwargs)
900+
else:
901+
_port_path_or_id = port_path_or_id
902+
903+
if callable(database_name):
904+
if instance is not None:
905+
_database_name = database_name(instance, *args, **kwargs)
906+
else:
907+
_database_name = database_name(*args, **kwargs)
908+
else:
909+
_database_name = database_name
910+
911+
trace = DatastoreTrace(
912+
_product, _target, _operation, _host, _port_path_or_id, _database_name, parent=parent, source=wrapped
913+
)
914+
915+
# Try to capture AWS DynamoDB info as agent attributes. Log any exception to debug.
916+
agent_attrs = {}
917+
try:
918+
region = None
919+
if hasattr(instance, "_client_config") and hasattr(instance._client_config, "region_name"):
920+
region = instance._client_config.region_name
921+
922+
transaction = current_transaction()
923+
settings = transaction.settings if transaction.settings else global_settings()
924+
account_id = settings.cloud.aws.account_id if settings and settings.cloud.aws.account_id else None
925+
926+
# There are 3 different partition options.
927+
# See https://docs.aws.amazon.com/IAM/latest/UserGuide/reference-arns.html for details.
928+
partition = None
929+
if hasattr(instance, "_endpoint") and hasattr(instance._endpoint, "host"):
930+
_db_host = instance._endpoint.host
931+
partition = "aws"
932+
if "amazonaws.cn" in _db_host:
933+
partition = "aws-cn"
934+
elif "amazonaws-us-gov.com" in _db_host:
935+
partition = "aws-us-gov"
936+
937+
if partition and region and account_id and _target:
938+
agent_attrs["cloud.resource_id"] = (
939+
f"arn:{partition}:dynamodb:{region}:{account_id:012d}:table/{_target}"
940+
)
941+
agent_attrs["db.system"] = "DynamoDB"
942+
943+
except Exception as e:
944+
_logger.debug("Failed to capture AWS DynamoDB info.", exc_info=True)
945+
trace.agent_attributes.update(agent_attrs)
946+
947+
if wrapper: # pylint: disable=W0125,W0126
948+
return wrapper(wrapped, trace)(*args, **kwargs)
949+
950+
with trace:
951+
return wrapped(*args, **kwargs)
952+
953+
return _nr_dynamodb_datastore_trace_wrapper_
954+
955+
844956
def sqs_message_trace(
845957
operation,
846958
destination_type,
@@ -891,14 +1003,14 @@ def _nr_sqs_message_trace_wrapper_(wrapped, instance, args, kwargs):
8911003

8921004
CUSTOM_TRACE_POINTS = {
8931005
("sns", "publish"): message_trace("SNS", "Produce", "Topic", extract(("TopicArn", "TargetArn"), "PhoneNumber")),
894-
("dynamodb", "put_item"): datastore_trace("DynamoDB", extract("TableName"), "put_item"),
895-
("dynamodb", "get_item"): datastore_trace("DynamoDB", extract("TableName"), "get_item"),
896-
("dynamodb", "update_item"): datastore_trace("DynamoDB", extract("TableName"), "update_item"),
897-
("dynamodb", "delete_item"): datastore_trace("DynamoDB", extract("TableName"), "delete_item"),
898-
("dynamodb", "create_table"): datastore_trace("DynamoDB", extract("TableName"), "create_table"),
899-
("dynamodb", "delete_table"): datastore_trace("DynamoDB", extract("TableName"), "delete_table"),
900-
("dynamodb", "query"): datastore_trace("DynamoDB", extract("TableName"), "query"),
901-
("dynamodb", "scan"): datastore_trace("DynamoDB", extract("TableName"), "scan"),
1006+
("dynamodb", "put_item"): dynamodb_datastore_trace("DynamoDB", extract("TableName"), "put_item"),
1007+
("dynamodb", "get_item"): dynamodb_datastore_trace("DynamoDB", extract("TableName"), "get_item"),
1008+
("dynamodb", "update_item"): dynamodb_datastore_trace("DynamoDB", extract("TableName"), "update_item"),
1009+
("dynamodb", "delete_item"): dynamodb_datastore_trace("DynamoDB", extract("TableName"), "delete_item"),
1010+
("dynamodb", "create_table"): dynamodb_datastore_trace("DynamoDB", extract("TableName"), "create_table"),
1011+
("dynamodb", "delete_table"): dynamodb_datastore_trace("DynamoDB", extract("TableName"), "delete_table"),
1012+
("dynamodb", "query"): dynamodb_datastore_trace("DynamoDB", extract("TableName"), "query"),
1013+
("dynamodb", "scan"): dynamodb_datastore_trace("DynamoDB", extract("TableName"), "scan"),
9021014
("sqs", "send_message"): sqs_message_trace(
9031015
"Produce", "Queue", extract_sqs, extract_agent_attrs=extract_sqs_agent_attrs
9041016
),

0 commit comments

Comments
 (0)