Skip to content

Commit 6c10093

Browse files
authored
Merge pull request #1346 from newrelic/fix-datastore-spans
Fix Datastore Span Attributes
2 parents 7f7a878 + edf60fb commit 6c10093

File tree

5 files changed

+78
-27
lines changed

5 files changed

+78
-27
lines changed

newrelic/core/database_node.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,4 @@ def span_event(self, *args, **kwargs):
288288

289289
self.agent_attributes["db.statement"] = sql
290290

291-
if self.target:
292-
self.agent_attributes["db.collection"] = self.target
293-
294291
return super(DatabaseNode, self).span_event(*args, **kwargs)

newrelic/core/datastore_node.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -136,12 +136,3 @@ def trace_node(self, stats, root, connections):
136136
return newrelic.core.trace_node.TraceNode(
137137
start_time=start_time, end_time=end_time, name=name, params=params, children=children, label=None
138138
)
139-
140-
def span_event(self, *args, **kwargs):
141-
if self.operation:
142-
self.agent_attributes["db.operation"] = self.operation
143-
144-
if self.target:
145-
self.agent_attributes["db.collection"] = self.target
146-
147-
return super(DatastoreNode, self).span_event(*args, **kwargs)

newrelic/core/node_mixin.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,16 +115,30 @@ def span_event(self, *args, **kwargs):
115115
a_attrs = attrs[2]
116116

117117
i_attrs["category"] = "datastore"
118-
i_attrs["component"] = self.product
119118
i_attrs["span.kind"] = "client"
120119

120+
if self.product:
121+
i_attrs["component"] = a_attrs["db.system"] = attribute.process_user_attribute("db.system", self.product)[1]
122+
if self.operation:
123+
a_attrs["db.operation"] = attribute.process_user_attribute("db.operation", self.operation)[1]
124+
if self.target:
125+
a_attrs["db.collection"] = attribute.process_user_attribute("db.collection", self.target)[1]
126+
121127
if self.instance_hostname:
122-
_, a_attrs["peer.hostname"] = attribute.process_user_attribute("peer.hostname", self.instance_hostname)
128+
peer_hostname = attribute.process_user_attribute("peer.hostname", self.instance_hostname)[1]
123129
else:
124-
a_attrs["peer.hostname"] = "Unknown"
130+
peer_hostname = "Unknown"
131+
132+
a_attrs["peer.hostname"] = a_attrs["server.address"] = peer_hostname
133+
134+
peer_address = f"{peer_hostname}:{self.port_path_or_id or 'Unknown'}"
125135

126-
peer_address = f"{self.instance_hostname or 'Unknown'}:{self.port_path_or_id or 'Unknown'}"
136+
a_attrs["peer.address"] = attribute.process_user_attribute("peer.address", peer_address)[1]
127137

128-
_, a_attrs["peer.address"] = attribute.process_user_attribute("peer.address", peer_address)
138+
# Attempt to treat port_path_or_id as an integer, fallback to not including it
139+
try:
140+
a_attrs["server.port"] = int(self.port_path_or_id)
141+
except Exception:
142+
pass
129143

130144
return attrs

newrelic/hooks/external_botocore.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1055,7 +1055,6 @@ def _nr_dynamodb_datastore_trace_wrapper_(wrapped, instance, args, kwargs):
10551055
agent_attrs["cloud.resource_id"] = (
10561056
f"arn:{partition}:dynamodb:{region}:{account_id:012d}:table/{_target}"
10571057
)
1058-
agent_attrs["db.system"] = "DynamoDB"
10591058

10601059
except Exception as e:
10611060
_logger.debug("Failed to capture AWS DynamoDB info.", exc_info=True)

tests/agent_features/test_span_events.py

Lines changed: 59 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -181,22 +181,48 @@ def test_database_db_statement_exclude():
181181

182182

