From d1c86d30e23de01b730d3a32c367ccbbbac6ba71 Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Tue, 15 Nov 2022 10:37:43 -0800 Subject: [PATCH 01/28] logs --- CHANGELOG.md | 2 + .../tests/logs/test_otlp_logs_exporter.py | 10 +- .../tests/test_proto_log_exporter.py | 2 +- .../src/opentelemetry/_logs/__init__.py | 56 +++++ .../opentelemetry/_logs/_internal/__init__.py | 226 ++++++++++++++++++ .../_logs/_internal}/severity.py | 8 +- .../opentelemetry/environment_variables.py | 6 + .../tests/logs/test_logger_provider.py | 78 ++++++ .../src/opentelemetry/sdk/_logs/__init__.py | 104 +++----- .../sdk/environment_variables.py | 8 - opentelemetry-sdk/tests/logs/test_export.py | 2 +- .../tests/logs/test_global_provider.py | 75 ------ opentelemetry-sdk/tests/logs/test_handler.py | 22 +- .../tests/logs/test_multi_log_prcessor.py | 2 +- .../src/opentelemetry/test/globals_test.py | 9 + 15 files changed, 431 insertions(+), 179 deletions(-) create mode 100644 opentelemetry-api/src/opentelemetry/_logs/__init__.py create mode 100644 opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py rename {opentelemetry-sdk/src/opentelemetry/sdk/_logs => opentelemetry-api/src/opentelemetry/_logs/_internal}/severity.py (91%) create mode 100644 opentelemetry-api/tests/logs/test_logger_provider.py delete mode 100644 opentelemetry-sdk/tests/logs/test_global_provider.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 339cdb62460..3515f5f039d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add missing entry points for OTLP/HTTP exporter ([#3027](https://github.com/open-telemetry/opentelemetry-python/pull/3027)) +- Implement logging API + ([#3027](https://github.com/open-telemetry/opentelemetry-python/pull/3027)) ## Version 1.14.0/0.35b0 (2022-11-04) diff --git a/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/logs/test_otlp_logs_exporter.py b/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/logs/test_otlp_logs_exporter.py index 07616090837..7bc36e190b8 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/logs/test_otlp_logs_exporter.py +++ b/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/logs/test_otlp_logs_exporter.py @@ -45,9 +45,7 @@ ) from opentelemetry.sdk._logs import LogData, LogRecord from opentelemetry.sdk._logs.export import LogExportResult -from opentelemetry.sdk._logs.severity import ( - SeverityNumber as SDKSeverityNumber, -) +from opentelemetry._logs import SeverityNumber from opentelemetry.sdk.resources import Resource as SDKResource from opentelemetry.sdk.util.instrumentation import InstrumentationScope from opentelemetry.trace import TraceFlags @@ -117,7 +115,7 @@ def setUp(self): span_id=5213367945872657620, trace_flags=TraceFlags(0x01), severity_text="WARNING", - severity_number=SDKSeverityNumber.WARN, + severity_number=SeverityNumber.WARN, body="Zhengzhou, We have a heaviest rains in 1000 years", resource=SDKResource({"key": "value"}), attributes={"a": 1, "b": "c"}, @@ -133,7 +131,7 @@ def setUp(self): span_id=5213367945872657623, trace_flags=TraceFlags(0x01), severity_text="INFO", - severity_number=SDKSeverityNumber.INFO2, + severity_number=SeverityNumber.INFO2, body="Sydney, Opera House is closed", resource=SDKResource({"key": "value"}), attributes={"custom_attr": [1, 2, 3]}, @@ -149,7 +147,7 @@ def setUp(self): span_id=5213367945872657628, trace_flags=TraceFlags(0x01), severity_text="ERROR", - severity_number=SDKSeverityNumber.WARN, + severity_number=SeverityNumber.WARN, body="Mumbai, Boil water before drinking", resource=SDKResource({"service": "myapp"}), ), diff --git a/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_log_exporter.py b/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_log_exporter.py index d94ddfb8f7c..a81c0c63e67 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_log_exporter.py +++ b/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_log_exporter.py @@ -54,7 +54,7 @@ ) from opentelemetry.sdk._logs import LogData from opentelemetry.sdk._logs import LogRecord as SDKLogRecord -from opentelemetry.sdk._logs.severity import SeverityNumber +from opentelemetry._logs import SeverityNumber from opentelemetry.sdk.environment_variables import ( OTEL_EXPORTER_OTLP_CERTIFICATE, OTEL_EXPORTER_OTLP_COMPRESSION, diff --git a/opentelemetry-api/src/opentelemetry/_logs/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/__init__.py new file mode 100644 index 00000000000..fd30be27f7f --- /dev/null +++ b/opentelemetry-api/src/opentelemetry/_logs/__init__.py @@ -0,0 +1,56 @@ +# 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 opentelemetry._logs._internal import ( + Logger, + LoggerProvider, + LogRecord, + get_logger, + get_logger_provider, + set_logger_provider, +) +from opentelemetry._logs._internal.severity import ( + SeverityNumber, + std_to_otel, +) + +__all__ = [ + "Logger", + "LoggerProvider", + "LogRecord", + "SeverityNumber", + "std_to_otel", +] diff --git a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py new file mode 100644 index 00000000000..225490dbec2 --- /dev/null +++ b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py @@ -0,0 +1,226 @@ +# 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 +import os +from typing import Any, Optional, cast + +from opentelemetry.environment_variables import _OTEL_PYTHON_LOGGER_PROVIDER +from opentelemetry._logs._internal.severity import SeverityNumber +from opentelemetry.trace.span import TraceFlags +from opentelemetry.util.types import Attributes +from opentelemetry.util._once import Once +from opentelemetry.util._providers import _load_provider + +_logger = getLogger(__name__) + + +class LoggerProvider(ABC): + """ + LoggerProvider is the entry point of the API. It provides access to `Logger` instances. + """ + + @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. + """ + + +class NoOpLoggerProvider(LoggerProvider): + """The default LoggerProvider used when no LoggerProvider implementation is available.""" + + 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 + + +class Logger(ABC): + """Handles emitting events and logs via `LogRecord`. + + """ + + @abstractmethod + def emit_event(self, record: "LogRecord"): + """Emits a :class:`LogRecord` representing an Event to the processing pipeline. + """ + + @abstractmethod + def emit(self, record: "LogRecord"): + """Emits a :class:`LogRecord` representing a log to the processing pipeline. + """ + + +class NoOpLogger(Logger): + """The default Logger used when no Logger implementation is available. + + All operations are no-op. + """ + + def emit_event(self, record: "LogRecord"): + pass + + def emit(self, record: "LogRecord"): + pass + + +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 + self.attributes = attributes + + +_LOGGER_PROVIDER_SET_ONCE = Once() +_LOGGER_PROVIDER = None + + +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 os.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 + + 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") + + +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) + + +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 + ) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/severity.py b/opentelemetry-api/src/opentelemetry/_logs/_internal/severity.py similarity index 91% rename from opentelemetry-sdk/src/opentelemetry/sdk/_logs/severity.py rename to opentelemetry-api/src/opentelemetry/_logs/_internal/severity.py index 25703759909..1daaa19f44c 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/severity.py +++ b/opentelemetry-api/src/opentelemetry/_logs/_internal/severity.py @@ -55,7 +55,7 @@ class SeverityNumber(enum.Enum): FATAL4 = 24 -_STD_TO_OTLP = { +_STD_TO_OTEL = { 10: SeverityNumber.DEBUG, 11: SeverityNumber.DEBUG2, 12: SeverityNumber.DEBUG3, @@ -103,13 +103,13 @@ class SeverityNumber(enum.Enum): } -def std_to_otlp(levelno: int) -> SeverityNumber: +def std_to_otel(levelno: int) -> SeverityNumber: """ Map python log levelno as defined in https://docs.python.org/3/library/logging.html#logging-levels - to OTLP log severity number. + to OTel log severity number as defined here: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/data-model.md#field-severitynumber """ if levelno < 10: return SeverityNumber.UNSPECIFIED if levelno > 53: return SeverityNumber.FATAL4 - return _STD_TO_OTLP[levelno] + return _STD_TO_OTEL[levelno] diff --git a/opentelemetry-api/src/opentelemetry/environment_variables.py b/opentelemetry-api/src/opentelemetry/environment_variables.py index 5c5a9b3c4aa..2c0e6fb9095 100644 --- a/opentelemetry-api/src/opentelemetry/environment_variables.py +++ b/opentelemetry-api/src/opentelemetry/environment_variables.py @@ -53,3 +53,9 @@ """ .. envvar:: OTEL_PYTHON_METER_PROVIDER """ + +_OTEL_PYTHON_LOGGER_PROVIDER = "OTEL_PYTHON_LOGGER_PROVIDER" +""" +.. envvar:: OTEL_PYTHON_LOGGER_PROVIDER +""" + diff --git a/opentelemetry-api/tests/logs/test_logger_provider.py b/opentelemetry-api/tests/logs/test_logger_provider.py new file mode 100644 index 00000000000..0103e6917a7 --- /dev/null +++ b/opentelemetry-api/tests/logs/test_logger_provider.py @@ -0,0 +1,78 @@ +# 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 logging import WARNING +from unittest.mock import Mock, patch + +import opentelemetry._logs._internal as logs_internal +from opentelemetry.environment_variables import _OTEL_PYTHON_LOGGER_PROVIDER +from opentelemetry._logs import get_logger_provider, set_logger_provider +from opentelemetry.test.globals_test import reset_logging_globals + + + +class TestGlobals(unittest.TestCase): + def setUp(self): + super().tearDown() + reset_logging_globals() + + def tearDown(self): + super().tearDown() + reset_logging_globals() + + def check_override_not_allowed(self): + """set_logger_provider should throw a warning when overridden""" + provider = get_logger_provider() + with self.assertLogs(level=WARNING) as test: + set_logger_provider(Mock()) + self.assertEqual( + test.output, + [ + ( + "WARNING:opentelemetry.sdk._logs:Overriding of current " + "LoggerProvider is not allowed" + ) + ], + ) + self.assertIs(provider, get_logger_provider()) + + def test_set_logger_provider(self): + lp_mock = Mock() + # pylint: disable=protected-access + assert logs_internal._LOGGER_PROVIDER is None + set_logger_provider(lp_mock) + assert logs_internal._LOGGER_PROVIDER is lp_mock + assert get_logger_provider() is lp_mock + + + def test_get_logger_provider(self): + # pylint: disable=protected-access + assert logs_internal._LOGGER_PROVIDER is None + + assert isinstance(get_logger_provider(), logs_internal.NoOpLoggerProvider) + + logs_internal._LOGGER_PROVIDER = None + + with patch.dict( + "os.environ", {_OTEL_PYTHON_LOGGER_PROVIDER: "test_logger_provider"} + ): + + with patch("opentelemetry._logs._internal._load_provider", Mock()): + with patch( + "opentelemetry._logs._internal.cast", + Mock(**{"return_value": "test_logger_provider"}), + ): + assert get_logger_provider() == "test_logger_provider" diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py index 1ca3aa48b0e..f9a8c1761ce 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py @@ -17,15 +17,19 @@ import concurrent.futures import json import logging -import os import threading import traceback from time import time_ns -from typing import Any, Callable, Optional, Tuple, Union, cast - -from opentelemetry.sdk._logs.severity import SeverityNumber, std_to_otlp -from opentelemetry.sdk.environment_variables import ( - _OTEL_PYTHON_LOGGER_PROVIDER, +from typing import Any, Callable, Optional, Tuple, Union + +from opentelemetry._logs import ( + Logger as APILogger, + LoggerProvider as APILoggerProvider, + LogRecord as APILogRecord, + SeverityNumber, + std_to_otel, + get_logger, + get_logger_provider, ) from opentelemetry.sdk.resources import Resource from opentelemetry.sdk.util import ns_to_iso_str @@ -37,13 +41,12 @@ get_current_span, ) 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: +class LogRecord(APILogRecord): """A LogRecord instance represents an event being logged. LogRecord instances are created and emitted via `Logger` @@ -54,6 +57,7 @@ class LogRecord: 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, @@ -63,15 +67,20 @@ def __init__( resource: Optional[Resource] = None, attributes: Optional[Attributes] = None, ): - self.timestamp = 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 + super().__init__( + **{ + "timestamp": timestamp, + "observed_timestamp": observed_timestamp, + "trace_id": trace_id, + "span_id": span_id, + "trace_flags": trace_flags, + "severity_text": severity_text, + "severity_number": severity_number, + "body": body, + "attributes": attributes, + } + ) self.resource = resource - self.attributes = attributes def __eq__(self, other: object) -> bool: if not isinstance(other, LogRecord): @@ -351,7 +360,7 @@ def _translate(self, record: logging.LogRecord) -> LogRecord: timestamp = int(record.created * 1e9) span_context = get_current_span().get_span_context() attributes = self._get_attributes(record) - severity_number = std_to_otlp(record.levelno) + severity_number = std_to_otel(record.levelno) return LogRecord( timestamp=timestamp, trace_id=span_context.trace_id, @@ -379,7 +388,7 @@ def flush(self) -> None: self._logger_provider.force_flush() -class Logger: +class Logger(APILogger): def __init__( self, resource: Resource, @@ -404,8 +413,12 @@ def emit(self, record: LogRecord): log_data = LogData(record, self._instrumentation_scope) self._multi_log_record_processor.emit(log_data) + def emit_event(self, record: LogRecord): + # TODO + pass + -class LoggerProvider: +class LoggerProvider(APILoggerProvider): def __init__( self, resource: Resource = Resource.create(), @@ -470,56 +483,3 @@ def force_flush(self, timeout_millis: int = 30000) -> bool: False otherwise. """ return self._multi_log_record_processor.force_flush(timeout_millis) - - -_LOGGER_PROVIDER = None - - -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 os.environ: - _LOGGER_PROVIDER = LoggerProvider() - return _LOGGER_PROVIDER - - _LOGGER_PROVIDER = cast( - "LoggerProvider", - _load_provider(_OTEL_PYTHON_LOGGER_PROVIDER, "logger_provider"), - ) - - return _LOGGER_PROVIDER - - -def set_logger_provider(logger_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. - """ - global _LOGGER_PROVIDER # pylint: disable=global-statement - - if _LOGGER_PROVIDER is not None: - _logger.warning("Overriding of current LoggerProvider is not allowed") - return - - _LOGGER_PROVIDER = logger_provider - - -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 - ) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables.py b/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables.py index e8afdd6cbf1..318bbeb1ce3 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables.py @@ -501,14 +501,6 @@ If both are set, :envvar:`OTEL_SERVICE_NAME` takes precedence. """ -_OTEL_PYTHON_LOGGER_PROVIDER = "OTEL_PYTHON_LOGGER_PROVIDER" -""" -.. envvar:: OTEL_PYTHON_LOGGER_PROVIDER - -The :envvar:`OTEL_PYTHON_LOGGER_PROVIDER` environment variable allows users to -provide the entry point for loading the log emitter provider. If not specified, SDK -LoggerProvider is used. -""" _OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED = ( "OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED" diff --git a/opentelemetry-sdk/tests/logs/test_export.py b/opentelemetry-sdk/tests/logs/test_export.py index e65fc04a423..a110e0e0189 100644 --- a/opentelemetry-sdk/tests/logs/test_export.py +++ b/opentelemetry-sdk/tests/logs/test_export.py @@ -36,7 +36,7 @@ from opentelemetry.sdk._logs.export.in_memory_log_exporter import ( InMemoryLogExporter, ) -from opentelemetry.sdk._logs.severity import SeverityNumber +from opentelemetry._logs import SeverityNumber from opentelemetry.sdk.resources import Resource as SDKResource from opentelemetry.sdk.util.instrumentation import InstrumentationScope from opentelemetry.test.concurrency_test import ConcurrencyTestBase diff --git a/opentelemetry-sdk/tests/logs/test_global_provider.py b/opentelemetry-sdk/tests/logs/test_global_provider.py deleted file mode 100644 index d888789898f..00000000000 --- a/opentelemetry-sdk/tests/logs/test_global_provider.py +++ /dev/null @@ -1,75 +0,0 @@ -# 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._logs import ( - LoggerProvider, - get_logger_provider, - set_logger_provider, -) -from opentelemetry.sdk.environment_variables import ( - _OTEL_PYTHON_LOGGER_PROVIDER, -) - - -class TestGlobals(unittest.TestCase): - def tearDown(self): - reload(_logs) - - def check_override_not_allowed(self): - """set_logger_provider should throw a warning when overridden""" - provider = get_logger_provider() - with self.assertLogs(level=WARNING) as test: - set_logger_provider(LoggerProvider()) - self.assertEqual( - test.output, - [ - ( - "WARNING:opentelemetry.sdk._logs:Overriding of current " - "LoggerProvider is not allowed" - ) - ], - ) - self.assertIs(provider, get_logger_provider()) - - def test_set_tracer_provider(self): - reload(_logs) - provider = LoggerProvider() - set_logger_provider(provider) - retrieved_provider = get_logger_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_LOGGER_PROVIDER: "sdk_logger_provider"}, - ) - def test_sdk_logger_provider(self): - reload(_logs) - self.check_override_not_allowed() - - @patch.dict("os.environ", {_OTEL_PYTHON_LOGGER_PROVIDER: "unknown"}) - def test_unknown_logger_provider(self): - reload(_logs) - with self.assertRaises(Exception): - get_logger_provider() diff --git a/opentelemetry-sdk/tests/logs/test_handler.py b/opentelemetry-sdk/tests/logs/test_handler.py index 771179c3d22..0581a598ab5 100644 --- a/opentelemetry-sdk/tests/logs/test_handler.py +++ b/opentelemetry-sdk/tests/logs/test_handler.py @@ -15,12 +15,12 @@ import unittest from unittest.mock import Mock -from opentelemetry.sdk import trace -from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler -from opentelemetry.sdk._logs import get_logger as sdk_get_logger -from opentelemetry.sdk._logs.severity import SeverityNumber +from opentelemetry._logs import get_logger as APIGetLogger +from opentelemetry._logs import SeverityNumber from opentelemetry.semconv.trace import SpanAttributes from opentelemetry.trace import INVALID_SPAN_CONTEXT +from opentelemetry.sdk import trace +from opentelemetry.sdk._logs import LoggingHandler, LoggerProvider def get_logger(level=logging.NOTSET, logger_provider=None): @@ -33,7 +33,7 @@ def get_logger(level=logging.NOTSET, logger_provider=None): class TestLoggingHandler(unittest.TestCase): def test_handler_default_log_level(self): emitter_provider_mock = Mock(spec=LoggerProvider) - emitter_mock = sdk_get_logger( + emitter_mock = APIGetLogger( __name__, logger_provider=emitter_provider_mock ) logger = get_logger(logger_provider=emitter_provider_mock) @@ -46,7 +46,7 @@ def test_handler_default_log_level(self): def test_handler_custom_log_level(self): emitter_provider_mock = Mock(spec=LoggerProvider) - emitter_mock = sdk_get_logger( + emitter_mock = APIGetLogger( __name__, logger_provider=emitter_provider_mock ) logger = get_logger( @@ -61,7 +61,7 @@ def test_handler_custom_log_level(self): def test_log_record_no_span_context(self): emitter_provider_mock = Mock(spec=LoggerProvider) - emitter_mock = sdk_get_logger( + emitter_mock = APIGetLogger( __name__, logger_provider=emitter_provider_mock ) logger = get_logger(logger_provider=emitter_provider_mock) @@ -80,7 +80,7 @@ def test_log_record_no_span_context(self): def test_log_record_user_attributes(self): """Attributes can be injected into logs by adding them to the LogRecord""" emitter_provider_mock = Mock(spec=LoggerProvider) - emitter_mock = sdk_get_logger( + emitter_mock = APIGetLogger( __name__, logger_provider=emitter_provider_mock ) logger = get_logger(logger_provider=emitter_provider_mock) @@ -95,7 +95,7 @@ def test_log_record_user_attributes(self): def test_log_record_exception(self): """Exception information will be included in attributes""" emitter_provider_mock = Mock(spec=LoggerProvider) - emitter_mock = sdk_get_logger( + emitter_mock = APIGetLogger( __name__, logger_provider=emitter_provider_mock ) logger = get_logger(logger_provider=emitter_provider_mock) @@ -128,7 +128,7 @@ def test_log_record_exception(self): def test_log_exc_info_false(self): """Exception information will be included in attributes""" emitter_provider_mock = Mock(spec=LoggerProvider) - emitter_mock = sdk_get_logger( + emitter_mock = APIGetLogger( __name__, logger_provider=emitter_provider_mock ) logger = get_logger(logger_provider=emitter_provider_mock) @@ -151,7 +151,7 @@ def test_log_exc_info_false(self): def test_log_record_trace_correlation(self): emitter_provider_mock = Mock(spec=LoggerProvider) - emitter_mock = sdk_get_logger( + emitter_mock = APIGetLogger( __name__, logger_provider=emitter_provider_mock ) logger = get_logger(logger_provider=emitter_provider_mock) diff --git a/opentelemetry-sdk/tests/logs/test_multi_log_prcessor.py b/opentelemetry-sdk/tests/logs/test_multi_log_prcessor.py index 004bc296bec..9986abe8dbb 100644 --- a/opentelemetry-sdk/tests/logs/test_multi_log_prcessor.py +++ b/opentelemetry-sdk/tests/logs/test_multi_log_prcessor.py @@ -29,7 +29,7 @@ LogRecordProcessor, SynchronousMultiLogRecordProcessor, ) -from opentelemetry.sdk._logs.severity import SeverityNumber +from opentelemetry._logs import SeverityNumber class AnotherLogRecordProcessor(LogRecordProcessor): diff --git a/tests/opentelemetry-test-utils/src/opentelemetry/test/globals_test.py b/tests/opentelemetry-test-utils/src/opentelemetry/test/globals_test.py index 19ee5f85eaf..3e2ddb1fc37 100644 --- a/tests/opentelemetry-test-utils/src/opentelemetry/test/globals_test.py +++ b/tests/opentelemetry-test-utils/src/opentelemetry/test/globals_test.py @@ -16,6 +16,7 @@ from opentelemetry import trace as trace_api from opentelemetry.metrics import _internal as metrics_api +from opentelemetry._logs import _internal as logging_api from opentelemetry.metrics._internal import _ProxyMeterProvider from opentelemetry.util._once import Once @@ -36,6 +37,14 @@ def reset_metrics_globals() -> None: metrics_api._PROXY_METER_PROVIDER = _ProxyMeterProvider() # type: ignore[attr-defined] +# pylint: disable=protected-access +def reset_logging_globals() -> None: + """WARNING: only use this for tests.""" + logging_api._LOGGER_PROVIDER_SET_ONCE = Once() # type: ignore[attr-defined] + logging_api._LOGGER_PROVIDER = None # type: ignore[attr-defined] + # logging_api._PROXY_LOGGER_PROVIDER = _ProxyLoggerProvider() # type: ignore[attr-defined] + + class TraceGlobalsTest(unittest.TestCase): """Resets trace API globals in setUp/tearDown From a3e2dae77860e84811fbef2e7db84125ac438a00 Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Tue, 15 Nov 2022 11:14:18 -0800 Subject: [PATCH 02/28] lint --- CHANGELOG.md | 2 +- docs/api/logs.rst | 17 +++++++++++++ docs/sdk/logs.severity.rst | 7 ------ .../opentelemetry/_logs/_internal/__init__.py | 11 +++----- .../opentelemetry/environment_variables.py | 1 - .../tests/logs/test_logger_provider.py | 25 ++++--------------- .../sdk/_configuration/__init__.py | 7 ++---- 7 files changed, 29 insertions(+), 41 deletions(-) create mode 100644 docs/api/logs.rst delete mode 100644 docs/sdk/logs.severity.rst diff --git a/CHANGELOG.md b/CHANGELOG.md index 3515f5f039d..1aa1edbf508 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add missing entry points for OTLP/HTTP exporter ([#3027](https://github.com/open-telemetry/opentelemetry-python/pull/3027)) - Implement logging API - ([#3027](https://github.com/open-telemetry/opentelemetry-python/pull/3027)) + ([#3038](https://github.com/open-telemetry/opentelemetry-python/pull/3038)) ## Version 1.14.0/0.35b0 (2022-11-04) diff --git a/docs/api/logs.rst b/docs/api/logs.rst new file mode 100644 index 00000000000..975f72dfee7 --- /dev/null +++ b/docs/api/logs.rst @@ -0,0 +1,17 @@ +opentelemetry._logs package +============================= + +.. warning:: + OpenTelemetry Python logs are in an experimental state. The APIs within + :mod:`opentelemetry._logs` are subject to change in minor/patch releases and make no + backward compatibility guarantees at this time. + + Once logs become stable, this package will be be renamed to ``opentelemetry.logs``. + +.. toctree:: + + +Module contents +--------------- + +.. automodule:: opentelemetry._logs diff --git a/docs/sdk/logs.severity.rst b/docs/sdk/logs.severity.rst deleted file mode 100644 index 1197e8b44e8..00000000000 --- a/docs/sdk/logs.severity.rst +++ /dev/null @@ -1,7 +0,0 @@ -opentelemetry.sdk._logs.severity -================================ - -.. automodule:: opentelemetry.sdk._logs.severity - :members: - :undoc-members: - :show-inheritance: \ No newline at end of file diff --git a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py index 225490dbec2..1d61756fb86 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py @@ -102,23 +102,20 @@ def get_logger( super().get_logger(name, version=version, schema_url=schema_url) return NoOpLogger(name, version=version, schema_url=schema_url) + # TODO: ProxyLoggerProvider class Logger(ABC): - """Handles emitting events and logs via `LogRecord`. - - """ + """Handles emitting events and logs via `LogRecord`.""" @abstractmethod def emit_event(self, record: "LogRecord"): - """Emits a :class:`LogRecord` representing an Event to the processing pipeline. - """ + """Emits a :class:`LogRecord` representing an Event to the processing pipeline.""" @abstractmethod def emit(self, record: "LogRecord"): - """Emits a :class:`LogRecord` representing a log to the processing pipeline. - """ + """Emits a :class:`LogRecord` representing a log to the processing pipeline.""" class NoOpLogger(Logger): diff --git a/opentelemetry-api/src/opentelemetry/environment_variables.py b/opentelemetry-api/src/opentelemetry/environment_variables.py index 2c0e6fb9095..c54b13c6da0 100644 --- a/opentelemetry-api/src/opentelemetry/environment_variables.py +++ b/opentelemetry-api/src/opentelemetry/environment_variables.py @@ -58,4 +58,3 @@ """ .. envvar:: OTEL_PYTHON_LOGGER_PROVIDER """ - diff --git a/opentelemetry-api/tests/logs/test_logger_provider.py b/opentelemetry-api/tests/logs/test_logger_provider.py index 0103e6917a7..d9457b039a7 100644 --- a/opentelemetry-api/tests/logs/test_logger_provider.py +++ b/opentelemetry-api/tests/logs/test_logger_provider.py @@ -23,7 +23,6 @@ from opentelemetry.test.globals_test import reset_logging_globals - class TestGlobals(unittest.TestCase): def setUp(self): super().tearDown() @@ -33,22 +32,6 @@ def tearDown(self): super().tearDown() reset_logging_globals() - def check_override_not_allowed(self): - """set_logger_provider should throw a warning when overridden""" - provider = get_logger_provider() - with self.assertLogs(level=WARNING) as test: - set_logger_provider(Mock()) - self.assertEqual( - test.output, - [ - ( - "WARNING:opentelemetry.sdk._logs:Overriding of current " - "LoggerProvider is not allowed" - ) - ], - ) - self.assertIs(provider, get_logger_provider()) - def test_set_logger_provider(self): lp_mock = Mock() # pylint: disable=protected-access @@ -57,17 +40,19 @@ def test_set_logger_provider(self): assert logs_internal._LOGGER_PROVIDER is lp_mock assert get_logger_provider() is lp_mock - def test_get_logger_provider(self): # pylint: disable=protected-access assert logs_internal._LOGGER_PROVIDER is None - assert isinstance(get_logger_provider(), logs_internal.NoOpLoggerProvider) + assert isinstance( + get_logger_provider(), logs_internal.NoOpLoggerProvider + ) logs_internal._LOGGER_PROVIDER = None with patch.dict( - "os.environ", {_OTEL_PYTHON_LOGGER_PROVIDER: "test_logger_provider"} + "os.environ", + {_OTEL_PYTHON_LOGGER_PROVIDER: "test_logger_provider"}, ): with patch("opentelemetry._logs._internal._load_provider", Mock()): diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py index c2280e1b27e..69ea3446fb7 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py @@ -31,12 +31,9 @@ OTEL_PYTHON_ID_GENERATOR, OTEL_TRACES_EXPORTER, ) +from opentelemetry._logs import set_logger_provider from opentelemetry.metrics import set_meter_provider -from opentelemetry.sdk._logs import ( - LoggerProvider, - LoggingHandler, - set_logger_provider, -) +from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler from opentelemetry.sdk._logs.export import BatchLogRecordProcessor, LogExporter from opentelemetry.sdk.environment_variables import ( _OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED, From a1128223d4f6baf4f4a094062cba4cd2ea8f26b5 Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Tue, 15 Nov 2022 12:46:01 -0800 Subject: [PATCH 03/28] lint --- docs/api/logs.rst | 5 ++++ docs/sdk/logs.rst | 1 - .../tests/logs/test_otlp_logs_exporter.py | 2 +- .../tests/test_proto_log_exporter.py | 2 +- .../src/opentelemetry/_logs/__init__.py | 5 +--- .../opentelemetry/_logs/_internal/__init__.py | 25 +++++++++++++------ .../tests/logs/test_logger_provider.py | 2 +- .../sdk/_configuration/__init__.py | 2 +- .../src/opentelemetry/sdk/_logs/__init__.py | 6 ++--- opentelemetry-sdk/tests/logs/test_export.py | 2 +- opentelemetry-sdk/tests/logs/test_handler.py | 2 +- .../tests/logs/test_multi_log_prcessor.py | 2 +- .../src/opentelemetry/test/globals_test.py | 2 +- 13 files changed, 35 insertions(+), 23 deletions(-) diff --git a/docs/api/logs.rst b/docs/api/logs.rst index 975f72dfee7..50d0a54cbad 100644 --- a/docs/api/logs.rst +++ b/docs/api/logs.rst @@ -8,8 +8,13 @@ opentelemetry._logs package Once logs become stable, this package will be be renamed to ``opentelemetry.logs``. +Submodules +---------- + .. toctree:: + logs.severity + Module contents --------------- diff --git a/docs/sdk/logs.rst b/docs/sdk/logs.rst index 569ad30b797..c10b26aa78e 100644 --- a/docs/sdk/logs.rst +++ b/docs/sdk/logs.rst @@ -14,7 +14,6 @@ Submodules .. toctree:: logs.export - logs.severity .. automodule:: opentelemetry.sdk._logs :members: diff --git a/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/logs/test_otlp_logs_exporter.py b/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/logs/test_otlp_logs_exporter.py index 7bc36e190b8..c5f0fcd92ec 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/logs/test_otlp_logs_exporter.py +++ b/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/logs/test_otlp_logs_exporter.py @@ -21,6 +21,7 @@ from google.rpc.error_details_pb2 import RetryInfo from grpc import StatusCode, server +from opentelemetry._logs import SeverityNumber from opentelemetry.exporter.otlp.proto.grpc._log_exporter import ( OTLPLogExporter, ) @@ -45,7 +46,6 @@ ) from opentelemetry.sdk._logs import LogData, LogRecord from opentelemetry.sdk._logs.export import LogExportResult -from opentelemetry._logs import SeverityNumber from opentelemetry.sdk.resources import Resource as SDKResource from opentelemetry.sdk.util.instrumentation import InstrumentationScope from opentelemetry.trace import TraceFlags diff --git a/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_log_exporter.py b/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_log_exporter.py index a81c0c63e67..7dcb82030d4 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_log_exporter.py +++ b/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_log_exporter.py @@ -21,6 +21,7 @@ import requests import responses +from opentelemetry._logs import SeverityNumber from opentelemetry.exporter.otlp.proto.http import Compression from opentelemetry.exporter.otlp.proto.http._log_exporter import ( DEFAULT_COMPRESSION, @@ -54,7 +55,6 @@ ) from opentelemetry.sdk._logs import LogData from opentelemetry.sdk._logs import LogRecord as SDKLogRecord -from opentelemetry._logs import SeverityNumber from opentelemetry.sdk.environment_variables import ( OTEL_EXPORTER_OTLP_CERTIFICATE, OTEL_EXPORTER_OTLP_COMPRESSION, diff --git a/opentelemetry-api/src/opentelemetry/_logs/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/__init__.py index fd30be27f7f..482e1c8dfac 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/__init__.py @@ -42,10 +42,7 @@ get_logger_provider, set_logger_provider, ) -from opentelemetry._logs._internal.severity import ( - SeverityNumber, - std_to_otel, -) +from opentelemetry._logs._internal.severity import SeverityNumber, std_to_otel __all__ = [ "Logger", diff --git a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py index 1d61756fb86..b141e7cd898 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py @@ -34,17 +34,17 @@ .. versionadded:: 1.15.0 """ +import os from abc import ABC, abstractmethod from logging import getLogger -import os from typing import Any, Optional, cast -from opentelemetry.environment_variables import _OTEL_PYTHON_LOGGER_PROVIDER from opentelemetry._logs._internal.severity import SeverityNumber +from opentelemetry.environment_variables import _OTEL_PYTHON_LOGGER_PROVIDER from opentelemetry.trace.span import TraceFlags -from opentelemetry.util.types import Attributes from opentelemetry.util._once import Once from opentelemetry.util._providers import _load_provider +from opentelemetry.util.types import Attributes _logger = getLogger(__name__) @@ -109,12 +109,23 @@ def get_logger( 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 + @abstractmethod - def emit_event(self, record: "LogRecord"): + def emit_event(self, record: "LogRecord") -> None: """Emits a :class:`LogRecord` representing an Event to the processing pipeline.""" @abstractmethod - def emit(self, record: "LogRecord"): + def emit(self, record: "LogRecord") -> None: """Emits a :class:`LogRecord` representing a log to the processing pipeline.""" @@ -124,10 +135,10 @@ class NoOpLogger(Logger): All operations are no-op. """ - def emit_event(self, record: "LogRecord"): + def emit_event(self, record: "LogRecord") -> None: pass - def emit(self, record: "LogRecord"): + def emit(self, record: "LogRecord") -> None: pass diff --git a/opentelemetry-api/tests/logs/test_logger_provider.py b/opentelemetry-api/tests/logs/test_logger_provider.py index d9457b039a7..1f5bfd428e5 100644 --- a/opentelemetry-api/tests/logs/test_logger_provider.py +++ b/opentelemetry-api/tests/logs/test_logger_provider.py @@ -18,8 +18,8 @@ from unittest.mock import Mock, patch import opentelemetry._logs._internal as logs_internal -from opentelemetry.environment_variables import _OTEL_PYTHON_LOGGER_PROVIDER from opentelemetry._logs import get_logger_provider, set_logger_provider +from opentelemetry.environment_variables import _OTEL_PYTHON_LOGGER_PROVIDER from opentelemetry.test.globals_test import reset_logging_globals diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py index 69ea3446fb7..5b8144c716e 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py @@ -25,13 +25,13 @@ from typing_extensions import Literal +from opentelemetry._logs import set_logger_provider from opentelemetry.environment_variables import ( OTEL_LOGS_EXPORTER, OTEL_METRICS_EXPORTER, OTEL_PYTHON_ID_GENERATOR, OTEL_TRACES_EXPORTER, ) -from opentelemetry._logs import set_logger_provider from opentelemetry.metrics import set_meter_provider from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler from opentelemetry.sdk._logs.export import BatchLogRecordProcessor, LogExporter diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py index f9a8c1761ce..6004c3e42bd 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py @@ -22,10 +22,10 @@ from time import time_ns from typing import Any, Callable, Optional, Tuple, Union +from opentelemetry._logs import Logger as APILogger +from opentelemetry._logs import LoggerProvider as APILoggerProvider +from opentelemetry._logs import LogRecord as APILogRecord from opentelemetry._logs import ( - Logger as APILogger, - LoggerProvider as APILoggerProvider, - LogRecord as APILogRecord, SeverityNumber, std_to_otel, get_logger, diff --git a/opentelemetry-sdk/tests/logs/test_export.py b/opentelemetry-sdk/tests/logs/test_export.py index a110e0e0189..bcca6fc740c 100644 --- a/opentelemetry-sdk/tests/logs/test_export.py +++ b/opentelemetry-sdk/tests/logs/test_export.py @@ -21,6 +21,7 @@ from concurrent.futures import ThreadPoolExecutor from unittest.mock import Mock, patch +from opentelemetry._logs import SeverityNumber from opentelemetry.sdk import trace from opentelemetry.sdk._logs import ( LogData, @@ -36,7 +37,6 @@ from opentelemetry.sdk._logs.export.in_memory_log_exporter import ( InMemoryLogExporter, ) -from opentelemetry._logs import SeverityNumber from opentelemetry.sdk.resources import Resource as SDKResource from opentelemetry.sdk.util.instrumentation import InstrumentationScope from opentelemetry.test.concurrency_test import ConcurrencyTestBase diff --git a/opentelemetry-sdk/tests/logs/test_handler.py b/opentelemetry-sdk/tests/logs/test_handler.py index 0581a598ab5..16a020db4b9 100644 --- a/opentelemetry-sdk/tests/logs/test_handler.py +++ b/opentelemetry-sdk/tests/logs/test_handler.py @@ -15,8 +15,8 @@ import unittest from unittest.mock import Mock -from opentelemetry._logs import get_logger as APIGetLogger from opentelemetry._logs import SeverityNumber +from opentelemetry._logs import get_logger as APIGetLogger from opentelemetry.semconv.trace import SpanAttributes from opentelemetry.trace import INVALID_SPAN_CONTEXT from opentelemetry.sdk import trace diff --git a/opentelemetry-sdk/tests/logs/test_multi_log_prcessor.py b/opentelemetry-sdk/tests/logs/test_multi_log_prcessor.py index 9986abe8dbb..e270812eb71 100644 --- a/opentelemetry-sdk/tests/logs/test_multi_log_prcessor.py +++ b/opentelemetry-sdk/tests/logs/test_multi_log_prcessor.py @@ -21,6 +21,7 @@ from abc import ABC, abstractmethod from unittest.mock import Mock +from opentelemetry._logs import SeverityNumber from opentelemetry.sdk._logs import ( ConcurrentMultiLogRecordProcessor, LoggerProvider, @@ -29,7 +30,6 @@ LogRecordProcessor, SynchronousMultiLogRecordProcessor, ) -from opentelemetry._logs import SeverityNumber class AnotherLogRecordProcessor(LogRecordProcessor): diff --git a/tests/opentelemetry-test-utils/src/opentelemetry/test/globals_test.py b/tests/opentelemetry-test-utils/src/opentelemetry/test/globals_test.py index 3e2ddb1fc37..23b3112430d 100644 --- a/tests/opentelemetry-test-utils/src/opentelemetry/test/globals_test.py +++ b/tests/opentelemetry-test-utils/src/opentelemetry/test/globals_test.py @@ -15,8 +15,8 @@ import unittest from opentelemetry import trace as trace_api -from opentelemetry.metrics import _internal as metrics_api from opentelemetry._logs import _internal as logging_api +from opentelemetry.metrics import _internal as metrics_api from opentelemetry.metrics._internal import _ProxyMeterProvider from opentelemetry.util._once import Once From 836274defe27efa50f6e2d3f9000cc8c496c39f0 Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Tue, 15 Nov 2022 13:35:52 -0800 Subject: [PATCH 04/28] lint --- docs/api/logs.severity.rst | 7 +++++++ opentelemetry-api/src/opentelemetry/_logs/__init__.py | 3 +++ 2 files changed, 10 insertions(+) create mode 100644 docs/api/logs.severity.rst diff --git a/docs/api/logs.severity.rst b/docs/api/logs.severity.rst new file mode 100644 index 00000000000..171331b2991 --- /dev/null +++ b/docs/api/logs.severity.rst @@ -0,0 +1,7 @@ +opentelemetry._logs.severity +============================ + +.. automodule:: opentelemetry._logs.severity + :members: + :undoc-members: + :show-inheritance: diff --git a/opentelemetry-api/src/opentelemetry/_logs/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/__init__.py index 482e1c8dfac..ea6383be867 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/__init__.py @@ -49,5 +49,8 @@ "LoggerProvider", "LogRecord", "SeverityNumber", + "get_logger", + "get_logger_provider", + "set_logger_provider", "std_to_otel", ] From 543dc735bdb89f0a61853dc72ca8ef5bc4b95b34 Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Tue, 15 Nov 2022 13:38:45 -0800 Subject: [PATCH 05/28] Update __init__.py --- .../src/opentelemetry/_logs/_internal/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py index b141e7cd898..9d5ce614b20 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py @@ -169,7 +169,7 @@ def __init__( self.trace_flags = trace_flags self.severity_text = severity_text self.severity_number = severity_number - self.body = body + self.body = body # type: ignore self.attributes = attributes @@ -198,7 +198,7 @@ def get_logger_provider() -> LoggerProvider: 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 + _LOGGER_PROVIDER = logger_provider # type: ignore did_set = _LOGGER_PROVIDER_SET_ONCE.do_once(set_lp) From cbde1a872fe031cda4fd1723d3f44e07bbfe4e1f Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Tue, 15 Nov 2022 14:04:51 -0800 Subject: [PATCH 06/28] lint --- docs/api/logs.rst | 2 +- opentelemetry-api/src/opentelemetry/_logs/__init__.py | 2 +- .../src/opentelemetry/_logs/_internal/__init__.py | 2 +- .../_logs/{_internal/severity.py => severity/__init__.py} | 0 opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py | 2 +- opentelemetry-sdk/tests/logs/test_handler.py | 4 ++-- 6 files changed, 6 insertions(+), 6 deletions(-) rename opentelemetry-api/src/opentelemetry/_logs/{_internal/severity.py => severity/__init__.py} (100%) diff --git a/docs/api/logs.rst b/docs/api/logs.rst index 50d0a54cbad..3ad03d7af50 100644 --- a/docs/api/logs.rst +++ b/docs/api/logs.rst @@ -1,5 +1,5 @@ opentelemetry._logs package -============================= +=========================== .. warning:: OpenTelemetry Python logs are in an experimental state. The APIs within diff --git a/opentelemetry-api/src/opentelemetry/_logs/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/__init__.py index ea6383be867..83109a318d0 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/__init__.py @@ -42,7 +42,7 @@ get_logger_provider, set_logger_provider, ) -from opentelemetry._logs._internal.severity import SeverityNumber, std_to_otel +from opentelemetry._logs.severity import SeverityNumber, std_to_otel __all__ = [ "Logger", diff --git a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py index 9d5ce614b20..3eb60ec5358 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py @@ -39,7 +39,7 @@ from logging import getLogger from typing import Any, Optional, cast -from opentelemetry._logs._internal.severity import SeverityNumber +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 diff --git a/opentelemetry-api/src/opentelemetry/_logs/_internal/severity.py b/opentelemetry-api/src/opentelemetry/_logs/severity/__init__.py similarity index 100% rename from opentelemetry-api/src/opentelemetry/_logs/_internal/severity.py rename to opentelemetry-api/src/opentelemetry/_logs/severity/__init__.py diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py index 6004c3e42bd..ca48861c651 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py @@ -27,9 +27,9 @@ from opentelemetry._logs import LogRecord as APILogRecord from opentelemetry._logs import ( SeverityNumber, - std_to_otel, get_logger, get_logger_provider, + std_to_otel, ) from opentelemetry.sdk.resources import Resource from opentelemetry.sdk.util import ns_to_iso_str diff --git a/opentelemetry-sdk/tests/logs/test_handler.py b/opentelemetry-sdk/tests/logs/test_handler.py index 16a020db4b9..408f8327a2b 100644 --- a/opentelemetry-sdk/tests/logs/test_handler.py +++ b/opentelemetry-sdk/tests/logs/test_handler.py @@ -17,10 +17,10 @@ from opentelemetry._logs import SeverityNumber from opentelemetry._logs import get_logger as APIGetLogger -from opentelemetry.semconv.trace import SpanAttributes -from opentelemetry.trace import INVALID_SPAN_CONTEXT from opentelemetry.sdk import trace from opentelemetry.sdk._logs import LoggingHandler, LoggerProvider +from opentelemetry.semconv.trace import SpanAttributes +from opentelemetry.trace import INVALID_SPAN_CONTEXT def get_logger(level=logging.NOTSET, logger_provider=None): From a44232d749b74427ccec1b706ffbfdf60b61edd1 Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Tue, 15 Nov 2022 14:49:13 -0800 Subject: [PATCH 07/28] lint --- docs/api/index.rst | 1 + docs/sdk/logs.rst | 3 +++ opentelemetry-sdk/tests/logs/test_handler.py | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/api/index.rst b/docs/api/index.rst index 22d77fc5a08..0238b01053b 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -8,6 +8,7 @@ OpenTelemetry Python API baggage context + logs propagate propagators trace diff --git a/docs/sdk/logs.rst b/docs/sdk/logs.rst index c10b26aa78e..b5febdc13e5 100644 --- a/docs/sdk/logs.rst +++ b/docs/sdk/logs.rst @@ -15,6 +15,9 @@ Submodules logs.export +Module contents +--------------- + .. automodule:: opentelemetry.sdk._logs :members: :undoc-members: diff --git a/opentelemetry-sdk/tests/logs/test_handler.py b/opentelemetry-sdk/tests/logs/test_handler.py index 408f8327a2b..b9c40608e14 100644 --- a/opentelemetry-sdk/tests/logs/test_handler.py +++ b/opentelemetry-sdk/tests/logs/test_handler.py @@ -18,7 +18,7 @@ from opentelemetry._logs import SeverityNumber from opentelemetry._logs import get_logger as APIGetLogger from opentelemetry.sdk import trace -from opentelemetry.sdk._logs import LoggingHandler, LoggerProvider +from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler from opentelemetry.semconv.trace import SpanAttributes from opentelemetry.trace import INVALID_SPAN_CONTEXT From 2daf55ea0af7ac5155bbbeb54434faa92b1b55ee Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Thu, 17 Nov 2022 10:44:04 -0800 Subject: [PATCH 08/28] lint --- opentelemetry-api/src/opentelemetry/_logs/__init__.py | 2 ++ opentelemetry-api/tests/logs/test_logger_provider.py | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/opentelemetry-api/src/opentelemetry/_logs/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/__init__.py index 83109a318d0..614dab24ce6 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/__init__.py @@ -38,6 +38,8 @@ Logger, LoggerProvider, LogRecord, + NoOpLogger, + NoOpLoggerProvider, get_logger, get_logger_provider, set_logger_provider, diff --git a/opentelemetry-api/tests/logs/test_logger_provider.py b/opentelemetry-api/tests/logs/test_logger_provider.py index 1f5bfd428e5..5943924bd8e 100644 --- a/opentelemetry-api/tests/logs/test_logger_provider.py +++ b/opentelemetry-api/tests/logs/test_logger_provider.py @@ -14,7 +14,6 @@ # type:ignore import unittest -from logging import WARNING from unittest.mock import Mock, patch import opentelemetry._logs._internal as logs_internal From 715e3720f19cd1a7cc7ceaf799e40c22b90d1553 Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Thu, 17 Nov 2022 10:47:06 -0800 Subject: [PATCH 09/28] shaq --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index aedcce541ae..a75f3576232 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ env: # Otherwise, set variable to the commit of your branch on # opentelemetry-python-contrib which is compatible with these Core repo # changes. - CONTRIB_REPO_SHA: 66edf69811e142c397d8500cafe6eddeb5565d6e + CONTRIB_REPO_SHA: c6134843900e2eeb1b8b3383a897b38cc0905c38 # This is needed because we do not clone the core repo in contrib builds anymore. # When running contrib builds as part of core builds, we use actions/checkout@v2 which # does not set an environment variable (simply just runs tox), which is different when From 78b95cedd7e212f26a64192725a46da9dce30e61 Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Thu, 17 Nov 2022 10:56:37 -0800 Subject: [PATCH 10/28] Update __init__.py --- opentelemetry-api/src/opentelemetry/_logs/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/opentelemetry-api/src/opentelemetry/_logs/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/__init__.py index 614dab24ce6..65d95d49f07 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/__init__.py @@ -50,6 +50,8 @@ "Logger", "LoggerProvider", "LogRecord", + "NoOpLogger", + "NoOpLoggerProvider", "SeverityNumber", "get_logger", "get_logger_provider", From 5f83f476ed597a6f4a82f7f6ea03d37bdcf29b7e Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Thu, 17 Nov 2022 11:46:21 -0800 Subject: [PATCH 11/28] logs --- .../src/opentelemetry/_logs/_internal/__init__.py | 6 +++--- .../src/opentelemetry/sdk/_logs/__init__.py | 12 +++++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py index 3eb60ec5358..3fb91e9231f 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py @@ -61,12 +61,12 @@ def get_logger( version: Optional[str] = None, schema_url: Optional[str] = None, ) -> "Logger": - """Returns a `Logger` for use by the given instrumentation library. + """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. + Logger instances are returned, even for different library names. - This function may return different `Logger` types (e.g. a no-op logger + This function may return different Logger types (e.g. a no-op logger vs. a functional logger). Args: diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py index ca48861c651..36ee405ea83 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py @@ -398,6 +398,11 @@ def __init__( ], instrumentation_scope: InstrumentationScope, ): + super().__init__( + instrumentation_scope.name, + instrumentation_scope.version, + instrumentation_scope.schema_url, + ) self._resource = resource self._multi_log_record_processor = multi_log_record_processor self._instrumentation_scope = instrumentation_scope @@ -442,14 +447,15 @@ def resource(self): def get_logger( self, - instrumenting_module_name: str, - instrumenting_module_version: str = "", + name: str, + version: Optional[str] = None, + schema_url: Optional[str] = None, ) -> Logger: return Logger( self._resource, self._multi_log_record_processor, InstrumentationScope( - instrumenting_module_name, instrumenting_module_version + name, version, schema_url, ), ) From ff8cb02b14c3c79576e7245c08456b2246437465 Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Thu, 17 Nov 2022 12:00:49 -0800 Subject: [PATCH 12/28] Create test_logs.py --- opentelemetry-sdk/tests/logs/test_logs.py | 59 +++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 opentelemetry-sdk/tests/logs/test_logs.py diff --git a/opentelemetry-sdk/tests/logs/test_logs.py b/opentelemetry-sdk/tests/logs/test_logs.py new file mode 100644 index 00000000000..cb764348ca4 --- /dev/null +++ b/opentelemetry-sdk/tests/logs/test_logs.py @@ -0,0 +1,59 @@ +# 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. + +# pylint: disable=protected-access + +import unittest + +from opentelemetry._logs import NoOpLogger +from opentelemetry.sdk._logs import LoggerProvider +from opentelemetry.sdk.resources import Resource + +class TestLoggerProvider(unittest.TestCase): + + def test_resource(self): + """ + `LoggerProvider` provides a way to allow a `Resource` to be specified. + """ + + logger_provider_0 = LoggerProvider() + logger_provider_1 = LoggerProvider() + + self.assertIs( + logger_provider_0.resource, + logger_provider_1.resource, + ) + self.assertIsInstance(logger_provider_0.resource, Resource) + self.assertIsInstance(logger_provider_1.resource, Resource) + + resource = Resource({"key": "value"}) + self.assertIs( + LoggerProvider(resource=resource).resource, resource + ) + + def test_get_logger(self): + """ + `LoggerProvider.get_logger` arguments are used to create an + `InstrumentationScope` object on the created `Logger`. + """ + + logger = LoggerProvider().get_logger( + "name", + version="version", + schema_url="schema_url", + ) + + self.assertEqual(logger._instrumentation_scope.name, "name") + self.assertEqual(logger._instrumentation_scope.version, "version") + self.assertEqual(logger._instrumentation_scope.schema_url, "schema_url") From eb311c44280d1cc5adddece32770c1fe58762f75 Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Thu, 17 Nov 2022 12:01:16 -0800 Subject: [PATCH 13/28] Update test_logs.py --- opentelemetry-sdk/tests/logs/test_logs.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/opentelemetry-sdk/tests/logs/test_logs.py b/opentelemetry-sdk/tests/logs/test_logs.py index cb764348ca4..0b8e4d457ac 100644 --- a/opentelemetry-sdk/tests/logs/test_logs.py +++ b/opentelemetry-sdk/tests/logs/test_logs.py @@ -54,6 +54,9 @@ def test_get_logger(self): schema_url="schema_url", ) - self.assertEqual(logger._instrumentation_scope.name, "name") - self.assertEqual(logger._instrumentation_scope.version, "version") - self.assertEqual(logger._instrumentation_scope.schema_url, "schema_url") + self.assertEqual( + logger._instrumentation_scope.name, "name") + self.assertEqual( + logger._instrumentation_scope.version, "version") + self.assertEqual( + logger._instrumentation_scope.schema_url, "schema_url") From 392cca43964f62691c62486a0fcbbb4053d59b03 Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Thu, 17 Nov 2022 12:10:28 -0800 Subject: [PATCH 14/28] lint --- .../src/opentelemetry/_logs/_internal/__init__.py | 2 +- opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py index 3fb91e9231f..fc6a985716c 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py @@ -51,7 +51,7 @@ class LoggerProvider(ABC): """ - LoggerProvider is the entry point of the API. It provides access to `Logger` instances. + LoggerProvider is the entry point of the API. It provides access to Logger instances. """ @abstractmethod diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py index 36ee405ea83..ed7dde67926 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py @@ -455,7 +455,9 @@ def get_logger( self._resource, self._multi_log_record_processor, InstrumentationScope( - name, version, schema_url, + name, + version, + schema_url, ), ) From 680052c4acded6b1c3ca2225793604802ce9e712 Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Thu, 17 Nov 2022 12:41:51 -0800 Subject: [PATCH 15/28] Update test_logs.py --- opentelemetry-sdk/tests/logs/test_logs.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/opentelemetry-sdk/tests/logs/test_logs.py b/opentelemetry-sdk/tests/logs/test_logs.py index 0b8e4d457ac..bc8c578ed12 100644 --- a/opentelemetry-sdk/tests/logs/test_logs.py +++ b/opentelemetry-sdk/tests/logs/test_logs.py @@ -16,10 +16,10 @@ import unittest -from opentelemetry._logs import NoOpLogger from opentelemetry.sdk._logs import LoggerProvider from opentelemetry.sdk.resources import Resource + class TestLoggerProvider(unittest.TestCase): def test_resource(self): @@ -30,10 +30,7 @@ def test_resource(self): logger_provider_0 = LoggerProvider() logger_provider_1 = LoggerProvider() - self.assertIs( - logger_provider_0.resource, - logger_provider_1.resource, - ) + self.assertIs(logger_provider_0.resource, logger_provider_1.resource,) self.assertIsInstance(logger_provider_0.resource, Resource) self.assertIsInstance(logger_provider_1.resource, Resource) @@ -54,9 +51,8 @@ def test_get_logger(self): schema_url="schema_url", ) + self.assertEqual(logger._instrumentation_scope.name, "name") + self.assertEqual(logger._instrumentation_scope.version, "version") self.assertEqual( - logger._instrumentation_scope.name, "name") - self.assertEqual( - logger._instrumentation_scope.version, "version") - self.assertEqual( - logger._instrumentation_scope.schema_url, "schema_url") + logger._instrumentation_scope.schema_url, "schema_url" + ) From dac61bcfbca765c658c84ed009e1c47aabc54efd Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Thu, 17 Nov 2022 13:39:01 -0800 Subject: [PATCH 16/28] Update __init__.py --- .../src/opentelemetry/_logs/_internal/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py index fc6a985716c..54c9fb103be 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py @@ -60,7 +60,7 @@ def get_logger( 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 @@ -97,7 +97,7 @@ def get_logger( 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) From a562310bd437a842e125ab8de360c2ea8831d7a7 Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Thu, 17 Nov 2022 16:49:55 -0800 Subject: [PATCH 17/28] Update __init__.py --- .../opentelemetry/_logs/_internal/__init__.py | 146 +++++++++--------- 1 file changed, 73 insertions(+), 73 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py index 54c9fb103be..89b65b0200f 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py @@ -49,6 +49,73 @@ _logger = getLogger(__name__) +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 + + +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 + + @abstractmethod + def emit_event(self, record: "LogRecord") -> None: + """Emits a :class:`LogRecord` representing an Event to the processing pipeline.""" + + @abstractmethod + def emit(self, record: "LogRecord") -> None: + """Emits a :class:`LogRecord` representing a log to the processing pipeline.""" + + +class NoOpLogger(Logger): + """The default Logger used when no Logger implementation is available. + + All operations are no-op. + """ + + def emit_event(self, record: "LogRecord") -> None: + pass + + def emit(self, record: "LogRecord") -> None: + pass + + class LoggerProvider(ABC): """ LoggerProvider is the entry point of the API. It provides access to Logger instances. @@ -60,13 +127,13 @@ def get_logger( name: str, version: Optional[str] = None, schema_url: Optional[str] = None, - ): - """Returns a Logger for use by the given instrumentation library. + ) -> "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. + `Logger` instances are returned, even for different library names. - This function may return different Logger types (e.g. a no-op logger + This function may return different `Logger` types (e.g. a no-op logger vs. a functional logger). Args: @@ -97,7 +164,7 @@ def get_logger( 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) @@ -106,73 +173,6 @@ def get_logger( # TODO: ProxyLoggerProvider -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 - - @abstractmethod - def emit_event(self, record: "LogRecord") -> None: - """Emits a :class:`LogRecord` representing an Event to the processing pipeline.""" - - @abstractmethod - def emit(self, record: "LogRecord") -> None: - """Emits a :class:`LogRecord` representing a log to the processing pipeline.""" - - -class NoOpLogger(Logger): - """The default Logger used when no Logger implementation is available. - - All operations are no-op. - """ - - def emit_event(self, record: "LogRecord") -> None: - pass - - def emit(self, record: "LogRecord") -> None: - pass - - -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 - - _LOGGER_PROVIDER_SET_ONCE = Once() _LOGGER_PROVIDER = None @@ -219,7 +219,7 @@ def get_logger( instrumenting_module_name: str, instrumenting_library_version: str = "", logger_provider: Optional[LoggerProvider] = None, -) -> Logger: +) -> "Logger": """Returns a `Logger` for use within a python process. This function is a convenience wrapper for From dc68579736d626cbcd13a4d50f84b03e788b390d Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Thu, 17 Nov 2022 17:03:58 -0800 Subject: [PATCH 18/28] logs --- .../src/opentelemetry/_logs/_internal/__init__.py | 6 +++--- opentelemetry-sdk/tests/logs/test_logs.py | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py index 89b65b0200f..41a73b87016 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py @@ -128,12 +128,12 @@ def get_logger( version: Optional[str] = None, schema_url: Optional[str] = None, ) -> "Logger": - """Returns a `Logger` for use by the given instrumentation library. + """Returns a 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. + instances are returned, even for different library names. - This function may return different `Logger` types (e.g. a no-op logger + This function may return different types (e.g. a no-op logger vs. a functional logger). Args: diff --git a/opentelemetry-sdk/tests/logs/test_logs.py b/opentelemetry-sdk/tests/logs/test_logs.py index bc8c578ed12..80a7d66f1cf 100644 --- a/opentelemetry-sdk/tests/logs/test_logs.py +++ b/opentelemetry-sdk/tests/logs/test_logs.py @@ -21,7 +21,6 @@ class TestLoggerProvider(unittest.TestCase): - def test_resource(self): """ `LoggerProvider` provides a way to allow a `Resource` to be specified. @@ -30,14 +29,15 @@ def test_resource(self): logger_provider_0 = LoggerProvider() logger_provider_1 = LoggerProvider() - self.assertIs(logger_provider_0.resource, logger_provider_1.resource,) + self.assertIs( + logger_provider_0.resource, + logger_provider_1.resource, + ) self.assertIsInstance(logger_provider_0.resource, Resource) self.assertIsInstance(logger_provider_1.resource, Resource) resource = Resource({"key": "value"}) - self.assertIs( - LoggerProvider(resource=resource).resource, resource - ) + self.assertIs(LoggerProvider(resource=resource).resource, resource) def test_get_logger(self): """ From b2cc0af11944f676f973067c8c00a4ea936f43ce Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Thu, 17 Nov 2022 17:21:27 -0800 Subject: [PATCH 19/28] Update __init__.py --- .../src/opentelemetry/_logs/_internal/__init__.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py index 41a73b87016..001abfd84e7 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py @@ -127,13 +127,13 @@ def get_logger( name: str, version: Optional[str] = None, schema_url: Optional[str] = None, - ) -> "Logger": - """Returns a for use by the given instrumentation library. + ) -> Logger: + """Returns a `Logger` for use by the given instrumentation library. For any two calls it is undefined whether the same or different - instances are returned, even for different library names. + `Logger` instances are returned, even for different library names. - This function may return different types (e.g. a no-op logger + This function may return different `Logger` types (e.g. a no-op logger vs. a functional logger). Args: @@ -164,7 +164,7 @@ def get_logger( name: str, version: Optional[str] = None, schema_url: Optional[str] = None, - ) -> "Logger": + ) -> Logger: """Returns a NoOpLogger.""" super().get_logger(name, version=version, schema_url=schema_url) return NoOpLogger(name, version=version, schema_url=schema_url) From 3e37593703e58a9a6a5c3a83a72e748a2db55ec7 Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Fri, 18 Nov 2022 09:39:29 -0800 Subject: [PATCH 20/28] docs --- docs/api/logs.rst | 28 ++++++++++++++-------------- docs/api/logs.severity.rst | 12 ++++++------ docs/sdk/index.rst | 2 +- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/docs/api/logs.rst b/docs/api/logs.rst index 3ad03d7af50..9c4c4210d86 100644 --- a/docs/api/logs.rst +++ b/docs/api/logs.rst @@ -1,22 +1,22 @@ -opentelemetry._logs package -=========================== +.. opentelemetry._logs package +.. =========================== -.. warning:: - OpenTelemetry Python logs are in an experimental state. The APIs within - :mod:`opentelemetry._logs` are subject to change in minor/patch releases and make no - backward compatibility guarantees at this time. +.. .. warning:: +.. OpenTelemetry Python logs are in an experimental state. The APIs within +.. :mod:`opentelemetry._logs` are subject to change in minor/patch releases and make no +.. backward compatibility guarantees at this time. - Once logs become stable, this package will be be renamed to ``opentelemetry.logs``. +.. Once logs become stable, this package will be be renamed to ``opentelemetry.logs``. -Submodules ----------- +.. Submodules +.. ---------- -.. toctree:: +.. .. toctree:: - logs.severity +.. logs.severity -Module contents ---------------- +.. Module contents +.. --------------- -.. automodule:: opentelemetry._logs +.. .. automodule:: opentelemetry._logs diff --git a/docs/api/logs.severity.rst b/docs/api/logs.severity.rst index 171331b2991..545a7d4920b 100644 --- a/docs/api/logs.severity.rst +++ b/docs/api/logs.severity.rst @@ -1,7 +1,7 @@ -opentelemetry._logs.severity -============================ +.. opentelemetry._logs.severity +.. ============================ -.. automodule:: opentelemetry._logs.severity - :members: - :undoc-members: - :show-inheritance: +.. .. automodule:: opentelemetry._logs.severity +.. :members: +.. :undoc-members: +.. :show-inheritance: diff --git a/docs/sdk/index.rst b/docs/sdk/index.rst index 47d49a55503..a1902380a98 100644 --- a/docs/sdk/index.rst +++ b/docs/sdk/index.rst @@ -9,6 +9,6 @@ OpenTelemetry Python SDK resources trace metrics - logs + .. logs error_handler environment_variables From 442453b2a83245c84fb63000060c18f0e7dca782 Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Fri, 18 Nov 2022 09:49:35 -0800 Subject: [PATCH 21/28] rename --- docs/api/index.rst | 2 +- docs/sdk/logs.rst | 34 +++++++++---------- .../src/opentelemetry/_logs/__init__.py | 17 +++------- .../opentelemetry/_logs/_internal/__init__.py | 8 ++--- .../src/opentelemetry/sdk/_logs/__init__.py | 4 +-- opentelemetry-sdk/tests/logs/test_handler.py | 18 +++++----- 6 files changed, 38 insertions(+), 45 deletions(-) diff --git a/docs/api/index.rst b/docs/api/index.rst index 0238b01053b..521b5fa94e8 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -8,7 +8,7 @@ OpenTelemetry Python API baggage context - logs + .. logs propagate propagators trace diff --git a/docs/sdk/logs.rst b/docs/sdk/logs.rst index b5febdc13e5..4d64dfdaa39 100644 --- a/docs/sdk/logs.rst +++ b/docs/sdk/logs.rst @@ -1,24 +1,24 @@ -opentelemetry.sdk._logs package -=============================== +.. opentelemetry.sdk._logs package +.. =============================== -.. warning:: - OpenTelemetry Python logs are in an experimental state. The APIs within - :mod:`opentelemetry.sdk._logs` are subject to change in minor/patch releases and make no - backward compatibility guarantees at this time. +.. .. warning:: +.. OpenTelemetry Python logs are in an experimental state. The APIs within +.. :mod:`opentelemetry.sdk._logs` are subject to change in minor/patch releases and make no +.. backward compatibility guarantees at this time. - Once logs become stable, this package will be be renamed to ``opentelemetry.sdk.logs``. +.. Once logs become stable, this package will be be renamed to ``opentelemetry.sdk.logs``. -Submodules ----------- +.. Submodules +.. ---------- -.. toctree:: +.. .. toctree:: - logs.export +.. logs.export -Module contents ---------------- +.. Module contents +.. --------------- -.. automodule:: opentelemetry.sdk._logs - :members: - :undoc-members: - :show-inheritance: +.. .. automodule:: opentelemetry.sdk._logs +.. :members: +.. :undoc-members: +.. :show-inheritance: diff --git a/opentelemetry-api/src/opentelemetry/_logs/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/__init__.py index 65d95d49f07..68366ddc53a 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/__init__.py @@ -46,15 +46,8 @@ ) from opentelemetry._logs.severity import SeverityNumber, std_to_otel -__all__ = [ - "Logger", - "LoggerProvider", - "LogRecord", - "NoOpLogger", - "NoOpLoggerProvider", - "SeverityNumber", - "get_logger", - "get_logger_provider", - "set_logger_provider", - "std_to_otel", -] +__all__ = [] +for key, value in globals().copy().items(): + if not key.startswith("_"): + value.__module__ = __name__ + __all__.append(key) diff --git a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py index 001abfd84e7..721c7ce6a94 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py @@ -34,9 +34,9 @@ .. versionadded:: 1.15.0 """ -import os 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 @@ -99,7 +99,7 @@ def emit_event(self, record: "LogRecord") -> None: """Emits a :class:`LogRecord` representing an Event to the processing pipeline.""" @abstractmethod - def emit(self, record: "LogRecord") -> None: + def emit_log(self, record: "LogRecord") -> None: """Emits a :class:`LogRecord` representing a log to the processing pipeline.""" @@ -112,7 +112,7 @@ class NoOpLogger(Logger): def emit_event(self, record: "LogRecord") -> None: pass - def emit(self, record: "LogRecord") -> None: + def emit_log(self, record: "LogRecord") -> None: pass @@ -181,7 +181,7 @@ 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 os.environ.keys(): + if _OTEL_PYTHON_LOGGER_PROVIDER not in environ.keys(): # TODO: return proxy _LOGGER_PROVIDER = NoOpLoggerProvider() return _LOGGER_PROVIDER diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py index ed7dde67926..5af5501e16f 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py @@ -379,7 +379,7 @@ def emit(self, record: logging.LogRecord) -> None: The record is translated to OTLP format, and then sent across the pipeline. """ - self._logger.emit(self._translate(record)) + self._logger.emit_log(self._translate(record)) def flush(self) -> None: """ @@ -411,7 +411,7 @@ def __init__( def resource(self): return self._resource - def emit(self, record: LogRecord): + def emit_log(self, record: LogRecord): """Emits the :class:`LogData` by associating :class:`LogRecord` and instrumentation info. """ diff --git a/opentelemetry-sdk/tests/logs/test_handler.py b/opentelemetry-sdk/tests/logs/test_handler.py index b9c40608e14..a11caea8ed4 100644 --- a/opentelemetry-sdk/tests/logs/test_handler.py +++ b/opentelemetry-sdk/tests/logs/test_handler.py @@ -39,10 +39,10 @@ def test_handler_default_log_level(self): logger = get_logger(logger_provider=emitter_provider_mock) # Make sure debug messages are ignored by default logger.debug("Debug message") - self.assertEqual(emitter_mock.emit.call_count, 0) + self.assertEqual(emitter_mock.emit_log.call_count, 0) # Assert emit gets called for warning message logger.warning("Warning message") - self.assertEqual(emitter_mock.emit.call_count, 1) + self.assertEqual(emitter_mock.emit_log.call_count, 1) def test_handler_custom_log_level(self): emitter_provider_mock = Mock(spec=LoggerProvider) @@ -54,10 +54,10 @@ def test_handler_custom_log_level(self): ) logger.warning("Warning message test custom log level") # Make sure any log with level < ERROR is ignored - self.assertEqual(emitter_mock.emit.call_count, 0) + self.assertEqual(emitter_mock.emit_log.call_count, 0) logger.error("Mumbai, we have a major problem") logger.critical("No Time For Caution") - self.assertEqual(emitter_mock.emit.call_count, 2) + self.assertEqual(emitter_mock.emit_log.call_count, 2) def test_log_record_no_span_context(self): emitter_provider_mock = Mock(spec=LoggerProvider) @@ -67,7 +67,7 @@ def test_log_record_no_span_context(self): logger = get_logger(logger_provider=emitter_provider_mock) # Assert emit gets called for warning message logger.warning("Warning message") - args, _ = emitter_mock.emit.call_args_list[0] + args, _ = emitter_mock.emit_log.call_args_list[0] log_record = args[0] self.assertIsNotNone(log_record) @@ -86,7 +86,7 @@ def test_log_record_user_attributes(self): logger = get_logger(logger_provider=emitter_provider_mock) # Assert emit gets called for warning message logger.warning("Warning message", extra={"http.status_code": 200}) - args, _ = emitter_mock.emit.call_args_list[0] + args, _ = emitter_mock.emit_log.call_args_list[0] log_record = args[0] self.assertIsNotNone(log_record) @@ -103,7 +103,7 @@ def test_log_record_exception(self): raise ZeroDivisionError("division by zero") except ZeroDivisionError: logger.exception("Zero Division Error") - args, _ = emitter_mock.emit.call_args_list[0] + args, _ = emitter_mock.emit_log.call_args_list[0] log_record = args[0] self.assertIsNotNone(log_record) @@ -136,7 +136,7 @@ def test_log_exc_info_false(self): raise ZeroDivisionError("division by zero") except ZeroDivisionError: logger.error("Zero Division Error", exc_info=False) - args, _ = emitter_mock.emit.call_args_list[0] + args, _ = emitter_mock.emit_log.call_args_list[0] log_record = args[0] self.assertIsNotNone(log_record) @@ -160,7 +160,7 @@ def test_log_record_trace_correlation(self): with tracer.start_as_current_span("test") as span: logger.critical("Critical message within span") - args, _ = emitter_mock.emit.call_args_list[0] + args, _ = emitter_mock.emit_log.call_args_list[0] log_record = args[0] self.assertEqual(log_record.body, "Critical message within span") self.assertEqual(log_record.severity_text, "CRITICAL") From c3a3bb79b9b8f0f824b27b148c182d35f657bb4e Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Fri, 18 Nov 2022 10:58:05 -0800 Subject: [PATCH 22/28] emit --- docs/api/index.rst | 1 - docs/sdk/index.rst | 1 - .../opentelemetry/_logs/_internal/__init__.py | 4 ++-- .../src/opentelemetry/sdk/_logs/__init__.py | 6 +++--- opentelemetry-sdk/tests/logs/test_handler.py | 18 +++++++++--------- 5 files changed, 14 insertions(+), 16 deletions(-) diff --git a/docs/api/index.rst b/docs/api/index.rst index 521b5fa94e8..22d77fc5a08 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -8,7 +8,6 @@ OpenTelemetry Python API baggage context - .. logs propagate propagators trace diff --git a/docs/sdk/index.rst b/docs/sdk/index.rst index a1902380a98..4c1cf22fff4 100644 --- a/docs/sdk/index.rst +++ b/docs/sdk/index.rst @@ -9,6 +9,5 @@ OpenTelemetry Python SDK resources trace metrics - .. logs error_handler environment_variables diff --git a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py index 721c7ce6a94..ae6fcebb70d 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py @@ -99,7 +99,7 @@ def emit_event(self, record: "LogRecord") -> None: """Emits a :class:`LogRecord` representing an Event to the processing pipeline.""" @abstractmethod - def emit_log(self, record: "LogRecord") -> None: + def emit(self, record: "LogRecord") -> None: """Emits a :class:`LogRecord` representing a log to the processing pipeline.""" @@ -112,7 +112,7 @@ class NoOpLogger(Logger): def emit_event(self, record: "LogRecord") -> None: pass - def emit_log(self, record: "LogRecord") -> None: + def emit(self, record: "LogRecord") -> None: pass diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py index 5af5501e16f..e43a6196651 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py @@ -377,9 +377,9 @@ def emit(self, record: logging.LogRecord) -> None: """ Emit a record. - The record is translated to OTLP format, and then sent across the pipeline. + The record is translated to OTel format, and then sent across the pipeline. """ - self._logger.emit_log(self._translate(record)) + self._logger.emit(self._translate(record)) def flush(self) -> None: """ @@ -411,7 +411,7 @@ def __init__( def resource(self): return self._resource - def emit_log(self, record: LogRecord): + def emit(self, record: LogRecord): """Emits the :class:`LogData` by associating :class:`LogRecord` and instrumentation info. """ diff --git a/opentelemetry-sdk/tests/logs/test_handler.py b/opentelemetry-sdk/tests/logs/test_handler.py index a11caea8ed4..b9c40608e14 100644 --- a/opentelemetry-sdk/tests/logs/test_handler.py +++ b/opentelemetry-sdk/tests/logs/test_handler.py @@ -39,10 +39,10 @@ def test_handler_default_log_level(self): logger = get_logger(logger_provider=emitter_provider_mock) # Make sure debug messages are ignored by default logger.debug("Debug message") - self.assertEqual(emitter_mock.emit_log.call_count, 0) + self.assertEqual(emitter_mock.emit.call_count, 0) # Assert emit gets called for warning message logger.warning("Warning message") - self.assertEqual(emitter_mock.emit_log.call_count, 1) + self.assertEqual(emitter_mock.emit.call_count, 1) def test_handler_custom_log_level(self): emitter_provider_mock = Mock(spec=LoggerProvider) @@ -54,10 +54,10 @@ def test_handler_custom_log_level(self): ) logger.warning("Warning message test custom log level") # Make sure any log with level < ERROR is ignored - self.assertEqual(emitter_mock.emit_log.call_count, 0) + self.assertEqual(emitter_mock.emit.call_count, 0) logger.error("Mumbai, we have a major problem") logger.critical("No Time For Caution") - self.assertEqual(emitter_mock.emit_log.call_count, 2) + self.assertEqual(emitter_mock.emit.call_count, 2) def test_log_record_no_span_context(self): emitter_provider_mock = Mock(spec=LoggerProvider) @@ -67,7 +67,7 @@ def test_log_record_no_span_context(self): logger = get_logger(logger_provider=emitter_provider_mock) # Assert emit gets called for warning message logger.warning("Warning message") - args, _ = emitter_mock.emit_log.call_args_list[0] + args, _ = emitter_mock.emit.call_args_list[0] log_record = args[0] self.assertIsNotNone(log_record) @@ -86,7 +86,7 @@ def test_log_record_user_attributes(self): logger = get_logger(logger_provider=emitter_provider_mock) # Assert emit gets called for warning message logger.warning("Warning message", extra={"http.status_code": 200}) - args, _ = emitter_mock.emit_log.call_args_list[0] + args, _ = emitter_mock.emit.call_args_list[0] log_record = args[0] self.assertIsNotNone(log_record) @@ -103,7 +103,7 @@ def test_log_record_exception(self): raise ZeroDivisionError("division by zero") except ZeroDivisionError: logger.exception("Zero Division Error") - args, _ = emitter_mock.emit_log.call_args_list[0] + args, _ = emitter_mock.emit.call_args_list[0] log_record = args[0] self.assertIsNotNone(log_record) @@ -136,7 +136,7 @@ def test_log_exc_info_false(self): raise ZeroDivisionError("division by zero") except ZeroDivisionError: logger.error("Zero Division Error", exc_info=False) - args, _ = emitter_mock.emit_log.call_args_list[0] + args, _ = emitter_mock.emit.call_args_list[0] log_record = args[0] self.assertIsNotNone(log_record) @@ -160,7 +160,7 @@ def test_log_record_trace_correlation(self): with tracer.start_as_current_span("test") as span: logger.critical("Critical message within span") - args, _ = emitter_mock.emit_log.call_args_list[0] + args, _ = emitter_mock.emit.call_args_list[0] log_record = args[0] self.assertEqual(log_record.body, "Critical message within span") self.assertEqual(log_record.severity_text, "CRITICAL") From 01925acdd5252a179b143ba210d63353d5c7ab93 Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Fri, 18 Nov 2022 11:06:09 -0800 Subject: [PATCH 23/28] lint --- docs/api/logs.rst | 22 ----------------- docs/api/logs.severity.rst | 7 ------ docs/sdk/logs.export.rst | 7 ------ docs/sdk/logs.rst | 24 ------------------- .../src/opentelemetry/_logs/__init__.py | 2 ++ .../opentelemetry/_logs/_internal/__init__.py | 2 +- 6 files changed, 3 insertions(+), 61 deletions(-) delete mode 100644 docs/api/logs.rst delete mode 100644 docs/api/logs.severity.rst delete mode 100644 docs/sdk/logs.export.rst delete mode 100644 docs/sdk/logs.rst diff --git a/docs/api/logs.rst b/docs/api/logs.rst deleted file mode 100644 index 9c4c4210d86..00000000000 --- a/docs/api/logs.rst +++ /dev/null @@ -1,22 +0,0 @@ -.. opentelemetry._logs package -.. =========================== - -.. .. warning:: -.. OpenTelemetry Python logs are in an experimental state. The APIs within -.. :mod:`opentelemetry._logs` are subject to change in minor/patch releases and make no -.. backward compatibility guarantees at this time. - -.. Once logs become stable, this package will be be renamed to ``opentelemetry.logs``. - -.. Submodules -.. ---------- - -.. .. toctree:: - -.. logs.severity - - -.. Module contents -.. --------------- - -.. .. automodule:: opentelemetry._logs diff --git a/docs/api/logs.severity.rst b/docs/api/logs.severity.rst deleted file mode 100644 index 545a7d4920b..00000000000 --- a/docs/api/logs.severity.rst +++ /dev/null @@ -1,7 +0,0 @@ -.. opentelemetry._logs.severity -.. ============================ - -.. .. automodule:: opentelemetry._logs.severity -.. :members: -.. :undoc-members: -.. :show-inheritance: diff --git a/docs/sdk/logs.export.rst b/docs/sdk/logs.export.rst deleted file mode 100644 index 19a40237424..00000000000 --- a/docs/sdk/logs.export.rst +++ /dev/null @@ -1,7 +0,0 @@ -opentelemetry.sdk._logs.export -============================== - -.. automodule:: opentelemetry.sdk._logs.export - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/sdk/logs.rst b/docs/sdk/logs.rst deleted file mode 100644 index 4d64dfdaa39..00000000000 --- a/docs/sdk/logs.rst +++ /dev/null @@ -1,24 +0,0 @@ -.. opentelemetry.sdk._logs package -.. =============================== - -.. .. warning:: -.. OpenTelemetry Python logs are in an experimental state. The APIs within -.. :mod:`opentelemetry.sdk._logs` are subject to change in minor/patch releases and make no -.. backward compatibility guarantees at this time. - -.. Once logs become stable, this package will be be renamed to ``opentelemetry.sdk.logs``. - -.. Submodules -.. ---------- - -.. .. toctree:: - -.. logs.export - -.. Module contents -.. --------------- - -.. .. automodule:: opentelemetry.sdk._logs -.. :members: -.. :undoc-members: -.. :show-inheritance: diff --git a/opentelemetry-api/src/opentelemetry/_logs/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/__init__.py index 68366ddc53a..b973c294ec8 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/__init__.py @@ -34,6 +34,8 @@ .. versionadded:: 1.15.0 """ +# pylint: disable=unused-import + from opentelemetry._logs._internal import ( Logger, LoggerProvider, diff --git a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py index ae6fcebb70d..9e98c89ef6d 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py @@ -66,7 +66,7 @@ def __init__( trace_flags: Optional["TraceFlags"] = None, severity_text: Optional[str] = None, severity_number: Optional[SeverityNumber] = None, - body: Optional[Any] = None, + body: Optional[Any] = None, # type: ignore attributes: Optional["Attributes"] = None, ): self.timestamp = timestamp From 577b159842cfdb7aafee441d0fba5f3f40a75448 Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Fri, 18 Nov 2022 11:18:39 -0800 Subject: [PATCH 24/28] lint --- docs/api/_logs.rst | 14 ++++++++++++++ docs/api/_logs.severity.rst | 4 ++++ docs/api/index.rst | 1 + docs/sdk/_logs.rst | 7 +++++++ docs/sdk/index.rst | 1 + .../src/opentelemetry/_logs/__init__.py | 5 +++-- .../src/opentelemetry/_logs/_internal/__init__.py | 2 +- 7 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 docs/api/_logs.rst create mode 100644 docs/api/_logs.severity.rst create mode 100644 docs/sdk/_logs.rst diff --git a/docs/api/_logs.rst b/docs/api/_logs.rst new file mode 100644 index 00000000000..85ae72dc0d4 --- /dev/null +++ b/docs/api/_logs.rst @@ -0,0 +1,14 @@ +opentelemetry._logs package +============================= + +Submodules +---------- + +.. toctree:: + + _logs.severity + +Module contents +--------------- + +.. automodule:: opentelemetry._logs diff --git a/docs/api/_logs.severity.rst b/docs/api/_logs.severity.rst new file mode 100644 index 00000000000..4e31e70cf88 --- /dev/null +++ b/docs/api/_logs.severity.rst @@ -0,0 +1,4 @@ +opentelemetry._logs.severity +============================ + +.. automodule:: opentelemetry._logs.severity \ No newline at end of file diff --git a/docs/api/index.rst b/docs/api/index.rst index 22d77fc5a08..c1dffd6e75d 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -6,6 +6,7 @@ OpenTelemetry Python API .. toctree:: :maxdepth: 1 + _logs baggage context propagate diff --git a/docs/sdk/_logs.rst b/docs/sdk/_logs.rst new file mode 100644 index 00000000000..185e7006e40 --- /dev/null +++ b/docs/sdk/_logs.rst @@ -0,0 +1,7 @@ +opentelemetry.sdk._logs package +=============================== + +.. automodule:: opentelemetry.sdk._logs + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sdk/index.rst b/docs/sdk/index.rst index 4c1cf22fff4..d5d3688443f 100644 --- a/docs/sdk/index.rst +++ b/docs/sdk/index.rst @@ -6,6 +6,7 @@ OpenTelemetry Python SDK .. toctree:: :maxdepth: 1 + _logs resources trace metrics diff --git a/opentelemetry-api/src/opentelemetry/_logs/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/__init__.py index b973c294ec8..17e3638e5bc 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/__init__.py @@ -35,8 +35,9 @@ """ # pylint: disable=unused-import +# type: ignore -from opentelemetry._logs._internal import ( +from opentelemetry._logs._internal import ( # noqa: F401 Logger, LoggerProvider, LogRecord, @@ -46,7 +47,7 @@ get_logger_provider, set_logger_provider, ) -from opentelemetry._logs.severity import SeverityNumber, std_to_otel +from opentelemetry._logs.severity import SeverityNumber, std_to_otel # noqa: F401 __all__ = [] for key, value in globals().copy().items(): diff --git a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py index 9e98c89ef6d..ae6fcebb70d 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py @@ -66,7 +66,7 @@ def __init__( trace_flags: Optional["TraceFlags"] = None, severity_text: Optional[str] = None, severity_number: Optional[SeverityNumber] = None, - body: Optional[Any] = None, # type: ignore + body: Optional[Any] = None, attributes: Optional["Attributes"] = None, ): self.timestamp = timestamp From 1a2194481863c3ced14b98025183c52b83fe7227 Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Fri, 18 Nov 2022 11:23:29 -0800 Subject: [PATCH 25/28] lint --- opentelemetry-api/src/opentelemetry/_logs/__init__.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/_logs/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/__init__.py index 17e3638e5bc..df3017abbc4 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/__init__.py @@ -35,7 +35,6 @@ """ # pylint: disable=unused-import -# type: ignore from opentelemetry._logs._internal import ( # noqa: F401 Logger, @@ -47,10 +46,13 @@ get_logger_provider, set_logger_provider, ) -from opentelemetry._logs.severity import SeverityNumber, std_to_otel # noqa: F401 +from opentelemetry._logs.severity import ( + SeverityNumber, + std_to_otel, + ) # noqa: F401 __all__ = [] -for key, value in globals().copy().items(): +for key, value in globals().copy().items(): # type: ignore if not key.startswith("_"): value.__module__ = __name__ __all__.append(key) From c3ba6a0f50dcb85a5133f22798512216ea6993dd Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Fri, 18 Nov 2022 11:28:01 -0800 Subject: [PATCH 26/28] lint --- opentelemetry-api/src/opentelemetry/_logs/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/_logs/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/__init__.py index df3017abbc4..22b8aecc909 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/__init__.py @@ -49,10 +49,10 @@ from opentelemetry._logs.severity import ( SeverityNumber, std_to_otel, - ) # noqa: F401 +) # noqa: F401 __all__ = [] for key, value in globals().copy().items(): # type: ignore if not key.startswith("_"): - value.__module__ = __name__ + value.__module__ = __name__ # type: ignore __all__.append(key) From 5d24feee246b7a25637c91ef1e25274afb09cf2f Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Fri, 18 Nov 2022 11:36:36 -0800 Subject: [PATCH 27/28] Update __init__.py --- opentelemetry-api/src/opentelemetry/_logs/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/_logs/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/__init__.py index 22b8aecc909..d9677a5f220 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/__init__.py @@ -46,10 +46,10 @@ get_logger_provider, set_logger_provider, ) -from opentelemetry._logs.severity import ( +from opentelemetry._logs.severity import ( # noqa: F401 SeverityNumber, std_to_otel, -) # noqa: F401 +) __all__ = [] for key, value in globals().copy().items(): # type: ignore From 6d6694f0a52c2cd049482eb10dd8de7d0aec7f05 Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Mon, 28 Nov 2022 11:24:16 -0800 Subject: [PATCH 28/28] logs --- CHANGELOG.md | 2 +- .../src/opentelemetry/_logs/_internal/__init__.py | 7 ------- opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py | 4 ---- 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1aa1edbf508..ce497bbc6aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add missing entry points for OTLP/HTTP exporter ([#3027](https://github.com/open-telemetry/opentelemetry-python/pull/3027)) -- Implement logging API +- Update logging to include logging api as per specification ([#3038](https://github.com/open-telemetry/opentelemetry-python/pull/3038)) ## Version 1.14.0/0.35b0 (2022-11-04) diff --git a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py index ae6fcebb70d..0b844e24d9a 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py @@ -94,10 +94,6 @@ def __init__( self._version = version self._schema_url = schema_url - @abstractmethod - def emit_event(self, record: "LogRecord") -> None: - """Emits a :class:`LogRecord` representing an Event to the processing pipeline.""" - @abstractmethod def emit(self, record: "LogRecord") -> None: """Emits a :class:`LogRecord` representing a log to the processing pipeline.""" @@ -109,9 +105,6 @@ class NoOpLogger(Logger): All operations are no-op. """ - def emit_event(self, record: "LogRecord") -> None: - pass - def emit(self, record: "LogRecord") -> None: pass diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py index e43a6196651..83cef931491 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py @@ -418,10 +418,6 @@ def emit(self, record: LogRecord): log_data = LogData(record, self._instrumentation_scope) self._multi_log_record_processor.emit(log_data) - def emit_event(self, record: LogRecord): - # TODO - pass - class LoggerProvider(APILoggerProvider): def __init__(