|
8 | 8 | from amazon.opentelemetry.distro.code_correlation.code_attributes_span_processor import CodeAttributesSpanProcessor |
9 | 9 | from opentelemetry.context import Context |
10 | 10 | from opentelemetry.sdk.trace import ReadableSpan, Span |
| 11 | +from opentelemetry.sdk.util.instrumentation import InstrumentationScope |
11 | 12 | from opentelemetry.semconv.attributes.code_attributes import CODE_FUNCTION_NAME |
12 | 13 | from opentelemetry.trace import SpanKind |
13 | 14 |
|
@@ -82,57 +83,85 @@ def test_max_stack_frames_constant(self): |
82 | 83 | """Test that MAX_STACK_FRAMES is set to expected value.""" |
83 | 84 | self.assertEqual(CodeAttributesSpanProcessor.MAX_STACK_FRAMES, 50) |
84 | 85 |
|
85 | | - def create_mock_span(self, span_kind=SpanKind.CLIENT, attributes=None): |
| 86 | + def create_mock_span(self, span_kind=SpanKind.CLIENT, attributes=None, instrumentation_scope_name=None): |
86 | 87 | """Helper to create a mock span with specified properties.""" |
87 | 88 | mock_span = MagicMock(spec=Span) |
88 | 89 | mock_span.kind = span_kind |
89 | 90 | mock_span.attributes = attributes |
| 91 | + |
| 92 | + # Set up instrumentation scope |
| 93 | + if instrumentation_scope_name is not None: |
| 94 | + mock_scope = MagicMock(spec=InstrumentationScope) |
| 95 | + mock_scope.name = instrumentation_scope_name |
| 96 | + mock_span.instrumentation_scope = mock_scope |
| 97 | + else: |
| 98 | + mock_span.instrumentation_scope = None |
| 99 | + |
90 | 100 | return mock_span |
91 | 101 |
|
92 | | - def test_should_process_span_client_span_without_attributes(self): |
93 | | - """Test that CLIENT spans without code attributes should be processed.""" |
94 | | - span = self.create_mock_span(SpanKind.CLIENT, attributes=None) |
95 | | - result = CodeAttributesSpanProcessor._should_process_span(span) |
| 102 | + def test_should_process_span_user_client_span_without_attributes(self): |
| 103 | + """Test that user CLIENT spans without code attributes should be processed.""" |
| 104 | + span = self.create_mock_span(SpanKind.CLIENT, attributes=None, instrumentation_scope_name="my-app") |
| 105 | + result = self.processor._should_process_span(span) |
96 | 106 | self.assertTrue(result) |
97 | 107 |
|
98 | | - def test_should_process_span_client_span_with_empty_attributes(self): |
99 | | - """Test that CLIENT spans with empty attributes should be processed.""" |
100 | | - span = self.create_mock_span(SpanKind.CLIENT, attributes={}) |
101 | | - result = CodeAttributesSpanProcessor._should_process_span(span) |
| 108 | + def test_should_process_span_user_client_span_with_empty_attributes(self): |
| 109 | + """Test that user CLIENT spans with empty attributes should be processed.""" |
| 110 | + span = self.create_mock_span(SpanKind.CLIENT, attributes={}, instrumentation_scope_name="my-app") |
| 111 | + result = self.processor._should_process_span(span) |
102 | 112 | self.assertTrue(result) |
103 | 113 |
|
104 | 114 | def test_should_process_span_client_span_with_existing_code_attributes(self): |
105 | | - """Test that CLIENT spans with existing code attributes should not be processed.""" |
| 115 | + """Test that spans with existing code attributes should not be processed.""" |
106 | 116 | attributes = {CODE_FUNCTION_NAME: "existing.function"} |
107 | | - span = self.create_mock_span(SpanKind.CLIENT, attributes=attributes) |
108 | | - result = CodeAttributesSpanProcessor._should_process_span(span) |
| 117 | + span = self.create_mock_span(SpanKind.CLIENT, attributes=attributes, instrumentation_scope_name="my-app") |
| 118 | + result = self.processor._should_process_span(span) |
109 | 119 | self.assertFalse(result) |
110 | 120 |
|
111 | | - def test_should_process_span_server_and_internal_spans(self): |
112 | | - """Test that SERVER and INTERNAL spans should not be processed.""" |
113 | | - test_cases = [ |
114 | | - SpanKind.SERVER, |
115 | | - SpanKind.INTERNAL, |
116 | | - ] |
| 121 | + def test_should_process_span_user_server_spans(self): |
| 122 | + """Test that user SERVER spans should be processed (new logic).""" |
| 123 | + span = self.create_mock_span(SpanKind.SERVER, attributes=None, instrumentation_scope_name="my-app") |
| 124 | + result = self.processor._should_process_span(span) |
| 125 | + self.assertTrue(result) |
117 | 126 |
|
118 | | - for span_kind in test_cases: |
119 | | - with self.subTest(span_kind=span_kind): |
120 | | - span = self.create_mock_span(span_kind, attributes=None) |
121 | | - result = CodeAttributesSpanProcessor._should_process_span(span) |
122 | | - self.assertFalse(result) |
| 127 | + def test_should_process_span_library_server_spans_not_processed(self): |
| 128 | + """Test that library instrumentation SERVER spans should not be processed.""" |
| 129 | + span = self.create_mock_span( |
| 130 | + SpanKind.SERVER, attributes=None, instrumentation_scope_name="opentelemetry.instrumentation.flask" |
| 131 | + ) |
| 132 | + result = self.processor._should_process_span(span) |
| 133 | + self.assertFalse(result) |
123 | 134 |
|
124 | | - def test_should_process_span_client_producer_consumer_spans(self): |
125 | | - """Test that CLIENT, PRODUCER, and CONSUMER spans should be processed.""" |
| 135 | + def test_should_process_span_library_internal_spans_not_processed(self): |
| 136 | + """Test that library instrumentation INTERNAL spans should not be processed.""" |
| 137 | + span = self.create_mock_span( |
| 138 | + SpanKind.INTERNAL, attributes=None, instrumentation_scope_name="opentelemetry.instrumentation.botocore" |
| 139 | + ) |
| 140 | + result = self.processor._should_process_span(span) |
| 141 | + self.assertFalse(result) |
| 142 | + |
| 143 | + def test_should_process_span_library_client_spans_processed(self): |
| 144 | + """Test that library instrumentation CLIENT spans should be processed.""" |
| 145 | + span = self.create_mock_span( |
| 146 | + SpanKind.CLIENT, attributes=None, instrumentation_scope_name="opentelemetry.instrumentation.requests" |
| 147 | + ) |
| 148 | + result = self.processor._should_process_span(span) |
| 149 | + self.assertTrue(result) |
| 150 | + |
| 151 | + def test_should_process_span_user_spans_all_kinds(self): |
| 152 | + """Test that user spans of all kinds should be processed.""" |
126 | 153 | test_cases = [ |
127 | 154 | SpanKind.CLIENT, |
| 155 | + SpanKind.SERVER, |
128 | 156 | SpanKind.PRODUCER, |
129 | 157 | SpanKind.CONSUMER, |
| 158 | + SpanKind.INTERNAL, |
130 | 159 | ] |
131 | 160 |
|
132 | 161 | for span_kind in test_cases: |
133 | 162 | with self.subTest(span_kind=span_kind): |
134 | | - span = self.create_mock_span(span_kind, attributes=None) |
135 | | - result = CodeAttributesSpanProcessor._should_process_span(span) |
| 163 | + span = self.create_mock_span(span_kind, attributes=None, instrumentation_scope_name="my-app") |
| 164 | + result = self.processor._should_process_span(span) |
136 | 165 | self.assertTrue(result) |
137 | 166 |
|
138 | 167 | @patch("amazon.opentelemetry.distro.code_correlation.code_attributes_span_processor.sys._getframe") |
@@ -300,7 +329,8 @@ def is_user_code_side_effect(filename): |
300 | 329 |
|
301 | 330 | def test_on_start_should_not_process_span(self): |
302 | 331 | """Test on_start when span should not be processed.""" |
303 | | - span = self.create_mock_span(SpanKind.SERVER) # Non-client span |
| 332 | + # Library instrumentation SERVER span should not be processed |
| 333 | + span = self.create_mock_span(SpanKind.SERVER, instrumentation_scope_name="opentelemetry.instrumentation.flask") |
304 | 334 |
|
305 | 335 | with patch.object(self.processor, "_capture_code_attributes") as mock_capture: |
306 | 336 | self.processor.on_start(span) |
|
0 commit comments