Repository: open-telemetry/opentelemetry-python

Issue:
Make utils private
Right now the `util` module is public and it contains certain public modules that only contain private members.

Make these modules private.


Discussion:

Resolving patch:
diff --git a/opentelemetry-api/src/opentelemetry/util/time.py b/opentelemetry-api/src/opentelemetry/util/_time.py
similarity index 57%
rename from opentelemetry-api/src/opentelemetry/util/time.py
rename to opentelemetry-api/src/opentelemetry/util/_time.py
--- a/opentelemetry-api/src/opentelemetry/util/time.py
+++ b/opentelemetry-api/src/opentelemetry/util/_time.py
@@ -12,16 +12,24 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+from logging import getLogger
 from sys import version_info
 
 if version_info.minor < 7:
+    getLogger(__name__).warning(  # pylint: disable=logging-not-lazy
+        "You are using Python 3.%s. This version does not support timestamps "
+        "with nanosecond precision and the Opentelemetry SDK will use "
+        "millisecond precision instead. Please refer to PEP 546 for more "
+        "information. Please upgrade to Python 3.7 or newer to use nanosecond "
+        "precision." % version_info.minor
+    )
     from time import time
 
-    def time_ns() -> int:
-        # FIXME this approach can have precision problems as explained here:
-        # https://github.com/open-telemetry/opentelemetry-python/issues/1594
+    def _time_ns():
         return int(time() * 1e9)
 
 
 else:
-    from time import time_ns  # pylint: disable=unused-import
+    from time import time_ns
+
+    _time_ns = time_ns
diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py
--- a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py
+++ b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py
@@ -54,7 +54,7 @@
 from opentelemetry.trace.propagation import SPAN_KEY
 from opentelemetry.trace.status import Status, StatusCode
 from opentelemetry.util import types
-from opentelemetry.util.time import time_ns
+from opentelemetry.util._time import _time_ns
 
 logger = logging.getLogger(__name__)
 
