Skip to content

Commit a6dff58

Browse files
authored
Add global LogEmitterProvider and convenience function get_log_emitter (#1901)
1 parent 69fdad9 commit a6dff58

File tree

6 files changed

+169
-1
lines changed

6 files changed

+169
-1
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased](https://github.com/open-telemetry/opentelemetry-python/compare/v1.3.0-0.22b0...HEAD)
88

9+
### Added
10+
- Add global LogEmitterProvider and convenience function get_log_emitter
11+
([#1901](https://github.com/open-telemetry/opentelemetry-python/pull/1901))
12+
913
### Changed
1014
- Updated `opentelemetry-opencensus-exporter` to use `service_name` of spans instead of resource
1115
([#1897](https://github.com/open-telemetry/opentelemetry-python/pull/1897))

opentelemetry-sdk/setup.cfg

+2
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ where = src
5151
[options.entry_points]
5252
opentelemetry_tracer_provider =
5353
sdk_tracer_provider = opentelemetry.sdk.trace:TracerProvider
54+
opentelemetry_log_emitter_provider =
55+
sdk_log_emitter_provider = opentelemetry.sdk.logs:LogEmitterProvider
5456
opentelemetry_exporter =
5557
console_span = opentelemetry.sdk.trace.export:ConsoleSpanExporter
5658
opentelemetry_id_generator =

opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py

+9
Original file line numberDiff line numberDiff line change
@@ -242,3 +242,12 @@
242242
243243
If both are set, :envvar:`OTEL_SERVICE_NAME` takes precedence.
244244
"""
245+
246+
OTEL_PYTHON_LOG_EMITTER_PROVIDER = "OTEL_PYTHON_LOG_EMITTER_PROVIDER"
247+
"""
248+
.. envvar:: OTEL_PYTHON_LOG_EMITTER_PROVIDER
249+
250+
The :envvar:`OTEL_PYTHON_LOG_EMITTER_PROVIDER` environment variable allows users to
251+
provide the entry point for loading the log emitter provider. If not specified, SDK
252+
LogEmitterProvider is used.
253+
"""

opentelemetry-sdk/src/opentelemetry/sdk/logs/__init__.py

+66-1
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,22 @@
1414

1515
import abc
1616
import atexit
17-
from typing import Any, Optional
17+
import logging
18+
import os
19+
from typing import Any, Optional, cast
1820

21+
from opentelemetry.sdk.environment_variables import (
22+
OTEL_PYTHON_LOG_EMITTER_PROVIDER,
23+
)
1924
from opentelemetry.sdk.logs.severity import SeverityNumber
2025
from opentelemetry.sdk.resources import Resource
2126
from opentelemetry.sdk.util.instrumentation import InstrumentationInfo
2227
from opentelemetry.trace.span import TraceFlags
28+
from opentelemetry.util._providers import _load_provider
2329
from opentelemetry.util.types import Attributes
2430

31+
_logger = logging.getLogger(__name__)
32+
2533

2634
class LogRecord:
2735
"""A LogRecord instance represents an event being logged.
@@ -172,3 +180,60 @@ def force_flush(self, timeout_millis: int = 30000) -> bool:
172180
False otherwise.
173181
"""
174182
# TODO: multi_log_processor.force_flush
183+
184+
185+
_LOG_EMITTER_PROVIDER = None
186+
187+
188+
def get_log_emitter_provider() -> LogEmitterProvider:
189+
"""Gets the current global :class:`~.LogEmitterProvider` object."""
190+
global _LOG_EMITTER_PROVIDER # pylint: disable=global-statement
191+
if _LOG_EMITTER_PROVIDER is None:
192+
if OTEL_PYTHON_LOG_EMITTER_PROVIDER not in os.environ:
193+
_LOG_EMITTER_PROVIDER = LogEmitterProvider()
194+
return _LOG_EMITTER_PROVIDER
195+
196+
_LOG_EMITTER_PROVIDER = cast(
197+
"LogEmitterProvider",
198+
_load_provider(
199+
OTEL_PYTHON_LOG_EMITTER_PROVIDER, "log_emitter_provider"
200+
),
201+
)
202+
203+
return _LOG_EMITTER_PROVIDER
204+
205+
206+
def set_log_emitter_provider(log_emitter_provider: LogEmitterProvider) -> None:
207+
"""Sets the current global :class:`~.LogEmitterProvider` object.
208+
209+
This can only be done once, a warning will be logged if any furter attempt
210+
is made.
211+
"""
212+
global _LOG_EMITTER_PROVIDER # pylint: disable=global-statement
213+
214+
if _LOG_EMITTER_PROVIDER is not None:
215+
_logger.warning(
216+
"Overriding of current LogEmitterProvider is not allowed"
217+
)
218+
return
219+
220+
_LOG_EMITTER_PROVIDER = log_emitter_provider
221+
222+
223+
def get_log_emitter(
224+
instrumenting_module_name: str,
225+
instrumenting_library_version: str = "",
226+
log_emitter_provider: Optional[LogEmitterProvider] = None,
227+
) -> LogEmitter:
228+
"""Returns a `LogEmitter` for use within a python process.
229+
230+
This function is a convenience wrapper for
231+
opentelemetry.sdk.logs.LogEmitterProvider.get_log_emitter.
232+
233+
If log_emitter_provider param is omitted the current configured one is used.
234+
"""
235+
if log_emitter_provider is None:
236+
log_emitter_provider = get_log_emitter_provider()
237+
return log_emitter_provider.get_log_emitter(
238+
instrumenting_module_name, instrumenting_library_version
239+
)
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright The OpenTelemetry Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Copyright The OpenTelemetry Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# type:ignore
16+
import unittest
17+
from importlib import reload
18+
from logging import WARNING
19+
from unittest.mock import patch
20+
21+
from opentelemetry.sdk import logs
22+
from opentelemetry.sdk.environment_variables import (
23+
OTEL_PYTHON_LOG_EMITTER_PROVIDER,
24+
)
25+
from opentelemetry.sdk.logs import (
26+
LogEmitterProvider,
27+
get_log_emitter_provider,
28+
set_log_emitter_provider,
29+
)
30+
31+
32+
class TestGlobals(unittest.TestCase):
33+
def tearDown(self):
34+
reload(logs)
35+
36+
def check_override_not_allowed(self):
37+
"""set_log_emitter_provider should throw a warning when overridden"""
38+
provider = get_log_emitter_provider()
39+
with self.assertLogs(level=WARNING) as test:
40+
set_log_emitter_provider(LogEmitterProvider())
41+
self.assertEqual(
42+
test.output,
43+
[
44+
(
45+
"WARNING:opentelemetry.sdk.logs:Overriding of current "
46+
"LogEmitterProvider is not allowed"
47+
)
48+
],
49+
)
50+
self.assertIs(provider, get_log_emitter_provider())
51+
52+
def test_set_tracer_provider(self):
53+
reload(logs)
54+
provider = LogEmitterProvider()
55+
set_log_emitter_provider(provider)
56+
retrieved_provider = get_log_emitter_provider()
57+
self.assertEqual(provider, retrieved_provider)
58+
59+
def test_tracer_provider_override_warning(self):
60+
reload(logs)
61+
self.check_override_not_allowed()
62+
63+
@patch.dict(
64+
"os.environ",
65+
{OTEL_PYTHON_LOG_EMITTER_PROVIDER: "sdk_log_emitter_provider"},
66+
)
67+
def test_sdk_log_emitter_provider(self):
68+
reload(logs)
69+
self.check_override_not_allowed()
70+
71+
@patch.dict("os.environ", {OTEL_PYTHON_LOG_EMITTER_PROVIDER: "unknown"})
72+
def test_unknown_log_emitter_provider(self):
73+
reload(logs)
74+
with self.assertRaises(Exception):
75+
get_log_emitter_provider()

0 commit comments

Comments
 (0)