Source code for opentelemetry._logs._internal

# 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.
"""
The OpenTelemetry logging API describes the classes used to generate logs and events.

The :class:`.LoggerProvider` provides users access to the :class:`.Logger` which in
turn is used to create :class:`.Event` and :class:`.Log` objects.

This module provides abstract (i.e. unimplemented) classes required for
logging, and a concrete no-op implementation :class:`.NoOpLogger` that allows applications
to use the API package alone without a supporting implementation.

To get a logger, you need to provide the package name from which you are
calling the logging APIs to OpenTelemetry by calling `LoggerProvider.get_logger`
with the calling module name and the version of your package.

The following code shows how to obtain a logger using the global :class:`.LoggerProvider`::

    from opentelemetry._logs import get_logger

    logger = get_logger("example-logger")

.. versionadded:: 1.15.0
"""

from abc import ABC, abstractmethod
from logging import getLogger
from os import environ
from typing import Any, Optional, cast

from opentelemetry._logs.severity import SeverityNumber
from opentelemetry.environment_variables import _OTEL_PYTHON_LOGGER_PROVIDER
from opentelemetry.trace.span import TraceFlags
from opentelemetry.util._once import Once
from opentelemetry.util._providers import _load_provider
from opentelemetry.util.types import Attributes

_logger = getLogger(__name__)


[docs]class LogRecord(ABC): """A LogRecord instance represents an event being logged. LogRecord instances are created and emitted via `Logger` every time something is logged. They contain all the information pertinent to the event being logged. """ def __init__( self, timestamp: Optional[int] = None, observed_timestamp: Optional[int] = None, trace_id: Optional[int] = None, span_id: Optional[int] = None, trace_flags: Optional["TraceFlags"] = None, severity_text: Optional[str] = None, severity_number: Optional[SeverityNumber] = None, body: Optional[Any] = None, attributes: Optional["Attributes"] = None, ): self.timestamp = timestamp self.observed_timestamp = observed_timestamp self.trace_id = trace_id self.span_id = span_id self.trace_flags = trace_flags self.severity_text = severity_text self.severity_number = severity_number self.body = body # type: ignore self.attributes = attributes
[docs]class Logger(ABC): """Handles emitting events and logs via `LogRecord`.""" def __init__( self, name: str, version: Optional[str] = None, schema_url: Optional[str] = None, ) -> None: super().__init__() self._name = name self._version = version self._schema_url = schema_url
[docs] @abstractmethod def emit(self, record: "LogRecord") -> None: """Emits a :class:`LogRecord` representing a log to the processing pipeline."""
[docs]class NoOpLogger(Logger): """The default Logger used when no Logger implementation is available. All operations are no-op. """
[docs] def emit(self, record: "LogRecord") -> None: pass
[docs]class LoggerProvider(ABC): """ LoggerProvider is the entry point of the API. It provides access to Logger instances. """
[docs] @abstractmethod def get_logger( self, name: str, version: Optional[str] = None, schema_url: Optional[str] = None, ) -> Logger: """Returns a `Logger` for use by the given instrumentation library. For any two calls it is undefined whether the same or different `Logger` instances are returned, even for different library names. This function may return different `Logger` types (e.g. a no-op logger vs. a functional logger). Args: name: The name of the instrumenting module. ``__name__`` may not be used as this can result in different logger names if the loggers are in different files. It is better to use a fixed string that can be imported where needed and used consistently as the name of the logger. This should *not* be the name of the module that is instrumented but the name of the module doing the instrumentation. E.g., instead of ``"requests"``, use ``"opentelemetry.instrumentation.requests"``. version: Optional. The version string of the instrumenting library. Usually this should be the same as ``pkg_resources.get_distribution(instrumenting_library_name).version``. schema_url: Optional. Specifies the Schema URL of the emitted telemetry. """
[docs]class NoOpLoggerProvider(LoggerProvider): """The default LoggerProvider used when no LoggerProvider implementation is available."""
[docs] def get_logger( self, name: str, version: Optional[str] = None, schema_url: Optional[str] = None, ) -> Logger: """Returns a NoOpLogger.""" super().get_logger(name, version=version, schema_url=schema_url) return NoOpLogger(name, version=version, schema_url=schema_url)
# TODO: ProxyLoggerProvider _LOGGER_PROVIDER_SET_ONCE = Once() _LOGGER_PROVIDER = None
[docs]def get_logger_provider() -> LoggerProvider: """Gets the current global :class:`~.LoggerProvider` object.""" global _LOGGER_PROVIDER # pylint: disable=global-statement if _LOGGER_PROVIDER is None: if _OTEL_PYTHON_LOGGER_PROVIDER not in environ.keys(): # TODO: return proxy _LOGGER_PROVIDER = NoOpLoggerProvider() return _LOGGER_PROVIDER logger_provider: LoggerProvider = _load_provider( # type: ignore _OTEL_PYTHON_LOGGER_PROVIDER, "logger_provider" ) _set_logger_provider(logger_provider, log=False) # _LOGGER_PROVIDER will have been set by one thread return cast("LoggerProvider", _LOGGER_PROVIDER)
def _set_logger_provider(logger_provider: LoggerProvider, log: bool) -> None: def set_lp() -> None: global _LOGGER_PROVIDER # pylint: disable=global-statement _LOGGER_PROVIDER = logger_provider # type: ignore did_set = _LOGGER_PROVIDER_SET_ONCE.do_once(set_lp) if log and not did_set: _logger.warning("Overriding of current LoggerProvider is not allowed")
[docs]def set_logger_provider(meter_provider: LoggerProvider) -> None: """Sets the current global :class:`~.LoggerProvider` object. This can only be done once, a warning will be logged if any further attempt is made. """ _set_logger_provider(meter_provider, log=True)
[docs]def get_logger( instrumenting_module_name: str, instrumenting_library_version: str = "", logger_provider: Optional[LoggerProvider] = None, ) -> "Logger": """Returns a `Logger` for use within a python process. This function is a convenience wrapper for opentelemetry.sdk._logs.LoggerProvider.get_logger. If logger_provider param is omitted the current configured one is used. """ if logger_provider is None: logger_provider = get_logger_provider() return logger_provider.get_logger( instrumenting_module_name, instrumenting_library_version )