@@ -171,9 +171,9 @@ def force_flush(self, timeout_millis: int = 30000) -> bool:
             True if all span processors flushed their spans within the
             given timeout, False otherwise.
         """
-        deadline_ns = time_ns() + timeout_millis * 1000000
+        deadline_ns = _time_ns() + timeout_millis * 1000000
         for sp in self._span_processors:
-            current_time_ns = time_ns()
+            current_time_ns = _time_ns()
             if current_time_ns >= deadline_ns:
                 return False
 
@@ -273,7 +273,7 @@ class EventBase(abc.ABC):
     def __init__(self, name: str, timestamp: Optional[int] = None) -> None:
         self._name = name
         if timestamp is None:
-            self._timestamp = time_ns()
+            self._timestamp = _time_ns()
         else:
             self._timestamp = timestamp
 
@@ -708,7 +708,7 @@ def add_event(
             Event(
                 name=name,
                 attributes=attributes,
-                timestamp=time_ns() if timestamp is None else timestamp,
+                timestamp=_time_ns() if timestamp is None else timestamp,
             )
         )
 
@@ -738,7 +738,7 @@ def start(
                 logger.warning("Calling start() on a started span.")
                 return
             self._start_time = (
-                start_time if start_time is not None else time_ns()
+                start_time if start_time is not None else _time_ns()
             )
 
         self._span_processor.on_start(self, parent_context=parent_context)
@@ -751,7 +751,7 @@ def end(self, end_time: Optional[int] = None) -> 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._end_time = end_time if end_time is not None else _time_ns()
 
         self._span_processor.on_end(self._readable_span())
 
diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/trace/export/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/trace/export/__init__.py
--- a/opentelemetry-sdk/src/opentelemetry/sdk/trace/export/__init__.py
+++ b/opentelemetry-sdk/src/opentelemetry/sdk/trace/export/__init__.py
@@ -29,7 +29,7 @@
     OTEL_BSP_SCHEDULE_DELAY,
 )
 from opentelemetry.sdk.trace import ReadableSpan, Span, SpanProcessor
-from opentelemetry.util.time import time_ns
+from opentelemetry.util._time import _time_ns
 
 logger = logging.getLogger(__name__)
 
@@ -231,9 +231,9 @@ def worker(self):
                         break
 
             # subtract the duration of this export call to the next timeout
-            start = time_ns()
+            start = _time_ns()
             self._export(flush_request)
-            end = time_ns()
+            end = _time_ns()
             duration = (end - start) / 1e9
             timeout = self.schedule_delay_millis / 1e3 - duration
 


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -10,7 +10,7 @@ env:
   # Otherwise, set variable to the commit of your branch on
   # opentelemetry-python-contrib which is compatible with these Core repo
   # changes.
-  CONTRIB_REPO_SHA: 8783e0ff97ad123006ff1ff2c2cf3f52161a406f
+  CONTRIB_REPO_SHA: 5bc0fa1611502be47a1f4eb550fe255e4b707ba1
 
 jobs:
   build:
diff --git a/opentelemetry-sdk/tests/trace/test_trace.py b/opentelemetry-sdk/tests/trace/test_trace.py
--- a/opentelemetry-sdk/tests/trace/test_trace.py
+++ b/opentelemetry-sdk/tests/trace/test_trace.py
@@ -38,7 +38,7 @@
 from opentelemetry.sdk.util import ns_to_iso_str
 from opentelemetry.sdk.util.instrumentation import InstrumentationInfo
 from opentelemetry.trace import StatusCode
-from opentelemetry.util.time import time_ns
+from opentelemetry.util._time import _time_ns
 
 
 def new_tracer() -> trace_api.Tracer:
@@ -709,7 +709,7 @@ def test_events(self):
             )
 
             # event name, attributes and timestamp
-            now = time_ns()
+            now = _time_ns()
             root.add_event("event2", {"name": ["birthday"]}, now)
 
             mutable_list = ["original_contents"]
diff --git a/shim/opentelemetry-opentracing-shim/tests/test_util.py b/shim/opentelemetry-opentracing-shim/tests/test_util.py
--- a/shim/opentelemetry-opentracing-shim/tests/test_util.py
+++ b/shim/opentelemetry-opentracing-shim/tests/test_util.py
@@ -12,41 +12,46 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import time
-import unittest
+from time import time
+from unittest import TestCase
 
-from opentelemetry.shim.opentracing_shim import util
-from opentelemetry.util.time import time_ns
+from opentelemetry.shim.opentracing_shim.util import (
+    DEFAULT_EVENT_NAME,
+    event_name_from_kv,
+    time_seconds_from_ns,
+    time_seconds_to_ns,
+)
+from opentelemetry.util._time import _time_ns
 
 
-class TestUtil(unittest.TestCase):
+class TestUtil(TestCase):
     def test_event_name_from_kv(self):
         # Test basic behavior.
         event_name = "send HTTP request"
-        res = util.event_name_from_kv({"event": event_name, "foo": "bar"})
+        res = event_name_from_kv({"event": event_name, "foo": "bar"})
         self.assertEqual(res, event_name)
 
         # Test None.
-        res = util.event_name_from_kv(None)
-        self.assertEqual(res, util.DEFAULT_EVENT_NAME)
+        res = event_name_from_kv(None)
+        self.assertEqual(res, DEFAULT_EVENT_NAME)
 
         # Test empty dict.
-        res = util.event_name_from_kv({})
-        self.assertEqual(res, util.DEFAULT_EVENT_NAME)
+        res = event_name_from_kv({})
+        self.assertEqual(res, DEFAULT_EVENT_NAME)
 
         # Test missing `event` field.
-        res = util.event_name_from_kv({"foo": "bar"})
-        self.assertEqual(res, util.DEFAULT_EVENT_NAME)
+        res = event_name_from_kv({"foo": "bar"})
+        self.assertEqual(res, DEFAULT_EVENT_NAME)
 
     def test_time_seconds_to_ns(self):
-        time_seconds = time.time()
-        result = util.time_seconds_to_ns(time_seconds)
+        time_seconds = time()
+        result = time_seconds_to_ns(time_seconds)
 
         self.assertEqual(result, int(time_seconds * 1e9))
 
     def test_time_seconds_from_ns(self):
-        time_nanoseconds = time_ns()
-        result = util.time_seconds_from_ns(time_nanoseconds)
+        time_nanoseconds = _time_ns()
+        result = time_seconds_from_ns(time_nanoseconds)
 
         self.assertEqual(result, time_nanoseconds / 1e9)
 
@@ -56,8 +61,8 @@ def test_time_conversion_precision(self):
         """
 
         time_seconds = 1570484241.9501917
-        time_nanoseconds = util.time_seconds_to_ns(time_seconds)
-        result = util.time_seconds_from_ns(time_nanoseconds)
+        time_nanoseconds = time_seconds_to_ns(time_seconds)
+        result = time_seconds_from_ns(time_nanoseconds)
 
         # Tolerate inaccuracies of less than a microsecond.
         # TODO: Put a link to an explanation in the docs.