Skip to content

Commit

Permalink
Adds support OTEL_SDK_DISABLED environment variable (#3648)
Browse files Browse the repository at this point in the history
* Adds support OTEL_SDK_DISABLED environment variable

* Pass schema_url and version to NoOpMeter and NoOpLogger, implement comments from review

* Add CHANGELOG entry

* Fix lint error

* Suppress lint errors due to returning a NoOpTracer when SDK is disabled

---------

Co-authored-by: Leighton Chen <lechen@microsoft.com>
Co-authored-by: Diego Hurtado <ocelotl@users.noreply.github.com>
  • Loading branch information
3 people committed Mar 20, 2024
1 parent 6dd85fc commit 2574707
Show file tree
Hide file tree
Showing 8 changed files with 54 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#3751](https://github.com/open-telemetry/opentelemetry-python/pull/3751))
- bump mypy to 0.982
([#3776](https://github.com/open-telemetry/opentelemetry-python/pull/3776))
- Add support for OTEL_SDK_DISABLED environment variable
([#3648](https://github.com/open-telemetry/opentelemetry-python/pull/3648))
- Fix ValueError message for PeriodicExportingMetricsReader
([#3769](https://github.com/open-telemetry/opentelemetry-python/pull/3769))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
from opentelemetry.sdk.environment_variables import (
OTEL_ATTRIBUTE_COUNT_LIMIT,
OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT,
OTEL_SDK_DISABLED,
)
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.util import ns_to_iso_str
Expand Down Expand Up @@ -607,6 +608,8 @@ def __init__(
self._multi_log_record_processor = (
multi_log_record_processor or SynchronousMultiLogRecordProcessor()
)
disabled = environ.get(OTEL_SDK_DISABLED, "")
self._disabled = disabled.lower().strip() == "true"
self._at_exit_handler = None
if shutdown_on_exit:
self._at_exit_handler = atexit.register(self.shutdown)
Expand All @@ -621,6 +624,9 @@ def get_logger(
version: Optional[str] = None,
schema_url: Optional[str] = None,
) -> Logger:
if self._disabled:
_logger.warning("SDK is disabled.")
return NoOpLogger(name, version=version, schema_url=schema_url)
return Logger(
self._resource,
self._multi_log_record_processor,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.

OTEL_SDK_DISABLED = "OTEL_SDK_DISABLED"
"""
.. envvar:: OTEL_SDK_DISABLED
The :envvar:`OTEL_SDK_DISABLED` environment variable disables the SDK for all signals
Default: "false"
"""

OTEL_RESOURCE_ATTRIBUTES = "OTEL_RESOURCE_ATTRIBUTES"
"""
.. envvar:: OTEL_RESOURCE_ATTRIBUTES
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

from atexit import register, unregister
from logging import getLogger
from os import environ
from threading import Lock
from time import time_ns
from typing import Optional, Sequence
Expand All @@ -32,6 +33,7 @@
)
from opentelemetry.metrics import UpDownCounter as APIUpDownCounter
from opentelemetry.metrics import _Gauge as APIGauge
from opentelemetry.sdk.environment_variables import OTEL_SDK_DISABLED
from opentelemetry.sdk.metrics._internal.exceptions import MetricsTimeoutError
from opentelemetry.sdk.metrics._internal.instrument import (
_Counter,
Expand Down Expand Up @@ -394,6 +396,8 @@ def __init__(
self._measurement_consumer = SynchronousMeasurementConsumer(
sdk_config=self._sdk_config
)
disabled = environ.get(OTEL_SDK_DISABLED, "")
self._disabled = disabled.lower().strip() == "true"

if shutdown_on_exit:
self._atexit_handler = register(self.shutdown)
Expand Down Expand Up @@ -512,6 +516,10 @@ def get_meter(
schema_url: Optional[str] = None,
) -> Meter:

if self._disabled:
_logger.warning("SDK is disabled.")
return NoOpMeter(name, version=version, schema_url=schema_url)

if self._shutdown:
_logger.warning(
"A shutdown `MeterProvider` can not provide a `Meter`"
Expand Down
8 changes: 7 additions & 1 deletion opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT,
OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT,
OTEL_LINK_ATTRIBUTE_COUNT_LIMIT,
OTEL_SDK_DISABLED,
OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT,
OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT,
OTEL_SPAN_EVENT_COUNT_LIMIT,
Expand All @@ -62,7 +63,7 @@
InstrumentationInfo,
InstrumentationScope,
)
from opentelemetry.trace import SpanContext
from opentelemetry.trace import NoOpTracer, SpanContext
from opentelemetry.trace.status import Status, StatusCode
from opentelemetry.util import types
from opentelemetry.util._decorator import _agnosticcontextmanager
Expand Down Expand Up @@ -1176,6 +1177,8 @@ def __init__(
sampler = sampling._get_from_env_or_default()
self.sampler = sampler
self._span_limits = span_limits or SpanLimits()
disabled = environ.get(OTEL_SDK_DISABLED, "")
self._disabled = disabled.lower().strip() == "true"
self._atexit_handler = None

if shutdown_on_exit:
Expand All @@ -1191,6 +1194,9 @@ def get_tracer(
instrumenting_library_version: typing.Optional[str] = None,
schema_url: typing.Optional[str] = None,
) -> "trace_api.Tracer":
if self._disabled:
logger.warning("SDK is disabled.")
return NoOpTracer()
if not instrumenting_module_name: # Reject empty strings too.
instrumenting_module_name = ""
logger.error("get_tracer called with missing module name.")
Expand Down
9 changes: 8 additions & 1 deletion opentelemetry-sdk/tests/logs/test_logs.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@
# pylint: disable=protected-access

import unittest
from unittest.mock import patch
from unittest.mock import Mock, patch

from opentelemetry.sdk._logs import LoggerProvider
from opentelemetry.sdk._logs._internal import (
NoOpLogger,
SynchronousMultiLogRecordProcessor,
)
from opentelemetry.sdk.environment_variables import OTEL_SDK_DISABLED
from opentelemetry.sdk.resources import Resource


Expand Down Expand Up @@ -61,6 +63,11 @@ def test_get_logger(self):
logger._instrumentation_scope.schema_url, "schema_url"
)

@patch.dict("os.environ", {OTEL_SDK_DISABLED: "true"})
def test_get_logger_with_sdk_disabled(self):
logger = LoggerProvider().get_logger(Mock())
self.assertIsInstance(logger, NoOpLogger)

@patch.object(Resource, "create")
def test_logger_provider_init(self, resource_patch):
logger_provider = LoggerProvider()
Expand Down
6 changes: 6 additions & 0 deletions opentelemetry-sdk/tests/metrics/test_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from unittest.mock import MagicMock, Mock, patch

from opentelemetry.metrics import NoOpMeter
from opentelemetry.sdk.environment_variables import OTEL_SDK_DISABLED
from opentelemetry.sdk.metrics import (
Counter,
Histogram,
Expand Down Expand Up @@ -465,6 +466,11 @@ def test_create_observable_up_down_counter(self):
)
self.assertEqual(observable_up_down_counter.name, "name")

@patch.dict("os.environ", {OTEL_SDK_DISABLED: "true"})
def test_get_meter_with_sdk_disabled(self):
meter_provider = MeterProvider()
self.assertIsInstance(meter_provider.get_meter(Mock()), NoOpMeter)


class InMemoryMetricExporter(MetricExporter):
def __init__(self):
Expand Down
9 changes: 9 additions & 0 deletions opentelemetry-sdk/tests/trace/test_trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# limitations under the License.

# pylint: disable=too-many-lines
# pylint: disable=no-member

import shutil
import subprocess
Expand All @@ -33,6 +34,7 @@
OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT,
OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT,
OTEL_LINK_ATTRIBUTE_COUNT_LIMIT,
OTEL_SDK_DISABLED,
OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT,
OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT,
OTEL_SPAN_EVENT_COUNT_LIMIT,
Expand Down Expand Up @@ -162,6 +164,13 @@ def test_tracer_provider_accepts_concurrent_multi_span_processor(self):
span_processor, tracer_provider._active_span_processor
)

@mock.patch.dict("os.environ", {OTEL_SDK_DISABLED: "true"})
def test_get_tracer_with_sdk_disabled(self):
tracer_provider = trace.TracerProvider()
self.assertIsInstance(
tracer_provider.get_tracer(Mock()), trace_api.NoOpTracer
)


class TestTracerSampling(unittest.TestCase):
def tearDown(self):
Expand Down

0 comments on commit 2574707

Please sign in to comment.