1818import json
1919import threading
2020import time
21- from queue import Queue
22- from typing import TYPE_CHECKING , Deque
21+ from typing import TYPE_CHECKING
2322
2423from google .protobuf import json_format
2524from opentelemetry ._logs .severity import SeverityNumber
2928from opentelemetry .sdk .trace import ReadableSpan , Span , SpanProcessor
3029from opentelemetry .trace import TraceFlags
3130
31+ from partial_span_processor .peekable_queue import PeekableQueue
32+
3233if TYPE_CHECKING :
3334 from opentelemetry import context as context_api
3435 from opentelemetry .sdk ._logs .export import LogExporter
@@ -79,10 +80,11 @@ def __init__(
7980 self .resource = resource
8081
8182 self .active_spans = {}
82- self .delayed_heartbeat_spans : Deque [tuple [int , datetime .datetime ]] = Deque [
83- tuple [ int , datetime . datetime ]] ()
83+ self .delayed_heartbeat_spans : PeekableQueue [tuple [int , datetime .datetime ]] = \
84+ PeekableQueue ()
8485 self .delayed_heartbeat_spans_lookup : set [int ] = set ()
85- self .ready_heartbeat_spans : Queue [tuple [int , datetime .datetime ]] = Queue ()
86+ self .ready_heartbeat_spans : PeekableQueue [
87+ tuple [int , datetime .datetime ]] = PeekableQueue ()
8688 self .lock = threading .Lock ()
8789
8890 self .done = False
@@ -110,18 +112,20 @@ def on_start(self, span: Span,
110112
111113 next_heartbeat_time = datetime .datetime .now () + datetime .timedelta (
112114 milliseconds = self .initial_heartbeat_delay_millis )
113- self .delayed_heartbeat_spans .appendleft (
115+ self .delayed_heartbeat_spans .put (
114116 (span .context .span_id , next_heartbeat_time ))
115117
116118 def on_end (self , span : ReadableSpan ) -> None :
119+ is_delayed_heartbeat_pending = False
117120 with self .lock :
118121 self .active_spans .pop (span .context .span_id )
119122
120123 if span .context .span_id in self .delayed_heartbeat_spans_lookup :
124+ is_delayed_heartbeat_pending = True
121125 self .delayed_heartbeat_spans_lookup .remove (span .context .span_id )
122- self . delayed_heartbeat_spans . remove (
123- ( span . context . span_id , next ( iter ( self . delayed_heartbeat_spans ))[ 1 ]))
124- return
126+
127+ if is_delayed_heartbeat_pending :
128+ return
125129
126130 self .export_log (span , get_stop_attributes ())
127131
@@ -188,28 +192,42 @@ def get_log_data(self, span: Span, attributes: dict[str, str]) -> LogData:
188192 )
189193
190194 def process_delayed_heartbeat_spans (self ) -> None :
191- with self .lock :
195+ spans_to_be_logged = []
196+ with (self .lock ):
192197 now = datetime .datetime .now ()
193- while self .delayed_heartbeat_spans and self .delayed_heartbeat_spans [- 1 ][
194- 1 ] <= now :
195- span_id , _ = self .delayed_heartbeat_spans .pop ()
198+ while True :
199+ if self .delayed_heartbeat_spans .empty ():
200+ break
201+
202+ (span_id , next_heartbeat_time ) = self .delayed_heartbeat_spans .peek ()
203+ if next_heartbeat_time > now :
204+ break
205+
196206 self .delayed_heartbeat_spans_lookup .discard (span_id )
207+ self .delayed_heartbeat_spans .get ()
197208
198209 span = self .active_spans .get (span_id )
199210 if not span :
200211 continue
201212
202- self . export_log (span , self . get_heartbeat_attributes () )
213+ spans_to_be_logged . append (span )
203214
204215 next_heartbeat_time = now + datetime .timedelta (
205216 milliseconds = self .heartbeat_interval_millis )
206217 self .ready_heartbeat_spans .put ((span_id , next_heartbeat_time ))
207218
219+ for span in spans_to_be_logged :
220+ self .export_log (span , self .get_heartbeat_attributes ())
221+
208222 def process_ready_heartbeat_spans (self ) -> None :
223+ spans_to_be_logged = []
209224 now = datetime .datetime .now ()
210225 with self .lock :
211- while not self .ready_heartbeat_spans .empty ():
212- span_id , next_heartbeat_time = self .ready_heartbeat_spans .queue [0 ]
226+ while True :
227+ if self .ready_heartbeat_spans .empty ():
228+ break
229+
230+ (span_id , next_heartbeat_time ) = self .ready_heartbeat_spans .peek ()
213231 if next_heartbeat_time > now :
214232 break
215233
@@ -219,12 +237,15 @@ def process_ready_heartbeat_spans(self) -> None:
219237 if not span :
220238 continue
221239
222- self . export_log (span , self . get_heartbeat_attributes () )
240+ spans_to_be_logged . append (span )
223241
224242 next_heartbeat_time = now + datetime .timedelta (
225243 milliseconds = self .heartbeat_interval_millis )
226244 self .ready_heartbeat_spans .put ((span_id , next_heartbeat_time ))
227245
246+ for span in spans_to_be_logged :
247+ self .export_log (span , self .get_heartbeat_attributes ())
248+
228249
229250def get_stop_attributes () -> dict [str , str ]:
230251 return {
0 commit comments