183183
@pytest.mark.parametrize(
184-
"trace_type,args,attrs",
184+
"trace_type,args,i_attrs,a_attrs",
185185
(
186186
(
187187
DatastoreTrace,
188-
("db_product", "db_target", "db_operation"),
189-
{"db.collection": "db_target", "db.operation": "db_operation"},
188+
("db_product", "db_target", "db_operation", "db_host", "1234", "db_name"),
189+
{"component": "db_product", "span.kind": "client"},
190+
{
191+
"db.system": "db_product",
192+
"db.operation": "db_operation",
193+
"db.collection": "db_target",
194+
"db.instance": "db_name",
195+
"peer.address": "db_host:1234",
196+
"peer.hostname": "db_host",
197+
"server.address": "db_host",
198+
"server.port": 1234,
199+
},
190200
),
191201
(
192202
DatabaseTrace,
193203
("select 1 from db_table",),
194-
{"db.collection": "db_table", "db.statement": "select ? from db_table"},
204+
{"span.kind": "client"},
205+
{"db.collection": "db_table", "db.statement": "select ? from db_table", "db.operation": "select"},
206+
),
207+
(
208+
DatabaseTrace,
209+
("select 1 from db_table", None, None, None, None, None, "db_host", "1234", "db_name"),
210+
{"span.kind": "client"},
211+
{
212+
"db.statement": "select ? from db_table",
213+
"db.operation": "select",
214+
"db.collection": "db_table",
215+
"db.instance": "db_name",
216+
"peer.address": "db_host:1234",
217+
"peer.hostname": "db_host",
218+
"server.address": "db_host",
219+
"server.port": 1234,
220+
},
195221
),
196222
),
197223
)
198-
def test_datastore_database_trace_attrs(trace_type, args, attrs):
199-
@validate_span_events(count=1, exact_agents=attrs)
224+
def test_datastore_database_trace_attrs(trace_type, args, i_attrs, a_attrs):
225+
@validate_span_events(count=1, exact_intrinsics=i_attrs, exact_agents=a_attrs)
200226
@override_application_settings({"distributed_tracing.enabled": True, "span_events.enabled": True})
201227
@background_task(name="test_database_db_statement_exclude")
202228
def test():
@@ -293,8 +319,23 @@ def _test():
293319
@pytest.mark.parametrize(
294320
"kwarg_override,attribute_override",
295321
(
296-
({"host": "a" * 256}, {"peer.hostname": "a" * 255, "peer.address": "a" * 255}),
297-
({"port_path_or_id": "a" * 256, "host": "a"}, {"peer.hostname": "a", "peer.address": f"a:{'a' * 253}"}),
322+
({"product": "a" * 256}, {"component": "a" * 255, "db.system": "a" * 255}),
323+
({"target": "a" * 256}, {"db.collection": "a" * 255}),
324+
({"operation": "a" * 256}, {"db.operation": "a" * 255}),
325+
({"host": "a" * 256}, {"peer.hostname": "a" * 255, "peer.address": "a" * 255, "server.address": "a" * 255}),
326+
(
327+
{"port_path_or_id": "a" * 256, "host": "a"},
328+
{"peer.hostname": "a", "peer.address": f"a:{'a' * 253}", "server.address": "a", "server.port": None},
329+
),
330+
(
331+
{"port_path_or_id": "1" * 256, "host": "a"},
332+
{
333+
"peer.hostname": "a",
334+
"peer.address": f"a:{'1' * 253}",
335+
"server.address": "a",
336+
"server.port": int("1" * 256),
337+
},
338+
),
298339
({"database_name": "a" * 256}, {"db.instance": "a" * 255}),
299340
),
300341
)
@@ -308,7 +349,16 @@ def test_datastore_span_limits(kwarg_override, attribute_override):
308349
"component": "library",
309350
}
310351

311-
exact_agents = {"db.instance": "db", "peer.hostname": "foo", "peer.address": "foo:1234"}
352+
exact_agents = {
353+
"db.collection": "table",
354+
"db.instance": "db",
355+
"db.operation": "operation",
356+
"db.system": "library",
357+
"peer.address": "foo:1234",
358+
"peer.hostname": "foo",
359+
"server.address": "foo",
360+
"server.port": 1234,
361+
}
312362

313363
for k, v in attribute_override.items():
314364
if k in exact_agents:

0 commit comments

Comments
 (0)