Skip to content

Commit ba28759

Browse files
committed
Span processors should be added once
1 parent d25e367 commit ba28759

File tree

2 files changed

+62
-36
lines changed

2 files changed

+62
-36
lines changed

opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -233,14 +233,14 @@ def _init_tracing(
233233
set_tracer_provider(provider)
234234

235235
exporter_args_map = exporter_args_map or {}
236-
span_processors = span_processors or []
237236
export_processor = export_span_processor or BatchSpanProcessor
238-
for _, exporter_class in exporters.items():
239-
exporter_args = exporter_args_map.get(exporter_class, {})
240237

241-
for span_processor in span_processors:
242-
provider.add_span_processor(span_processor)
238+
span_processors = span_processors or []
239+
for span_processor in span_processors:
240+
provider.add_span_processor(span_processor)
243241

242+
for _, exporter_class in exporters.items():
243+
exporter_args = exporter_args_map.get(exporter_class, {})
244244
provider.add_span_processor(
245245
export_processor(exporter_class(**exporter_args))
246246
)
@@ -284,15 +284,14 @@ def _init_logging(
284284
set_logger_provider(provider)
285285

286286
exporter_args_map = exporter_args_map or {}
287+
export_processor = export_log_record_processor or BatchLogRecordProcessor
287288

288289
log_record_processors = log_record_processors or []
289-
export_processor = export_log_record_processor or BatchLogRecordProcessor
290+
for log_record_processor in log_record_processors:
291+
provider.add_log_record_processor(log_record_processor)
292+
290293
for _, exporter_class in exporters.items():
291294
exporter_args = exporter_args_map.get(exporter_class, {})
292-
293-
for log_record_processor in log_record_processors:
294-
provider.add_log_record_processor(log_record_processor)
295-
296295
provider.add_log_record_processor(
297296
export_processor(exporter_class(**exporter_args))
298297
)

opentelemetry-sdk/tests/test_configurator.py

Lines changed: 53 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
_initialize_components,
4646
_OTelSDKConfigurator,
4747
)
48-
from opentelemetry.sdk._logs import LoggingHandler
48+
from opentelemetry.sdk._logs import LoggingHandler, LogRecordProcessor
4949
from opentelemetry.sdk._logs._internal.export import LogRecordExporter
5050
from opentelemetry.sdk._logs.export import (
5151
ConsoleLogRecordExporter,
@@ -65,6 +65,7 @@
6565
)
6666
from opentelemetry.sdk.metrics.view import Aggregation
6767
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
68+
from opentelemetry.sdk.trace import SpanProcessor
6869
from opentelemetry.sdk.trace.export import (
6970
ConsoleSpanExporter,
7071
SimpleSpanProcessor,
@@ -88,23 +89,23 @@ class Provider:
8889
def __init__(self, resource=None, sampler=None, id_generator=None):
8990
self.sampler = sampler
9091
self.id_generator = id_generator
91-
self.processor = None
92+
self.processors = []
9293
self.resource = resource or Resource.create({})
9394

9495
def add_span_processor(self, processor):
95-
self.processor = processor
96+
self.processors.append(processor)
9697

9798

9899
class DummyLoggerProvider:
99100
def __init__(self, resource=None):
100101
self.resource = resource
101-
self.processor = DummyLogRecordProcessor(DummyOTLPLogExporter())
102+
self.processors = []
102103

103104
def add_log_record_processor(self, processor):
104-
self.processor = processor
105+
self.processors.append(processor)
105106

106107
def get_logger(self, name, *args, **kwargs):
107-
return DummyLogger(name, self.resource, self.processor)
108+
return DummyLogger(name, self.resource, self.processors)
108109

109110
def force_flush(self, *args, **kwargs):
110111
pass
@@ -115,10 +116,10 @@ class DummyMeterProvider(MeterProvider):
115116

116117

117118
class DummyLogger:
118-
def __init__(self, name, resource, processor):
119+
def __init__(self, name, resource, processors):
119120
self.name = name
120121
self.resource = resource
121-
self.processor = processor
122+
self.processors = processors
122123

123124
def emit(
124125
self,
@@ -133,7 +134,8 @@ def emit(
133134
attributes=None,
134135
event_name=None,
135136
):
136-
self.processor.emit(record)
137+
for processor in self.processors:
138+
processor.emit(record)
137139

138140

139141
class DummyLogRecordProcessor:
@@ -357,10 +359,11 @@ def test_trace_init_default(self):
357359
provider = self.set_provider_mock.call_args[0][0]
358360
self.assertIsInstance(provider, Provider)
359361
self.assertIsInstance(provider.id_generator, RandomIdGenerator)
360-
self.assertIsInstance(provider.processor, Processor)
361-
self.assertIsInstance(provider.processor.exporter, Exporter)
362+
self.assertEqual(len(provider.processors), 1)
363+
self.assertIsInstance(provider.processors[0], Processor)
364+
self.assertIsInstance(provider.processors[0].exporter, Exporter)
362365
self.assertEqual(
363-
provider.processor.exporter.service_name, "my-test-service"
366+
provider.processors[0].exporter.service_name, "my-test-service"
364367
)
365368
self.assertEqual(
366369
provider.resource.attributes.get("telemetry.auto.version"),
@@ -380,8 +383,11 @@ def test_trace_init_otlp(self):
380383
provider = self.set_provider_mock.call_args[0][0]
381384
self.assertIsInstance(provider, Provider)
382385
self.assertIsInstance(provider.id_generator, RandomIdGenerator)
383-
self.assertIsInstance(provider.processor, Processor)
384-
self.assertIsInstance(provider.processor.exporter, OTLPSpanExporter)
386+
self.assertEqual(len(provider.processors), 1)
387+
self.assertIsInstance(provider.processors[0], Processor)
388+
self.assertIsInstance(
389+
provider.processors[0].exporter, OTLPSpanExporter
390+
)
385391
self.assertIsInstance(provider.resource, Resource)
386392
self.assertEqual(
387393
provider.resource.attributes.get("service.name"),
@@ -399,18 +405,25 @@ def test_trace_init_exporter_uses_exporter_args_map(self):
399405
)
400406

401407
provider = self.set_provider_mock.call_args[0][0]
402-
exporter = provider.processor.exporter
408+
self.assertEqual(len(provider.processors), 1)
409+
exporter = provider.processors[0].exporter
403410
self.assertEqual(exporter.compression, "gzip")
404411

405-
def test_trace_init_custom_export_span_processor(self):
412+
def test_trace_init_custom_span_processors(self):
413+
span_processor = mock.Mock(spec=SpanProcessor)
406414
_init_tracing(
407415
{"otlp": OTLPSpanExporter},
408416
id_generator=RandomIdGenerator(),
417+
span_processors=[span_processor],
409418
export_span_processor=SimpleSpanProcessor,
410419
)
411420

412421
provider = self.set_provider_mock.call_args[0][0]
413-
self.assertTrue(isinstance(provider.processor, SimpleSpanProcessor))
422+
self.assertEqual(len(provider.processors), 2)
423+
self.assertEqual(provider.processors[0], span_processor)
424+
self.assertTrue(
425+
isinstance(provider.processors[1], SimpleSpanProcessor)
426+
)
414427

415428
@patch.dict(environ, {OTEL_PYTHON_ID_GENERATOR: "custom_id_generator"})
416429
@patch("opentelemetry.sdk._configuration.IdGenerator", new=IdGenerator)
@@ -700,12 +713,16 @@ def test_logging_init_exporter(self):
700713
provider.resource.attributes.get("service.name"),
701714
"otlp-service",
702715
)
703-
self.assertIsInstance(provider.processor, DummyLogRecordProcessor)
716+
self.assertEqual(len(provider.processors), 1)
717+
self.assertIsInstance(
718+
provider.processors[0], DummyLogRecordProcessor
719+
)
704720
self.assertIsInstance(
705-
provider.processor.exporter, DummyOTLPLogExporter
721+
provider.processors[0].exporter, DummyOTLPLogExporter
706722
)
707723
getLogger(__name__).error("hello")
708-
self.assertTrue(provider.processor.exporter.export_called)
724+
self.assertEqual(len(provider.processors), 1)
725+
self.assertTrue(provider.processors[0].exporter.export_called)
709726

710727
def test_logging_init_exporter_uses_exporter_args_map(self):
711728
with ResetGlobalLoggingState():
@@ -720,18 +737,27 @@ def test_logging_init_exporter_uses_exporter_args_map(self):
720737
)
721738
self.assertEqual(self.set_provider_mock.call_count, 1)
722739
provider = self.set_provider_mock.call_args[0][0]
723-
self.assertEqual(provider.processor.exporter.compression, "gzip")
740+
self.assertEqual(len(provider.processors), 1)
741+
self.assertEqual(
742+
provider.processors[0].exporter.compression, "gzip"
743+
)
724744

725-
def test_logging_init_custom_export_log_record_processor(self):
745+
def test_logging_init_custom_log_record_processors(self):
746+
log_record_processor = mock.Mock(spec=LogRecordProcessor)
726747
with ResetGlobalLoggingState():
727748
resource = Resource.create({})
728749
_init_logging(
729750
{"otlp": DummyOTLPLogExporter},
730751
resource=resource,
752+
log_record_processors=[log_record_processor],
731753
export_log_record_processor=SimpleLogRecordProcessor,
732754
)
733755
provider = self.set_provider_mock.call_args[0][0]
734-
self.assertIsInstance(provider.processor, SimpleLogRecordProcessor)
756+
self.assertEqual(len(provider.processors), 2)
757+
self.assertEqual(provider.processors[0], log_record_processor)
758+
self.assertIsInstance(
759+
provider.processors[1], SimpleLogRecordProcessor
760+
)
735761

736762
@patch.dict(
737763
environ,
@@ -752,12 +778,13 @@ def test_logging_init_exporter_without_handler_setup(self):
752778
provider.resource.attributes.get("service.name"),
753779
"otlp-service",
754780
)
755-
self.assertIsInstance(provider.processor, DummyLogRecordProcessor)
781+
self.assertEqual(len(provider.processors), 1)
782+
self.assertIsInstance(provider.processors[0], DummyLogRecordProcessor)
756783
self.assertIsInstance(
757-
provider.processor.exporter, DummyOTLPLogExporter
784+
provider.processors[0].exporter, DummyOTLPLogExporter
758785
)
759786
getLogger(__name__).error("hello")
760-
self.assertFalse(provider.processor.exporter.export_called)
787+
self.assertFalse(provider.processors[0].exporter.export_called)
761788

762789
@patch.dict(
763790
environ,

0 commit comments

Comments
 (0)