Repository: open-telemetry/opentelemetry-python

Issue:
Log a warning when replacing the global Tracer/Meter provider
If the global `TracerProvider` or `MeterProvider` is replaced, there is a good chance it was done by accident and can lead to unexpected behavior. This is a good starting point towards addressing #781.

I think this would be a "good first issue" if someone can add the label!


Discussion:

Resolving patch:
diff --git a/opentelemetry-api/src/opentelemetry/metrics/__init__.py b/opentelemetry-api/src/opentelemetry/metrics/__init__.py
--- a/opentelemetry-api/src/opentelemetry/metrics/__init__.py
+++ b/opentelemetry-api/src/opentelemetry/metrics/__init__.py
@@ -460,6 +460,10 @@ def get_meter(
 def set_meter_provider(meter_provider: MeterProvider) -> None:
     """Sets the current global :class:`~.MeterProvider` object."""
     global _METER_PROVIDER  # pylint: disable=global-statement
+
+    if _METER_PROVIDER is not None:
+        logger.warning("Overriding current MeterProvider")
+
     _METER_PROVIDER = meter_provider
 
 
diff --git a/opentelemetry-api/src/opentelemetry/trace/__init__.py b/opentelemetry-api/src/opentelemetry/trace/__init__.py
--- a/opentelemetry-api/src/opentelemetry/trace/__init__.py
+++ b/opentelemetry-api/src/opentelemetry/trace/__init__.py
@@ -463,6 +463,10 @@ def get_tracer(
 def set_tracer_provider(tracer_provider: TracerProvider) -> None:
     """Sets the current global :class:`~.TracerProvider` object."""
     global _TRACER_PROVIDER  # pylint: disable=global-statement
+
+    if _TRACER_PROVIDER is not None:
+        logger.warning("Overriding current TracerProvider")
+
     _TRACER_PROVIDER = tracer_provider
 
 


Test patch:
diff --git a/opentelemetry-api/tests/metrics/test_globals.py b/opentelemetry-api/tests/metrics/test_globals.py
new file mode 100644
--- /dev/null
+++ b/opentelemetry-api/tests/metrics/test_globals.py
@@ -0,0 +1,23 @@
+# type:ignore
+import unittest
+from logging import WARNING
+
+from opentelemetry import metrics
+from opentelemetry.sdk.metrics import MeterProvider
+
+
+class TestGlobals(unittest.TestCase):
+    def test_meter_provider_override_warning(self):
+        """metrics.set_meter_provider should throw a warning when overridden"""
+        metrics.set_meter_provider(MeterProvider())
+        with self.assertLogs(level=WARNING) as test:
+            metrics.set_meter_provider(MeterProvider())
+            self.assertEqual(
+                test.output,
+                [
+                    (
+                        "WARNING:opentelemetry.metrics:Overriding current "
+                        "MeterProvider"
+                    )
+                ],
+            )
diff --git a/opentelemetry-api/tests/trace/test_globals.py b/opentelemetry-api/tests/trace/test_globals.py
--- a/opentelemetry-api/tests/trace/test_globals.py
+++ b/opentelemetry-api/tests/trace/test_globals.py
@@ -1,7 +1,9 @@
 import unittest
+from logging import WARNING
 from unittest.mock import patch
 
 from opentelemetry import context, trace
+from opentelemetry.sdk.trace import TracerProvider  # type:ignore
 
 
 class TestGlobals(unittest.TestCase):
@@ -20,6 +22,21 @@ def test_get_tracer(self):
         trace.get_tracer("foo", "var", mock_provider)
         mock_provider.get_tracer.assert_called_with("foo", "var")
 
+    def test_tracer_provider_override_warning(self):
+        """trace.set_tracer_provider should throw a warning when overridden"""
+        trace.set_tracer_provider(TracerProvider())
+        with self.assertLogs(level=WARNING) as test:
+            trace.set_tracer_provider(TracerProvider())
+            self.assertEqual(
+                test.output,
+                [
+                    (
+                        "WARNING:opentelemetry.trace:Overriding current "
+                        "TracerProvider"
+                    )
+                ],
+            )
+
 
 class TestTracer(unittest.TestCase):
     def setUp(self):