fed8b2eed7
Backend release / release (push) Waiting to run
Bandit Security Scan / bandit_scan (push) Waiting to run
Build and push multi-arch DocsGPT Docker image / build (linux/amd64, ubuntu-latest, amd64) (push) Waiting to run
Build and push multi-arch DocsGPT Docker image / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Waiting to run
Build and push multi-arch DocsGPT Docker image / manifest (push) Blocked by required conditions
Build and push DocsGPT FE Docker image for development / build (linux/amd64, ubuntu-latest, amd64) (push) Waiting to run
Build and push DocsGPT FE Docker image for development / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Waiting to run
Build and push DocsGPT FE Docker image for development / manifest (push) Blocked by required conditions
Python linting / ruff (push) Waiting to run
Run python tests with pytest / Run tests and count coverage (3.12) (push) Waiting to run
React Widget Build / build (push) Waiting to run
105 lines
3.5 KiB
Python
105 lines
3.5 KiB
Python
"""Tests for setup_logging — in particular the OTEL log-handler hand-off.
|
|
|
|
`opentelemetry-instrument` attaches an OTEL `LoggingHandler` to the root
|
|
logger before our module-level `setup_logging()` runs in `application/app.py`.
|
|
The default `dictConfig` call replaces `root.handlers`, which would silently
|
|
drop the OTEL handler. setup_logging snapshots and re-attaches OTEL handlers
|
|
when OTLP log export is enabled.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
import sys
|
|
import types
|
|
|
|
import pytest
|
|
|
|
from application.core.logging_config import setup_logging
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _reset_root_logger():
|
|
"""Snapshot/restore the root logger so tests don't leak handlers."""
|
|
root = logging.getLogger()
|
|
saved_handlers = list(root.handlers)
|
|
saved_level = root.level
|
|
yield
|
|
root.handlers = saved_handlers
|
|
root.setLevel(saved_level)
|
|
|
|
|
|
def _make_fake_otel_handler() -> logging.Handler:
|
|
"""Build a Handler whose class lives in a module starting with 'opentelemetry'.
|
|
|
|
Mirrors how the real `opentelemetry.sdk._logs.LoggingHandler` would be
|
|
detected without needing the OTEL SDK installed in the test env.
|
|
"""
|
|
fake_module = types.ModuleType("opentelemetry.fake_sdk._logs")
|
|
sys.modules.setdefault(fake_module.__name__, fake_module)
|
|
|
|
class FakeOtelHandler(logging.Handler):
|
|
pass
|
|
|
|
FakeOtelHandler.__module__ = fake_module.__name__
|
|
return FakeOtelHandler()
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestSetupLogging:
|
|
|
|
def test_default_keeps_only_console_handler(self, monkeypatch):
|
|
monkeypatch.delenv("OTEL_LOGS_EXPORTER", raising=False)
|
|
monkeypatch.delenv("OTEL_SDK_DISABLED", raising=False)
|
|
logging.getLogger().handlers = []
|
|
|
|
setup_logging()
|
|
|
|
handlers = logging.getLogger().handlers
|
|
assert len(handlers) == 1
|
|
assert isinstance(handlers[0], logging.StreamHandler)
|
|
|
|
def test_preserves_otel_handler_when_otlp_logs_enabled(self, monkeypatch):
|
|
monkeypatch.setenv("OTEL_LOGS_EXPORTER", "otlp")
|
|
monkeypatch.delenv("OTEL_SDK_DISABLED", raising=False)
|
|
|
|
otel_handler = _make_fake_otel_handler()
|
|
logging.getLogger().handlers = [otel_handler]
|
|
|
|
setup_logging()
|
|
|
|
handlers = logging.getLogger().handlers
|
|
assert otel_handler in handlers, (
|
|
"OTEL handler must survive setup_logging when OTLP log export is on"
|
|
)
|
|
assert any(
|
|
isinstance(h, logging.StreamHandler) and not isinstance(h, type(otel_handler))
|
|
for h in handlers
|
|
), "console handler should still be installed alongside the OTEL handler"
|
|
|
|
def test_does_not_preserve_when_sdk_disabled(self, monkeypatch):
|
|
monkeypatch.setenv("OTEL_LOGS_EXPORTER", "otlp")
|
|
monkeypatch.setenv("OTEL_SDK_DISABLED", "true")
|
|
|
|
otel_handler = _make_fake_otel_handler()
|
|
logging.getLogger().handlers = [otel_handler]
|
|
|
|
setup_logging()
|
|
|
|
handlers = logging.getLogger().handlers
|
|
assert otel_handler not in handlers, (
|
|
"When OTEL_SDK_DISABLED=true the handler should not be preserved"
|
|
)
|
|
|
|
def test_does_not_preserve_when_logs_exporter_unset(self, monkeypatch):
|
|
monkeypatch.delenv("OTEL_LOGS_EXPORTER", raising=False)
|
|
monkeypatch.delenv("OTEL_SDK_DISABLED", raising=False)
|
|
|
|
otel_handler = _make_fake_otel_handler()
|
|
logging.getLogger().handlers = [otel_handler]
|
|
|
|
setup_logging()
|
|
|
|
handlers = logging.getLogger().handlers
|
|
assert otel_handler not in handlers
|