Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add global LogEmitterProvider and convenience function get_log_emitter #1901

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
2 changes: 2 additions & 0 deletions opentelemetry-sdk/setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,3 +242,12 @@

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
srikanthccv marked this conversation as resolved.
Show resolved Hide resolved

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.
"""
67 changes: 66 additions & 1 deletion opentelemetry-sdk/src/opentelemetry/sdk/logs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
)
13 changes: 13 additions & 0 deletions opentelemetry-sdk/tests/logs/__init__.py
Original file line number Diff line number Diff line change
@@ -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.
75 changes: 75 additions & 0 deletions opentelemetry-sdk/tests/logs/test_global_provider.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# 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 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()