Skip to content

Commit bd80ce5

Browse files
authored
fix: ignore non-deterministic SQL parameters when matching Postgres query mocks (#61)
1 parent 80d3477 commit bd80ce5

File tree

2 files changed

+37
-4
lines changed

2 files changed

+37
-4
lines changed

drift/instrumentation/psycopg/instrumentation.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from opentelemetry.trace import StatusCode as OTelStatusCode
1515

1616
from ...core.drift_sdk import TuskDrift
17-
from ...core.json_schema_helper import JsonSchemaHelper
17+
from ...core.json_schema_helper import JsonSchemaHelper, SchemaMerge
1818
from ...core.mode_utils import handle_record_mode, handle_replay_mode
1919
from ...core.tracing import TdSpanAttributes
2020
from ...core.tracing.span_utils import CreateSpanOptions, SpanUtils
@@ -1468,7 +1468,21 @@ def _set_span_attributes(
14681468
input_value: The input data dictionary (query, parameters, etc.)
14691469
output_value: The output data dictionary (rows, rowcount, error, etc.)
14701470
"""
1471-
input_result = JsonSchemaHelper.generate_schema_and_hash(input_value, {})
1471+
# IMPORTANT: Tell the exporter (otel_converter) how to generate schema + hashes.
1472+
# The exporter recomputes the schema/hashes at export time from td.input_value and td.input_schema_merges.
1473+
# Mark parameters as match_importance=0.0 so non-deterministic values (e.g. timestamps) don't prevent mock matching.
1474+
span.set_attribute(
1475+
TdSpanAttributes.INPUT_SCHEMA_MERGES,
1476+
json.dumps({"parameters": {"match_importance": 0.0}}),
1477+
)
1478+
1479+
# Set match_importance=0 for parameters to allow fuzzy matching on query text
1480+
# This handles non-deterministic values like timestamps while still exact-matching
1481+
# deterministic values like IDs (exact hash match takes priority over reduced hash)
1482+
input_result = JsonSchemaHelper.generate_schema_and_hash(
1483+
input_value,
1484+
{"parameters": SchemaMerge(match_importance=0.0)},
1485+
)
14721486
output_result = JsonSchemaHelper.generate_schema_and_hash(output_value, {})
14731487

14741488
span.set_attribute(TdSpanAttributes.INPUT_VALUE, json.dumps(input_value))
@@ -1614,6 +1628,7 @@ def _try_get_mock(
16141628
submodule_name="query",
16151629
input_value=input_value,
16161630
kind=SpanKind.CLIENT,
1631+
input_schema_merges={"parameters": SchemaMerge(match_importance=0.0)},
16171632
is_pre_app_start=not sdk.app_ready,
16181633
)
16191634

drift/instrumentation/psycopg2/instrumentation.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from opentelemetry.trace import StatusCode as OTelStatusCode
2020

2121
from ...core.drift_sdk import TuskDrift
22-
from ...core.json_schema_helper import JsonSchemaHelper
22+
from ...core.json_schema_helper import JsonSchemaHelper, SchemaMerge
2323
from ...core.mode_utils import handle_record_mode, handle_replay_mode
2424
from ...core.tracing import TdSpanAttributes
2525
from ...core.tracing.span_utils import CreateSpanOptions, SpanUtils
@@ -822,6 +822,9 @@ def _try_get_mock(
822822
# Use centralized mock finding utility
823823
from ...core.mock_utils import find_mock_response_sync
824824

825+
# Set match_importance=0 for parameters to allow fuzzy matching on query text
826+
# This handles non-deterministic values like timestamps while still exact-matching
827+
# deterministic values like IDs (exact hash match takes priority over reduced hash)
825828
mock_response_output = find_mock_response_sync(
826829
sdk=sdk,
827830
trace_id=trace_id,
@@ -833,6 +836,7 @@ def _try_get_mock(
833836
submodule_name="query",
834837
input_value=input_value,
835838
kind=SpanKind.CLIENT,
839+
input_schema_merges={"parameters": SchemaMerge(match_importance=0.0)},
836840
is_pre_app_start=not sdk.app_ready,
837841
)
838842

@@ -984,6 +988,14 @@ def _finalize_query_span(
984988
# Serialize parameters to handle datetime and other non-JSON types
985989
input_value["parameters"] = serialize_value(params)
986990

991+
# IMPORTANT: Tell the exporter (otel_converter) how to generate schema + hashes.
992+
# The exporter recomputes the schema/hashes at export time from td.input_value and td.input_schema_merges.
993+
# Mark parameters as match_importance=0.0 so non-deterministic values (e.g. timestamps) don't prevent mock matching.
994+
span.set_attribute(
995+
TdSpanAttributes.INPUT_SCHEMA_MERGES,
996+
json.dumps({"parameters": {"match_importance": 0.0}}),
997+
)
998+
987999
# Build output value
9881000
output_value = {}
9891001

@@ -1078,7 +1090,13 @@ def patched_fetchall():
10781090
logger.debug(f"Error getting query metadata: {e}")
10791091

10801092
# Generate schemas and hashes
1081-
input_result = JsonSchemaHelper.generate_schema_and_hash(input_value, {})
1093+
# Set match_importance=0 for parameters to allow fuzzy matching on query text
1094+
# This handles non-deterministic values like timestamps while still exact-matching
1095+
# deterministic values like IDs (exact hash match takes priority over reduced hash)
1096+
input_result = JsonSchemaHelper.generate_schema_and_hash(
1097+
input_value,
1098+
{"parameters": SchemaMerge(match_importance=0.0)},
1099+
)
10821100
output_result = JsonSchemaHelper.generate_schema_and_hash(output_value, {})
10831101

10841102
# Set span attributes

0 commit comments

Comments
 (0)