12
12
# See the License for the specific language governing permissions and
13
13
# limitations under the License.
14
14
15
+ import time
15
16
import unittest
17
+ from unittest import mock
16
18
19
+ from opentelemetry import trace as trace_api
17
20
from opentelemetry .sdk import trace
18
21
from opentelemetry .sdk .trace import export
19
22
20
23
21
- class TestSimpleExportSpanProcessor (unittest .TestCase ):
22
- def test_simple_span_processor (self ):
23
- class MySpanExporter (export .SpanExporter ):
24
- def __init__ (self , destination ):
25
- self .destination = destination
24
+ class MySpanExporter (export .SpanExporter ):
25
+ """Very simple span exporter used for testing."""
26
+
27
+ def __init__ (self , destination , max_export_batch_size = None ):
28
+ self .destination = destination
29
+ self .max_export_batch_size = max_export_batch_size
26
30
27
- def export (self , spans : trace .Span ) -> export .SpanExportResult :
28
- self .destination .extend (span .name for span in spans )
29
- return export .SpanExportResult .SUCCESS
31
+ def export (self , spans : trace .Span ) -> export .SpanExportResult :
32
+ if (
33
+ self .max_export_batch_size is not None
34
+ and len (spans ) > self .max_export_batch_size
35
+ ):
36
+ raise ValueError ("Batch is too big" )
37
+ self .destination .extend (span .name for span in spans )
38
+ return export .SpanExportResult .SUCCESS
30
39
40
+
41
+ class TestSimpleExportSpanProcessor (unittest .TestCase ):
42
+ def test_simple_span_processor (self ):
31
43
tracer = trace .Tracer ()
32
44
33
45
spans_names_list = []
@@ -42,3 +54,142 @@ def export(self, spans: trace.Span) -> export.SpanExportResult:
42
54
pass
43
55
44
56
self .assertListEqual (["xxx" , "bar" , "foo" ], spans_names_list )
57
+
58
+
59
+ def _create_start_and_end_span (name , span_processor ):
60
+ span = trace .Span (
61
+ name ,
62
+ mock .Mock (spec = trace_api .SpanContext ),
63
+ span_processor = span_processor ,
64
+ )
65
+ span .start ()
66
+ span .end ()
67
+
68
+
69
+ class TestBatchExportSpanProcessor (unittest .TestCase ):
70
+ def test_batch_span_processor (self ):
71
+ spans_names_list = []
72
+
73
+ my_exporter = MySpanExporter (destination = spans_names_list )
74
+ span_processor = export .BatchExportSpanProcessor (my_exporter )
75
+
76
+ span_names = ["xxx" , "bar" , "foo" ]
77
+
78
+ for name in span_names :
79
+ _create_start_and_end_span (name , span_processor )
80
+
81
+ span_processor .shutdown ()
82
+ self .assertListEqual (span_names , spans_names_list )
83
+
84
+ def test_batch_span_processor_lossless (self ):
85
+ """Test that no spans are lost when sending max_queue_size spans"""
86
+ spans_names_list = []
87
+
88
+ my_exporter = MySpanExporter (
89
+ destination = spans_names_list , max_export_batch_size = 128
90
+ )
91
+ span_processor = export .BatchExportSpanProcessor (
92
+ my_exporter , max_queue_size = 512 , max_export_batch_size = 128
93
+ )
94
+
95
+ for _ in range (512 ):
96
+ _create_start_and_end_span ("foo" , span_processor )
97
+
98
+ span_processor .shutdown ()
99
+ self .assertEqual (len (spans_names_list ), 512 )
100
+
101
+ def test_batch_span_processor_many_spans (self ):
102
+ """Test that no spans are lost when sending many spans"""
103
+ spans_names_list = []
104
+
105
+ my_exporter = MySpanExporter (
106
+ destination = spans_names_list , max_export_batch_size = 128
107
+ )
108
+ span_processor = export .BatchExportSpanProcessor (
109
+ my_exporter ,
110
+ max_queue_size = 256 ,
111
+ max_export_batch_size = 64 ,
112
+ schedule_delay_millis = 100 ,
113
+ )
114
+
115
+ for _ in range (4 ):
116
+ for _ in range (256 ):
117
+ _create_start_and_end_span ("foo" , span_processor )
118
+
119
+ time .sleep (0.05 ) # give some time for the exporter to upload spans
120
+
121
+ span_processor .shutdown ()
122
+ self .assertEqual (len (spans_names_list ), 1024 )
123
+
124
+ def test_batch_span_processor_scheduled_delay (self ):
125
+ """Test that spans are exported each schedule_delay_millis"""
126
+ spans_names_list = []
127
+
128
+ my_exporter = MySpanExporter (destination = spans_names_list )
129
+ span_processor = export .BatchExportSpanProcessor (
130
+ my_exporter , schedule_delay_millis = 50
131
+ )
132
+
133
+ # create single span
134
+ _create_start_and_end_span ("foo" , span_processor )
135
+
136
+ time .sleep (0.05 + 0.02 )
137
+ # span should be already exported
138
+ self .assertEqual (len (spans_names_list ), 1 )
139
+
140
+ span_processor .shutdown ()
141
+
142
+ def test_batch_span_processor_parameters (self ):
143
+ # zero max_queue_size
144
+ self .assertRaises (
145
+ ValueError , export .BatchExportSpanProcessor , None , max_queue_size = 0
146
+ )
147
+
148
+ # negative max_queue_size
149
+ self .assertRaises (
150
+ ValueError ,
151
+ export .BatchExportSpanProcessor ,
152
+ None ,
153
+ max_queue_size = - 500 ,
154
+ )
155
+
156
+ # zero schedule_delay_millis
157
+ self .assertRaises (
158
+ ValueError ,
159
+ export .BatchExportSpanProcessor ,
160
+ None ,
161
+ schedule_delay_millis = 0 ,
162
+ )
163
+
164
+ # negative schedule_delay_millis
165
+ self .assertRaises (
166
+ ValueError ,
167
+ export .BatchExportSpanProcessor ,
168
+ None ,
169
+ schedule_delay_millis = - 500 ,
170
+ )
171
+
172
+ # zero max_export_batch_size
173
+ self .assertRaises (
174
+ ValueError ,
175
+ export .BatchExportSpanProcessor ,
176
+ None ,
177
+ max_export_batch_size = 0 ,
178
+ )
179
+
180
+ # negative max_export_batch_size
181
+ self .assertRaises (
182
+ ValueError ,
183
+ export .BatchExportSpanProcessor ,
184
+ None ,
185
+ max_export_batch_size = - 500 ,
186
+ )
187
+
188
+ # max_export_batch_size > max_queue_size:
189
+ self .assertRaises (
190
+ ValueError ,
191
+ export .BatchExportSpanProcessor ,
192
+ None ,
193
+ max_queue_size = 256 ,
194
+ max_export_batch_size = 512 ,
195
+ )
0 commit comments