From 43c79ae2ce7a1c2d1fa3eda712371510c80cc41e Mon Sep 17 00:00:00 2001 From: Srikanth Chekuri Date: Sun, 6 Jun 2021 19:18:28 +0530 Subject: [PATCH 1/4] Add global LogEmitterProvider and convenience function get_log_emitter --- opentelemetry-sdk/setup.cfg | 2 + .../sdk/environment_variables/__init__.py | 5 ++ .../src/opentelemetry/sdk/logs/__init__.py | 67 ++++++++++++++++++- opentelemetry-sdk/tests/logs/__init__.py | 13 ++++ .../tests/logs/test_global_provider.py | 61 +++++++++++++++++ 5 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 opentelemetry-sdk/tests/logs/__init__.py create mode 100644 opentelemetry-sdk/tests/logs/test_global_provider.py diff --git a/opentelemetry-sdk/setup.cfg b/opentelemetry-sdk/setup.cfg index 6c258c9796a..c4e19b1c15e 100644 --- a/opentelemetry-sdk/setup.cfg +++ b/opentelemetry-sdk/setup.cfg @@ -51,6 +51,8 @@ where = src [options.entry_points] opentelemetry_tracer_provider = sdk_tracer_provider = opentelemetry.sdk.trace:TracerProvider +opentelemetry_log_emitter_provider = + sdk_log_emitter_provider = opentelemetry.sdk.logs:LogEmitterProvider opentelemetry_exporter = console_span = opentelemetry.sdk.trace.export:ConsoleSpanExporter opentelemetry_id_generator = diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py index a59ca0e5c1d..6e27fecd2d6 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py @@ -242,3 +242,8 @@ If both are set, :envvar:`OTEL_SERVICE_NAME` takes precedence. """ + +OTEL_PYTHON_LOG_EMITTER_PROVIDER = "OTEL_PYTHON_LOG_EMITTER_PROVIDER" +""" +.. envvar:: OTEL_PYTHON_LOG_EMITTER_PROVIDER +""" diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/logs/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/logs/__init__.py index 9a0fb2a095c..f93987e08d0 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/logs/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/logs/__init__.py @@ -14,14 +14,22 @@ import abc import atexit -from typing import Any, Optional +import logging +import os +from typing import Any, Optional, cast +from opentelemetry.sdk.environment_variables import ( + OTEL_PYTHON_LOG_EMITTER_PROVIDER, +) from opentelemetry.sdk.logs.severity import SeverityNumber from opentelemetry.sdk.resources import Resource from opentelemetry.sdk.util.instrumentation import InstrumentationInfo from opentelemetry.trace.span import TraceFlags +from opentelemetry.util._providers import _load_provider from opentelemetry.util.types import Attributes +_logger = logging.getLogger(__name__) + class LogRecord: """A LogRecord instance represents an event being logged. @@ -172,3 +180,60 @@ def force_flush(self, timeout_millis: int = 30000) -> bool: False otherwise. """ # TODO: multi_log_processor.force_flush + + +_LOG_EMITTER_PROVIDER = None + + +def get_log_emitter_provider() -> LogEmitterProvider: + """Gets the current global :class:`~.LogEmitterProvider` object.""" + global _LOG_EMITTER_PROVIDER # pylint: disable=global-statement + if _LOG_EMITTER_PROVIDER is None: + if OTEL_PYTHON_LOG_EMITTER_PROVIDER not in os.environ: + _LOG_EMITTER_PROVIDER = LogEmitterProvider() + return _LOG_EMITTER_PROVIDER + + _LOG_EMITTER_PROVIDER = cast( + "LogEmitterProvider", + _load_provider( + OTEL_PYTHON_LOG_EMITTER_PROVIDER, "log_emitter_provider" + ), + ) + + return _LOG_EMITTER_PROVIDER + + +def set_log_emitter_provider(log_emitter_provider: LogEmitterProvider) -> None: + """Sets the current global :class:`~.LogEmitterProvider` object. + + This can only be done once, a warning will be logged if any furter attempt + is made. + """ + global _LOG_EMITTER_PROVIDER # pylint: disable=global-statement + + if _LOG_EMITTER_PROVIDER is not None: + _logger.warning( + "Overriding of current LogEmitterProvider is not allowed" + ) + return + + _LOG_EMITTER_PROVIDER = log_emitter_provider + + +def get_log_emitter( + instrumenting_module_name: str, + instrumenting_library_version: str = "", + log_emitter_provider: Optional[LogEmitterProvider] = None, +) -> LogEmitter: + """Returns a `LogEmitter` for use within a python process. + + This function is a convenience wrapper for + opentelemetry.sdk.logs.LogEmitterProvider.get_log_emitter. + + If log_emitter_provider param is omitted the current configured one is used. + """ + if log_emitter_provider is None: + log_emitter_provider = get_log_emitter_provider() + return log_emitter_provider.get_log_emitter( + instrumenting_module_name, instrumenting_library_version + ) diff --git a/opentelemetry-sdk/tests/logs/__init__.py b/opentelemetry-sdk/tests/logs/__init__.py new file mode 100644 index 00000000000..b0a6f428417 --- /dev/null +++ b/opentelemetry-sdk/tests/logs/__init__.py @@ -0,0 +1,13 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/opentelemetry-sdk/tests/logs/test_global_provider.py b/opentelemetry-sdk/tests/logs/test_global_provider.py new file mode 100644 index 00000000000..2490ed44576 --- /dev/null +++ b/opentelemetry-sdk/tests/logs/test_global_provider.py @@ -0,0 +1,61 @@ +# type:ignore +import unittest +from importlib import reload +from logging import WARNING +from unittest.mock import patch + +from opentelemetry.sdk import logs +from opentelemetry.sdk.environment_variables import ( + OTEL_PYTHON_LOG_EMITTER_PROVIDER, +) +from opentelemetry.sdk.logs import ( + LogEmitterProvider, + get_log_emitter_provider, + set_log_emitter_provider, +) + + +class TestGlobals(unittest.TestCase): + def tearDown(self): + reload(logs) + + def check_override_not_allowed(self): + """set_log_emitter_provider should throw a warning when overridden""" + provider = get_log_emitter_provider() + with self.assertLogs(level=WARNING) as test: + set_log_emitter_provider(LogEmitterProvider()) + self.assertEqual( + test.output, + [ + ( + "WARNING:opentelemetry.sdk.logs:Overriding of current " + "LogEmitterProvider is not allowed" + ) + ], + ) + self.assertIs(provider, get_log_emitter_provider()) + + def test_set_tracer_provider(self): + reload(logs) + provider = LogEmitterProvider() + set_log_emitter_provider(provider) + retrieved_provider = get_log_emitter_provider() + self.assertEqual(provider, retrieved_provider) + + def test_tracer_provider_override_warning(self): + reload(logs) + self.check_override_not_allowed() + + @patch.dict( + "os.environ", + {OTEL_PYTHON_LOG_EMITTER_PROVIDER: "sdk_log_emitter_provider"}, + ) + def test_sdk_log_emitter_provider(self): + reload(logs) + self.check_override_not_allowed() + + @patch.dict("os.environ", {OTEL_PYTHON_LOG_EMITTER_PROVIDER: "unknown"}) + def test_unknown_log_emitter_provider(self): + reload(logs) + with self.assertRaises(Exception): + get_log_emitter_provider() From b88bb2aad9f6e6b5de25167f904066da088a380e Mon Sep 17 00:00:00 2001 From: Srikanth Chekuri Date: Thu, 10 Jun 2021 01:00:51 +0530 Subject: [PATCH 2/4] Add license --- .../tests/logs/test_global_provider.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/opentelemetry-sdk/tests/logs/test_global_provider.py b/opentelemetry-sdk/tests/logs/test_global_provider.py index 2490ed44576..fc687d1961d 100644 --- a/opentelemetry-sdk/tests/logs/test_global_provider.py +++ b/opentelemetry-sdk/tests/logs/test_global_provider.py @@ -1,3 +1,17 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + # type:ignore import unittest from importlib import reload From bb4c3da926309b39f88f311500cc3ff1b1139a2a Mon Sep 17 00:00:00 2001 From: Srikanth Chekuri Date: Sat, 12 Jun 2021 00:01:38 +0530 Subject: [PATCH 3/4] Add env description --- .../src/opentelemetry/sdk/environment_variables/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py index 6e27fecd2d6..33cab53cb67 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py @@ -246,4 +246,8 @@ OTEL_PYTHON_LOG_EMITTER_PROVIDER = "OTEL_PYTHON_LOG_EMITTER_PROVIDER" """ .. envvar:: OTEL_PYTHON_LOG_EMITTER_PROVIDER + +The :envvar:`OTEL_PYTHON_LOG_EMITTER_PROVIDER` environment variable allows users to +provide the entry point for loading the log emitter provider. If not specified, SDK +LogEmitterProvider is used. """ From 035ed924db3f4e409f2b24ba0c979d0b3a7ccf7a Mon Sep 17 00:00:00 2001 From: Srikanth Chekuri Date: Mon, 14 Jun 2021 21:34:37 +0530 Subject: [PATCH 4/4] Add CHANGELOG entry --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4cf4a1ccd9..e76232d5ac2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased](https://github.com/open-telemetry/opentelemetry-python/compare/v1.3.0-0.22b0...HEAD) +### Added +- Add global LogEmitterProvider and convenience function get_log_emitter + ([#1901](https://github.com/open-telemetry/opentelemetry-python/pull/1901)) + ### Changed - Updated `opentelemetry-opencensus-exporter` to use `service_name` of spans instead of resource ([#1897](https://github.com/open-telemetry/opentelemetry-python/pull/1897))