@@ -598,3 +598,160 @@ def child_span_handler(request):
598598 else :
599599 assert "user.ip_address" not in server_span ["attributes" ]
600600 assert "user.ip_address" not in child_span ["attributes" ]
601+
602+
603+ NO_QUERY_STRING = object ()
604+
605+ _QUERY_PARAM_DATA_COLLECTION_CASES = [
606+ pytest .param (
607+ {"send_default_pii" : True },
608+ "toy=tennisball&color=red&auth=secret" ,
609+ id = "send_default_pii_true" ,
610+ ),
611+ pytest .param (
612+ {"send_default_pii" : False },
613+ NO_QUERY_STRING ,
614+ id = "send_default_pii_false" ,
615+ ),
616+ pytest .param (
617+ {},
618+ NO_QUERY_STRING ,
619+ id = "defaults" ,
620+ ),
621+ pytest .param (
622+ {"_experiments" : {"data_collection" : {}}},
623+ "toy=tennisball&color=red&auth=[Filtered]" ,
624+ id = "data_collection_denylist_default" ,
625+ ),
626+ pytest .param (
627+ {
628+ "_experiments" : {
629+ "data_collection" : {
630+ "url_query_params" : {"mode" : "denylist" , "terms" : ["toy" ]}
631+ }
632+ }
633+ },
634+ "toy=[Filtered]&color=red&auth=[Filtered]" ,
635+ id = "data_collection_denylist_custom_terms" ,
636+ ),
637+ pytest .param (
638+ {
639+ "_experiments" : {
640+ "data_collection" : {
641+ "url_query_params" : {"mode" : "allowlist" , "terms" : ["toy" ]}
642+ }
643+ }
644+ },
645+ "toy=tennisball&color=[Filtered]&auth=[Filtered]" ,
646+ id = "data_collection_allowlist" ,
647+ ),
648+ pytest .param (
649+ {
650+ "_experiments" : {
651+ "data_collection" : {
652+ "url_query_params" : {"mode" : "allowlist" , "terms" : ["auth" ]}
653+ }
654+ }
655+ },
656+ "toy=[Filtered]&color=[Filtered]&auth=[Filtered]" ,
657+ id = "data_collection_allowlist_sensitive_term" ,
658+ ),
659+ pytest .param (
660+ {"_experiments" : {"data_collection" : {"url_query_params" : {"mode" : "off" }}}},
661+ NO_QUERY_STRING ,
662+ id = "data_collection_off" ,
663+ ),
664+ pytest .param (
665+ {
666+ "send_default_pii" : True ,
667+ "_experiments" : {"data_collection" : {"url_query_params" : {"mode" : "off" }}},
668+ },
669+ NO_QUERY_STRING ,
670+ id = "data_collection_wins_over_send_default_pii" ,
671+ ),
672+ ]
673+
674+
675+ @pytest .mark .skipif (
676+ not PERFORMANCE_SUPPORTED , reason = "Performance not supported on this Sanic version"
677+ )
678+ @pytest .mark .parametrize (
679+ "init_kwargs, expected_query" , _QUERY_PARAM_DATA_COLLECTION_CASES
680+ )
681+ def test_url_query_data_collection_span_streaming (
682+ sentry_init , app , capture_items , init_kwargs , expected_query
683+ ):
684+ init_kwargs = dict (init_kwargs )
685+ experiments = dict (init_kwargs .pop ("_experiments" , {}))
686+ experiments ["trace_lifecycle" ] = "stream"
687+ sentry_init (
688+ integrations = [SanicIntegration ()],
689+ traces_sample_rate = 1.0 ,
690+ _experiments = experiments ,
691+ ** init_kwargs ,
692+ )
693+
694+ items = capture_items ("span" )
695+
696+ c = get_client (app )
697+ with c as client :
698+ _ , response = client .get ("/message?toy=tennisball&color=red&auth=secret" )
699+ assert response .status == 200
700+
701+ sentry_sdk .flush ()
702+
703+ (server_span ,) = [
704+ i .payload
705+ for i in items
706+ if i .payload ["attributes" ].get ("sentry.origin" ) == "auto.http.sanic"
707+ and i .payload ["is_segment" ]
708+ ]
709+
710+ data_collection_enabled = "data_collection" in experiments
711+ url_attrs_expected = data_collection_enabled or init_kwargs .get (
712+ "send_default_pii" , False
713+ )
714+
715+ if expected_query is NO_QUERY_STRING :
716+ assert "http.query" not in server_span ["attributes" ]
717+ if url_attrs_expected :
718+ assert server_span ["attributes" ]["url.full" ].endswith ("/message" )
719+ assert server_span ["attributes" ]["url.path" ].endswith ("/message" )
720+ else :
721+ assert "url.full" not in server_span ["attributes" ]
722+ assert "url.path" not in server_span ["attributes" ]
723+ else :
724+ assert server_span ["attributes" ]["http.query" ] == expected_query
725+ assert server_span ["attributes" ]["url.full" ].endswith (
726+ f"/message?{ expected_query } "
727+ )
728+ assert server_span ["attributes" ]["url.path" ].endswith ("/message" )
729+
730+
731+ @pytest .mark .parametrize (
732+ "init_kwargs, expected_query" , _QUERY_PARAM_DATA_COLLECTION_CASES
733+ )
734+ def test_url_query_data_collection_event_processor (
735+ sentry_init , app , capture_events , init_kwargs , expected_query
736+ ):
737+ sentry_init (integrations = [SanicIntegration ()], ** init_kwargs )
738+
739+ events = capture_events ()
740+
741+ c = get_client (app )
742+ with c as client :
743+ _ , response = client .get ("/message?toy=tennisball&color=red&auth=secret" )
744+ assert response .status == 200
745+
746+ (event ,) = events
747+
748+ assert event ["request" ]["url" ].endswith ("/message" )
749+ assert event ["request" ]["method" ] == "GET"
750+ if "data_collection" not in init_kwargs .get ("_experiments" , {}):
751+ assert (
752+ event ["request" ]["query_string" ] == "toy=tennisball&color=red&auth=secret"
753+ )
754+ elif expected_query is NO_QUERY_STRING :
755+ assert "query_string" not in event ["request" ]
756+ else :
757+ assert event ["request" ]["query_string" ] == expected_query
0 commit comments