diff --git a/opentelemetry-api/src/opentelemetry/trace/__init__.py b/opentelemetry-api/src/opentelemetry/trace/__init__.py index b79cdeb4df5..55cdc567d5d 100644 --- a/opentelemetry-api/src/opentelemetry/trace/__init__.py +++ b/opentelemetry-api/src/opentelemetry/trace/__init__.py @@ -142,7 +142,7 @@ class SpanKind(enum.Enum): class Span: """A span represents a single operation within a trace.""" - def start(self) -> None: + def start(self, start_time: int = None) -> None: """Sets the current time as the span's start time. Each span represents a single operation. The span's start time is the @@ -152,7 +152,7 @@ def start(self) -> None: implementations are free to ignore or raise on further calls. """ - def end(self) -> None: + def end(self, end_time: int = None) -> None: """Sets the current time as the span's end time. The span's end time is the wall time at which the operation finished. diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py index a694476e1fe..37294ee05f7 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py @@ -340,19 +340,21 @@ def add_lazy_link(self, link: "trace_api.Link") -> None: return self.links.append(link) - def start(self): + def start(self, start_time: int = None): with self._lock: if not self.is_recording_events(): return has_started = self.start_time is not None if not has_started: - self.start_time = util.time_ns() + self.start_time = ( + start_time if start_time is not None else util.time_ns() + ) if has_started: logger.warning("Calling start() on a started span.") return self.span_processor.on_start(self) - def end(self): + def end(self, end_time: int = None): with self._lock: if not self.is_recording_events(): return @@ -360,7 +362,9 @@ def end(self): raise RuntimeError("Calling end() on a not started span.") has_ended = self.end_time is not None if not has_ended: - self.end_time = util.time_ns() + self.end_time = ( + end_time if end_time is not None else util.time_ns() + ) if has_ended: logger.warning("Calling end() on an ended span.") return diff --git a/opentelemetry-sdk/tests/trace/test_trace.py b/opentelemetry-sdk/tests/trace/test_trace.py index 0570affc411..378534453c2 100644 --- a/opentelemetry-sdk/tests/trace/test_trace.py +++ b/opentelemetry-sdk/tests/trace/test_trace.py @@ -234,6 +234,16 @@ def test_start_span(self): span.start() self.assertEqual(start_time, span.start_time) + def test_span_override_start_and_end_time(self): + """Span sending custom start_time and end_time values""" + span = trace.Span("name", mock.Mock(spec=trace_api.SpanContext)) + start_time = 123 + span.start(start_time) + self.assertEqual(start_time, span.start_time) + end_time = 456 + span.end(end_time) + self.assertEqual(end_time, span.end_time) + def test_ended_span(self): """"Events, attributes are not allowed after span is ended""" tracer = trace.Tracer("test_ended_span")