Skip to content

Commit 2b413fb

Browse files
committed
Sanitise SQL queries in collector mode
When `set_sql_body` is used in collector mode, emit attributes following the OpenTelemetry Semantic Conventions for Database Spans, as the collector expects, rather than the `appsignal.sql_body` attribute that the agent expects.
1 parent c4e330c commit 2b413fb

3 files changed

Lines changed: 35 additions & 3 deletions

File tree

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
bump: patch
3+
type: fix
4+
---
5+
6+
Emit the `db.system.name` and `db.query.text` semantic-convention attributes
7+
instead of `appsignal.sql_body` when `set_sql_body` is used in collector
8+
mode. This fixes SQL query sanitization when using the experimental collector
9+
mode.

src/appsignal/tracing.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,14 @@ def set_body(body: str, span: Span | None = None) -> None:
101101

102102

103103
def set_sql_body(body: str, span: Span | None = None) -> None:
104-
_set_attribute("appsignal.sql_body", body, span)
104+
# The collector sanitizes SQL via the `db.query.text` attribute, gated on
105+
# `db.system.name` being set to a recognized SQL system. The agent
106+
# sanitizes via the `appsignal.sql_body` magic attribute.
107+
if _use_collector():
108+
_set_attribute("db.system.name", "other_sql", span)
109+
_set_attribute("db.query.text", body, span)
110+
else:
111+
_set_attribute("appsignal.sql_body", body, span)
105112

106113

107114
def set_namespace(namespace: str, span: Span | None = None) -> None:

tests/test_tracing.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
from opentelemetry import trace
44
from opentelemetry.trace import StatusCode
55

6-
from appsignal.client import Client
7-
86
from appsignal import (
97
send_error,
108
send_error_with_context,
@@ -21,6 +19,7 @@
2119
set_sql_body,
2220
set_tag,
2321
)
22+
from appsignal.client import Client
2423

2524

2625
tracer = trace.get_tracer("appsignal/tests")
@@ -98,6 +97,23 @@ def test_set_name_collector_mode(spans):
9897
assert "appsignal.name" not in dict(span.attributes)
9998

10099

100+
def test_set_sql_body_collector_mode(spans):
101+
Client(
102+
active=True,
103+
name="MyApp",
104+
push_api_key="0000-0000-0000-0000",
105+
collector_endpoint="https://custom-endpoint.appsignal.com",
106+
)
107+
108+
with tracer.start_as_current_span("span"):
109+
set_sql_body("SELECT * FROM users")
110+
111+
attributes = dict(spans()[0].attributes)
112+
assert attributes["db.system.name"] == "other_sql"
113+
assert attributes["db.query.text"] == "SELECT * FROM users"
114+
assert "appsignal.sql_body" not in attributes
115+
116+
101117
def test_set_attributes_on_span(spans):
102118
with tracer.start_as_current_span("parent span") as span:
103119
with tracer.start_as_current_span("child span"):

0 commit comments

Comments
 (0)