@@ -653,6 +653,7 @@ def test_stack_trace_defaults(self) -> None:
653653
654654 assert self .options .stack_trace_level == "all"
655655 assert self .options .stack_trace_length == 30
656+ assert self .options .stack_trace_technology_config == {}
656657
657658 @pytest .mark .parametrize (
658659 "level_value,expected_level" ,
@@ -692,7 +693,7 @@ def test_stack_trace_level_env_var_invalid(
692693 "length_value,expected_length" ,
693694 [
694695 ("25" , 25 ),
695- ("60" , 60 ), # Not capped here, capped when _add_stack () is called
696+ ("60" , 60 ), # Not capped here, capped when add_stack () is called
696697 ],
697698 )
698699 def test_stack_trace_length_env_var (
@@ -739,3 +740,253 @@ def test_stack_trace_both_env_vars(self) -> None:
739740 self .options = BaseOptions ()
740741 assert self .options .stack_trace_level == "error"
741742 assert self .options .stack_trace_length == 15
743+
744+ def test_stack_trace_in_code_config (self ) -> None :
745+ """Test in-code configuration for stack trace."""
746+ config ["tracing" ] = {
747+ "global" : {
748+ "stack_trace" : "error" ,
749+ "stack_trace_length" : 20
750+ }
751+ }
752+ self .options = BaseOptions ()
753+ assert self .options .stack_trace_level == "error"
754+ assert self .options .stack_trace_length == 20
755+
756+ def test_stack_trace_agent_config (self ) -> None :
757+ """Test agent configuration for stack trace."""
758+ self .options = StandardOptions ()
759+
760+ test_tracing = {
761+ "global" : {
762+ "stack-trace" : "error" ,
763+ "stack-trace-length" : 15
764+ }
765+ }
766+ self .options .set_tracing (test_tracing )
767+
768+ assert self .options .stack_trace_level == "error"
769+ assert self .options .stack_trace_length == 15
770+
771+ def test_stack_trace_precedence_env_over_in_code (self ) -> None :
772+ """Test environment variables take precedence over in-code config."""
773+ config ["tracing" ] = {
774+ "global" : {
775+ "stack_trace" : "all" ,
776+ "stack_trace_length" : 10
777+ }
778+ }
779+
780+ with patch .dict (
781+ os .environ ,
782+ {
783+ "INSTANA_STACK_TRACE" : "error" ,
784+ "INSTANA_STACK_TRACE_LENGTH" : "25" ,
785+ },
786+ ):
787+ self .options = BaseOptions ()
788+ assert self .options .stack_trace_level == "error"
789+ assert self .options .stack_trace_length == 25
790+
791+ def test_stack_trace_precedence_in_code_over_agent (self ) -> None :
792+ """Test in-code config takes precedence over agent config."""
793+ config ["tracing" ] = {
794+ "global" : {
795+ "stack_trace" : "error" ,
796+ "stack_trace_length" : 20
797+ }
798+ }
799+
800+ self .options = StandardOptions ()
801+
802+ test_tracing = {
803+ "global" : {
804+ "stack-trace" : "all" ,
805+ "stack-trace-length" : 10
806+ }
807+ }
808+ self .options .set_tracing (test_tracing )
809+
810+ # In-code config should win
811+ assert self .options .stack_trace_level == "error"
812+ assert self .options .stack_trace_length == 20
813+
814+ def test_stack_trace_technology_specific_override (self ) -> None :
815+ """Test technology-specific stack trace configuration."""
816+ self .options = StandardOptions ()
817+
818+ test_tracing = {
819+ "global" : {
820+ "stack-trace" : "error" ,
821+ "stack-trace-length" : 25
822+ },
823+ "kafka" : {
824+ "stack-trace" : "all" ,
825+ "stack-trace-length" : 35
826+ },
827+ "redis" : {
828+ "stack-trace" : "none"
829+ }
830+ }
831+ self .options .set_tracing (test_tracing )
832+
833+ # Global config
834+ assert self .options .stack_trace_level == "error"
835+ assert self .options .stack_trace_length == 25
836+
837+ # Kafka-specific override
838+ level , length = self .options .get_stack_trace_config ("kafka-producer" )
839+ assert level == "all"
840+ assert length == 35
841+
842+ # Redis-specific override (inherits length from global)
843+ level , length = self .options .get_stack_trace_config ("redis" )
844+ assert level == "none"
845+ assert length == 25
846+
847+ # Non-overridden span uses global
848+ level , length = self .options .get_stack_trace_config ("mysql" )
849+ assert level == "error"
850+ assert length == 25
851+
852+ def test_get_stack_trace_config_with_hyphenated_span_name (self ) -> None :
853+ """Test get_stack_trace_config extracts technology name correctly."""
854+ self .options = StandardOptions ()
855+ self .options .stack_trace_technology_config = {
856+ "kafka" : {"level" : "all" , "length" : 35 }
857+ }
858+
859+ # Should match "kafka" from "kafka-producer"
860+ level , length = self .options .get_stack_trace_config ("kafka-producer" )
861+ assert level == "all"
862+ assert length == 35
863+
864+ # Should match "kafka" from "kafka-consumer"
865+ level , length = self .options .get_stack_trace_config ("kafka-consumer" )
866+ assert level == "all"
867+ assert length == 35
868+
869+ def test_stack_trace_yaml_config_basic (self ) -> None :
870+ """Test YAML configuration for stack trace (basic format)."""
871+ with patch .dict (
872+ os .environ ,
873+ {"INSTANA_CONFIG_PATH" : "tests/util/test_stack_trace_config_1.yaml" },
874+ ):
875+ self .options = BaseOptions ()
876+ assert self .options .stack_trace_level == "all"
877+ assert self .options .stack_trace_length == 15
878+
879+ def test_stack_trace_yaml_config_with_prefix (
880+ self ,
881+ caplog : pytest .LogCaptureFixture ,
882+ ) -> None :
883+ """Test YAML configuration with com.instana prefix."""
884+ caplog .set_level (logging .WARNING , logger = "instana" )
885+ with patch .dict (
886+ os .environ ,
887+ {"INSTANA_CONFIG_PATH" : "tests/util/test_stack_trace_config_2.yaml" },
888+ ):
889+ self .options = BaseOptions ()
890+ assert self .options .stack_trace_level == "error"
891+ assert self .options .stack_trace_length == 20
892+
893+ assert (
894+ 'Please use "tracing" instead of "com.instana.tracing" for local configuration file.'
895+ in caplog .messages
896+ )
897+
898+ def test_stack_trace_yaml_config_disabled (self ) -> None :
899+ """Test YAML configuration with stack trace disabled."""
900+ with patch .dict (
901+ os .environ ,
902+ {"INSTANA_CONFIG_PATH" : "tests/util/test_stack_trace_config_3.yaml" },
903+ ):
904+ self .options = BaseOptions ()
905+ assert self .options .stack_trace_level == "none"
906+ assert self .options .stack_trace_length == 5
907+
908+ def test_stack_trace_yaml_config_invalid (
909+ self ,
910+ caplog : pytest .LogCaptureFixture ,
911+ ) -> None :
912+ """Test YAML configuration with invalid values."""
913+ caplog .set_level (logging .WARNING , logger = "instana" )
914+ with patch .dict (
915+ os .environ ,
916+ {"INSTANA_CONFIG_PATH" : "tests/util/test_stack_trace_config_4.yaml" },
917+ ):
918+ self .options = BaseOptions ()
919+ # Should fall back to defaults
920+ assert self .options .stack_trace_level == "all"
921+ assert self .options .stack_trace_length == 30
922+ assert any (
923+ "Invalid stack-trace value" in message
924+ for message in caplog .messages
925+ )
926+ assert any (
927+ "must be positive" in message
928+ for message in caplog .messages
929+ )
930+
931+ def test_stack_trace_yaml_config_partial (self ) -> None :
932+ """Test YAML configuration with only stack-trace (no length)."""
933+ with patch .dict (
934+ os .environ ,
935+ {"INSTANA_CONFIG_PATH" : "tests/util/test_stack_trace_config_5.yaml" },
936+ ):
937+ self .options = BaseOptions ()
938+ assert self .options .stack_trace_level == "error"
939+ assert self .options .stack_trace_length == 30 # Default
940+
941+ def test_stack_trace_precedence_env_over_yaml (self ) -> None :
942+ """Test environment variables take precedence over YAML config."""
943+ with patch .dict (
944+ os .environ ,
945+ {
946+ "INSTANA_CONFIG_PATH" : "tests/util/test_stack_trace_config_1.yaml" ,
947+ "INSTANA_STACK_TRACE" : "error" ,
948+ "INSTANA_STACK_TRACE_LENGTH" : "25" ,
949+ },
950+ ):
951+ self .options = BaseOptions ()
952+ # Env vars should override YAML
953+ assert self .options .stack_trace_level == "error"
954+ assert self .options .stack_trace_length == 25
955+
956+ def test_stack_trace_precedence_yaml_over_in_code (self ) -> None :
957+ """Test YAML config takes precedence over in-code config."""
958+ config ["tracing" ] = {
959+ "global" : {
960+ "stack_trace" : "error" ,
961+ "stack_trace_length" : 10
962+ }
963+ }
964+
965+ with patch .dict (
966+ os .environ ,
967+ {"INSTANA_CONFIG_PATH" : "tests/util/test_stack_trace_config_1.yaml" },
968+ ):
969+ self .options = BaseOptions ()
970+ # YAML should override in-code config
971+ assert self .options .stack_trace_level == "all"
972+ assert self .options .stack_trace_length == 15
973+
974+ def test_stack_trace_precedence_yaml_over_agent (self ) -> None :
975+ """Test YAML config takes precedence over agent config."""
976+ with patch .dict (
977+ os .environ ,
978+ {"INSTANA_CONFIG_PATH" : "tests/util/test_stack_trace_config_2.yaml" },
979+ ):
980+ self .options = StandardOptions ()
981+
982+ test_tracing = {
983+ "global" : {
984+ "stack-trace" : "all" ,
985+ "stack-trace-length" : 30
986+ }
987+ }
988+ self .options .set_tracing (test_tracing )
989+
990+ # YAML should override agent config
991+ assert self .options .stack_trace_level == "error"
992+ assert self .options .stack_trace_length == 20
0 commit comments