def worker(self): timeout = self.schedule_delay_millis / 1e3 flush_request = None # type: typing.Optional[_FlushRequest] while not self.done: with self.condition: if self.done: # done flag may have changed, avoid waiting break flush_request = self._get_and_unset_flush_request() if (len(self.queue) < self.max_export_batch_size and flush_request is None): self.condition.wait(timeout) flush_request = self._get_and_unset_flush_request() if not self.queue: # spurious notification, let's wait again, reset timeout timeout = self.schedule_delay_millis / 1e3 self._notify_flush_request_finished(flush_request) flush_request = None continue if self.done: # missing spans will be sent when calling flush break # subtract the duration of this export call to the next timeout start = time_ns() self._export(flush_request) end = time_ns() duration = (end - start) / 1e9 timeout = self.schedule_delay_millis / 1e3 - duration self._notify_flush_request_finished(flush_request) flush_request = None # there might have been a new flush request while export was running # and before the done flag switched to true with self.condition: shutdown_flush_request = self._get_and_unset_flush_request() # be sure that all spans are sent self._drain_queue() self._notify_flush_request_finished(flush_request) self._notify_flush_request_finished(shutdown_flush_request)
def end(self, end_time: Optional[int] = None) -> None: with self._lock: if self._start_time is None: raise RuntimeError("Calling end() on a not started span.") if self._end_time is not None: logger.warning("Calling end() on an ended span.") return self._end_time = end_time if end_time is not None else time_ns() self._span_processor.on_end(self._readable_span())
def start( self, start_time: Optional[int] = None, parent_context: Optional[context_api.Context] = None, ) -> None: with self._lock: if self._start_time is not None: logger.warning("Calling start() on a started span.") return self._start_time = ( start_time if start_time is not None else time_ns() ) self._span_processor.on_start(self, parent_context=parent_context)
def add_event( self, name: str, attributes: types.Attributes = None, timestamp: Optional[int] = None, ) -> None: _filter_attribute_values(attributes) attributes = _create_immutable_attributes(attributes) self._add_event( Event( name=name, attributes=attributes, timestamp=time_ns() if timestamp is None else timestamp, ) )
def force_flush(self, timeout_millis: int = 30000) -> bool: """Sequentially calls force_flush on all underlying :class:`SpanProcessor` Args: timeout_millis: The maximum amount of time over all span processors to wait for spans to be exported. In case the first n span processors exceeded the timeout followup span processors will be skipped. Returns: True if all span processors flushed their spans within the given timeout, False otherwise. """ deadline_ns = time_ns() + timeout_millis * 1000000 for sp in self._span_processors: current_time_ns = time_ns() if current_time_ns >= deadline_ns: return False if not sp.force_flush((deadline_ns - current_time_ns) // 1000000): return False return True
def test_events(self): self.assertEqual(trace_api.get_current_span(), trace_api.INVALID_SPAN) with self.tracer.start_as_current_span("root") as root: # only event name root.add_event("event0") # event name and attributes root.add_event("event1", { "name": "pluto", "some_bools": [True, False] }) # event name, attributes and timestamp now = time_ns() root.add_event("event2", {"name": ["birthday"]}, now) mutable_list = ["original_contents"] root.add_event("event3", {"name": mutable_list}) self.assertEqual(len(root.events), 4) self.assertEqual(root.events[0].name, "event0") self.assertEqual(root.events[0].attributes, {}) self.assertEqual(root.events[1].name, "event1") self.assertEqual( root.events[1].attributes, { "name": "pluto", "some_bools": (True, False) }, ) self.assertEqual(root.events[2].name, "event2") self.assertEqual(root.events[2].attributes, {"name": ("birthday", )}) self.assertEqual(root.events[2].timestamp, now) self.assertEqual(root.events[3].name, "event3") self.assertEqual(root.events[3].attributes, {"name": ("original_contents", )}) mutable_list = ["new_contents"] self.assertEqual(root.events[3].attributes, {"name": ("original_contents", )})
def __init__(self, name: str, timestamp: Optional[int] = None) -> None: self._name = name if timestamp is None: self._timestamp = time_ns() else: self._timestamp = timestamp
def test_time_seconds_from_ns(self): time_nanoseconds = time_ns() result = util.time_seconds_from_ns(time_nanoseconds) self.assertEqual(result, time_nanoseconds / 1e9)