diff --git a/opentracing-shim/src/opentracingshim/__init__.py b/opentracing-shim/src/opentracingshim/__init__.py index 7c5066f44d1..c0f59de937a 100644 --- a/opentracing-shim/src/opentracingshim/__init__.py +++ b/opentracing-shim/src/opentracingshim/__init__.py @@ -61,12 +61,11 @@ def set_operation_name(self, operation_name): self._otel_span.update_name(operation_name) return self - def finish(self, finish_time=None): - self._otel_span.end() - # TODO: Handle finish_time. The OpenTelemetry API doesn't currently - # support setting end time on a span and we cannot assume that all - # OpenTelemetry Tracer implementations have an `end_time` field. - # https://github.com/open-telemetry/opentelemetry-python/issues/134 + def finish(self, finish_time: float = None): + end_time = finish_time + if end_time is not None: + end_time = util.time_seconds_to_ns(finish_time) + self._otel_span.end(end_time=end_time) def set_tag(self, key, value): self._otel_span.set_attribute(key, value) @@ -233,7 +232,14 @@ def start_span( for key, value in tags.items(): span.set_attribute(key, value) - span.start(start_time=start_time) + # The OpenTracing API expects time values to be `float` values which + # represent the number of seconds since the epoch. OpenTelemetry + # represents time values as nanoseconds since the epoch. + start_time_ns = start_time + if start_time_ns is not None: + start_time_ns = util.time_seconds_to_ns(start_time) + + span.start(start_time=start_time_ns) context = SpanContextWrapper(span.get_context()) return SpanWrapper(self, context, span) diff --git a/opentracing-shim/src/opentracingshim/util.py b/opentracing-shim/src/opentracingshim/util.py index 48a1a108c45..6f7b80fe020 100644 --- a/opentracing-shim/src/opentracingshim/util.py +++ b/opentracing-shim/src/opentracingshim/util.py @@ -28,6 +28,32 @@ def time_ns(): DEFAULT_EVENT_NAME = "log" +def time_seconds_to_ns(time_seconds: float) -> int: + """Converts a time value in seconds to a time value in nanoseconds. + + `time_seconds` is a `float` as returned by `time.time()` which represents + the number of seconds since the epoch. + + The returned value is an `int` representing the number of nanoseconds since + the epoch. + """ + + return int(time_seconds * 1e9) + + +def time_seconds_from_ns(time_nanoseconds: int) -> float: + """Converts a time value in nanoseconds to a time value in seconds. + + `time_nanoseconds` is an `int` representing the number of nanoseconds since + the epoch. + + The returned value is a `float` representing the number of seconds since + the epoch. + """ + + return time_nanoseconds / 1e9 + + def event_name_from_kv(key_values: dict) -> str: """A helper function which returns an event name from the given dict, or a default event name. diff --git a/opentracing-shim/tests/test_shim.py b/opentracing-shim/tests/test_shim.py index 2e2a71c8e7c..c9a9c06a720 100644 --- a/opentracing-shim/tests/test_shim.py +++ b/opentracing-shim/tests/test_shim.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import time import unittest import opentracing @@ -19,6 +20,7 @@ import opentracingshim from opentelemetry import trace from opentelemetry.sdk.trace import Tracer +from opentracingshim import util class TestShim(unittest.TestCase): @@ -112,9 +114,20 @@ def test_explicit_span_finish(self): def test_explicit_start_time(self): """Test `start_time` argument.""" - now = opentracingshim.util.time_ns() + now = time.time() with self.shim.start_active_span("TestSpan", start_time=now) as scope: - self.assertEqual(scope.span.unwrap().start_time, now) + result = util.time_seconds_from_ns(scope.span.unwrap().start_time) + self.assertEqual(result, now) + + def test_explicit_end_time(self): + """Test `end_time` argument of `finish()` method.""" + + span = self.shim.start_span("TestSpan") + now = time.time() + span.finish(now) + + end_time = util.time_seconds_from_ns(span.unwrap().end_time) + self.assertEqual(end_time, now) def test_explicit_span_activation(self): """Test manual activation and deactivation of a span.""" diff --git a/opentracing-shim/tests/test_util.py b/opentracing-shim/tests/test_util.py index 3b2dabcc89f..99e0b61ddce 100644 --- a/opentracing-shim/tests/test_util.py +++ b/opentracing-shim/tests/test_util.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import time import unittest from opentracingshim import util @@ -35,3 +36,15 @@ def test_event_name_from_kv(self): # Test missing `event` field. res = util.event_name_from_kv({"foo": "bar"}) self.assertEqual(res, util.DEFAULT_EVENT_NAME) + + def test_time_seconds_to_ns(self): + time_seconds = time.time() + result = util.time_seconds_to_ns(time_seconds) + + self.assertEqual(result, int(time_seconds * 1e9)) + + def test_time_seconds_from_ns(self): + time_nanoseconds = util.time_ns() + result = util.time_seconds_from_ns(time_nanoseconds) + + self.assertEqual(result, time_nanoseconds / 1e9)