diff --git a/benchmarks/README.md b/benchmarks/README.md index 297d562..728ee71 100644 --- a/benchmarks/README.md +++ b/benchmarks/README.md @@ -619,7 +619,8 @@ record per MCP message), FastStream's own "Received" and "Processed" (filtered a Linux, a 2-CPU container on the same Apple M2 under OrbStack, CPython 3.14.9, structlog 26.1.0, orjson 3.11.9, sentry-sdk 2.67.1, opentelemetry-sdk 1.44.0. Output to a real `/dev/null` file, -50000 calls per round, loop overhead (0.06 µs) subtracted. +50000 calls per round, loop overhead (0.06 µs) subtracted. The `MemoryHandler` was removed afterwards +(#377), and 2.0 writes through the `StreamHandler` directly; the rows have not been rerun. | call | µs/call | |---|---:| @@ -627,7 +628,6 @@ orjson 3.11.9, sentry-sdk 2.67.1, opentelemetry-sdk 1.44.0. Output to a real `/d | same with 5 keyword values | 10.4 | | `log.debug(...)` at INFO, filtered | 1.1 | | info, JSON through stdlib `json` (the fallback without orjson) | 11.5 | -| info, `logging_buffer_capacity=1` | 10.5 | | info inside a recording OpenTelemetry span | 10.7 | | info with Sentry's LoggingIntegration, breadcrumb level INFO (default) | 15.7 | | info with Sentry, `sentry_logging_breadcrumb_level=None` | 10.5 | diff --git a/benchmarks/frameworks/logging_suite.py b/benchmarks/frameworks/logging_suite.py index 966fb4e..981a572 100644 --- a/benchmarks/frameworks/logging_suite.py +++ b/benchmarks/frameworks/logging_suite.py @@ -28,7 +28,6 @@ class LogScenario: span: bool = False native: bool = False stdlib_json: bool = False - buffer_capacity: int = 10 SCENARIOS: typing.Final = { @@ -37,7 +36,6 @@ class LogScenario: "info_kw5": LogScenario(call="info_kw5"), "debug_filtered": LogScenario(call="debug"), "info_stdjson": LogScenario(call="info", stdlib_json=True), - "info_capacity1": LogScenario(call="info", buffer_capacity=1), "info_span": LogScenario(call="info", span=True), "info_sentry": LogScenario(call="info", sentry={}), "info_sentry_nocrumb": LogScenario(call="info", sentry={"sentry_logging_breadcrumb_level": None}), @@ -113,7 +111,7 @@ def setup(scenario: LogScenario) -> list[typing.Callable[[], object]]: configure_native(devnull_bytes) elif scenario.call != "noop": with contextlib.redirect_stdout(devnull): - config = LoggingConfig(logging_enabled=True, logging_buffer_capacity=scenario.buffer_capacity) + config = LoggingConfig(logging_enabled=True) LoggingInstrument(bootstrap_config=config).bootstrap() if scenario.sentry is not None: diff --git a/docs/integrations/fastmcp.md b/docs/integrations/fastmcp.md index d2416d2..8b21989 100644 --- a/docs/integrations/fastmcp.md +++ b/docs/integrations/fastmcp.md @@ -36,7 +36,6 @@ bootstrapper_config = FastMcpConfig( sentry_dsn="https://testdsn@localhost/1", prometheus_metrics_path="/custom-metrics/", health_checks_path="/custom-health/", - logging_buffer_capacity=0, ) bootstrapper = FastMcpBootstrapper(bootstrap_config=bootstrapper_config) application: FastMCP = bootstrapper.bootstrap() diff --git a/docs/integrations/faststream.md b/docs/integrations/faststream.md index 5d8b819..e6ef526 100644 --- a/docs/integrations/faststream.md +++ b/docs/integrations/faststream.md @@ -43,7 +43,6 @@ bootstrapper_config = FastStreamConfig( prometheus_middleware_cls=RedisPrometheusMiddleware, sentry_dsn="https://testdsn@localhost/1", health_checks_path="/custom-health/", - logging_buffer_capacity=0, application=AsgiFastStream(broker), ) bootstrapper = FastStreamBootstrapper(bootstrapper_config) diff --git a/docs/introduction/configuration.md b/docs/introduction/configuration.md index 22316d6..5ede1fb 100644 --- a/docs/introduction/configuration.md +++ b/docs/introduction/configuration.md @@ -352,8 +352,6 @@ Additional parameters: - `logging_enabled` - whether to configure structlog (default: `True`). - `logging_log_level` -- `logging_flush_level` -- `logging_buffer_capacity` - `logging_extra_processors` - `logging_unset_handlers` - `logging_record_filters` - standard-library `logging.Filter` instances to attach to named loggers (see below). diff --git a/lite_bootstrap/instruments/logging_factory.py b/lite_bootstrap/instruments/logging_factory.py index 8ce9da3..4341a86 100644 --- a/lite_bootstrap/instruments/logging_factory.py +++ b/lite_bootstrap/instruments/logging_factory.py @@ -1,7 +1,6 @@ import dataclasses import json import logging -import logging.handlers import sys import typing @@ -14,8 +13,6 @@ @dataclasses.dataclass(kw_only=True, slots=True, frozen=True) class _MemoryLoggerFactoryConfig: - logging_buffer_capacity: int - logging_flush_level: int logging_log_level: int # default_factory, not a bare default: a bare one binds sys.stdout at import time, so a # process that rebinds stdout before bootstrap would keep logging to the stale stream. @@ -102,20 +99,15 @@ def __init__( kwargs["ignore_frame_names"] = [*(kwargs.get("ignore_frame_names") or ()), __name__] super().__init__(*args, **kwargs) self.config = config - self._created_handlers: dict[logging.Logger, logging.handlers.MemoryHandler] = {} + self._created_handlers: dict[logging.Logger, logging.StreamHandler[typing.Any]] = {} self._leveled_loggers: set[logging.Logger] = set() def __call__(self, *args: typing.Any) -> logging.Logger: # noqa: ANN401 logger: typing.Final = super().__call__(*args) if logger in self._created_handlers: return logger - stream_handler: typing.Final = logging.StreamHandler(stream=self.config.log_stream) - stream_handler.setFormatter(_RenderedLineFormatter()) - handler: typing.Final = logging.handlers.MemoryHandler( - capacity=self.config.logging_buffer_capacity, - flushLevel=self.config.logging_flush_level, - target=stream_handler, - ) + handler: typing.Final = logging.StreamHandler(stream=self.config.log_stream) + handler.setFormatter(_RenderedLineFormatter()) logger.addHandler(handler) if logger.level == logging.NOTSET: logger.setLevel(self.config.logging_log_level) @@ -130,9 +122,6 @@ def close_handlers(self) -> None: created_logger.propagate = True if created_logger in self._leveled_loggers: created_logger.setLevel(logging.NOTSET) - target = handler.target handler.close() - if target is not None: - target.close() self._created_handlers.clear() self._leveled_loggers.clear() diff --git a/lite_bootstrap/instruments/logging_instrument.py b/lite_bootstrap/instruments/logging_instrument.py index e9182f0..cad35e6 100644 --- a/lite_bootstrap/instruments/logging_instrument.py +++ b/lite_bootstrap/instruments/logging_instrument.py @@ -61,8 +61,6 @@ def tracer_injection(_: "WrappedLogger", __: str, event_dict: "EventDict") -> "E @dataclasses.dataclass(kw_only=True, frozen=True) class LoggingConfig(BaseConfig): logging_log_level: int = logging.INFO - logging_flush_level: int = logging.ERROR - logging_buffer_capacity: int = 10 logging_extra_processors: list[typing.Any] = dataclasses.field(default_factory=list) logging_unset_handlers: list[str] = dataclasses.field( default_factory=list, @@ -150,8 +148,6 @@ def memory_logger_factory(self) -> "MemoryLoggerFactory": config = self.bootstrap_config cached = MemoryLoggerFactory( config=_MemoryLoggerFactoryConfig( - logging_buffer_capacity=config.logging_buffer_capacity, - logging_flush_level=config.logging_flush_level, logging_log_level=config.logging_log_level, ), ) diff --git a/scripts/floor_smoke.py b/scripts/floor_smoke.py index f6241d3..65ef1cf 100644 --- a/scripts/floor_smoke.py +++ b/scripts/floor_smoke.py @@ -138,7 +138,6 @@ def _free() -> None: service_name="floor-smoke", service_version="1.0.0", service_environment="test", - logging_buffer_capacity=0, sentry_dsn=SENTRY_DSN, sentry_additional_params=SENTRY_PARAMS, sentry_tags={"floor": "smoke"}, @@ -170,7 +169,6 @@ async def floor_error() -> None: bootstrap_config=FastAPIConfig( service_name="floor-smoke", service_version="1.0.0", - logging_buffer_capacity=0, sentry_dsn=SENTRY_DSN, sentry_additional_params=SENTRY_PARAMS, application=application, @@ -189,7 +187,6 @@ def _fastapi() -> None: service_name="floor-smoke", service_version="1.0.0", service_debug=False, - logging_buffer_capacity=0, cors_allowed_origins=["http://test"], health_checks_path=HEALTH_PATH, health_checks_include_in_schema=True, @@ -225,7 +222,6 @@ async def floor_error() -> None: service_name="floor-smoke", service_version="1.0.0", service_debug=False, - logging_buffer_capacity=0, sentry_dsn=SENTRY_DSN, sentry_additional_params=SENTRY_PARAMS, application_config=AppConfig(route_handlers=[floor_error]), @@ -244,7 +240,6 @@ def _litestar() -> None: service_name="floor-smoke", service_version="1.0.0", service_debug=False, - logging_buffer_capacity=0, cors_allowed_origins=["http://test"], health_checks_path=HEALTH_PATH, sentry_dsn=SENTRY_DSN, @@ -267,7 +262,6 @@ def _faststream() -> None: bootstrap_config=FastStreamConfig( service_name="floor-smoke", service_version="1.0.0", - logging_buffer_capacity=0, health_checks_path=HEALTH_PATH, sentry_dsn=SENTRY_DSN, sentry_additional_params=SENTRY_PARAMS, @@ -290,7 +284,6 @@ def _fastmcp_lean_sentry_capture() -> None: bootstrap_config=FastMcpConfig( service_name="floor-smoke", service_version="1.0.0", - logging_buffer_capacity=0, sentry_dsn=SENTRY_DSN, sentry_additional_params=SENTRY_PARAMS, ) @@ -314,7 +307,6 @@ def _fastmcp() -> None: bootstrap_config=FastMcpConfig( service_name="floor-smoke", service_version="1.0.0", - logging_buffer_capacity=0, health_checks_path=HEALTH_PATH, sentry_dsn=SENTRY_DSN, sentry_additional_params=SENTRY_PARAMS, diff --git a/scripts/ft_smoke.py b/scripts/ft_smoke.py index 58c84e4..b9305c1 100644 --- a/scripts/ft_smoke.py +++ b/scripts/ft_smoke.py @@ -30,7 +30,6 @@ def main() -> None: bootstrap_config=FastAPIConfig( service_name="ft-smoke", service_debug=False, - logging_buffer_capacity=0, health_checks_path="/health/", ) ) diff --git a/tests/instruments/test_logging_instrument.py b/tests/instruments/test_logging_instrument.py index f0b1243..d109a01 100644 --- a/tests/instruments/test_logging_instrument.py +++ b/tests/instruments/test_logging_instrument.py @@ -19,7 +19,6 @@ def test_logging_instrument_simple(logging_mock: LoggingMock) -> None: logging_instrument = LoggingInstrument( bootstrap_config=LoggingConfig( logging_unset_handlers=["uvicorn"], - logging_buffer_capacity=0, service_debug=False, logging_extra_processors=[logging_mock], ) @@ -49,7 +48,6 @@ def test_logging_instrument_tracer_injection(logging_mock: LoggingMock) -> None: logging_instrument = LoggingInstrument( bootstrap_config=LoggingConfig( logging_unset_handlers=["uvicorn"], - logging_buffer_capacity=0, logging_extra_processors=[logging_mock], ) ) @@ -85,64 +83,29 @@ def test_logging_instrument_tracer_injection(logging_mock: LoggingMock) -> None: opentelemetry_instrument.teardown() -def test_memory_logger_factory_info() -> None: - test_capacity = 10 - test_flush_level = logging.ERROR - test_stream = StringIO() - - logger_factory = MemoryLoggerFactory( - config=_MemoryLoggerFactoryConfig( - logging_buffer_capacity=test_capacity, - logging_flush_level=test_flush_level, - logging_log_level=logging.INFO, - log_stream=test_stream, - ), +def _make_factory(stream: StringIO) -> MemoryLoggerFactory: + return MemoryLoggerFactory( + config=_MemoryLoggerFactoryConfig(logging_log_level=logging.INFO, log_stream=stream), ) - test_logger = logger_factory() - test_message = "test message" - - for current_log_index in range(test_capacity): - test_logger.info(test_message) - log_contents = test_stream.getvalue() - if current_log_index == test_capacity - 1: - assert test_message in log_contents - else: - assert not log_contents -def test_memory_logger_factory_error() -> None: - test_capacity = 10 - test_flush_level = logging.ERROR +def test_memory_logger_factory_writes_each_line_at_once() -> None: test_stream = StringIO() - - logger_factory = MemoryLoggerFactory( - config=_MemoryLoggerFactoryConfig( - logging_buffer_capacity=test_capacity, - logging_flush_level=test_flush_level, - logging_log_level=logging.INFO, - log_stream=test_stream, - ), - ) - test_logger = logger_factory() - error_message = "error message" - test_logger.error(error_message) - assert error_message in test_stream.getvalue() - - -def _unbuffered_factory(stream: StringIO) -> MemoryLoggerFactory: - return MemoryLoggerFactory( - config=_MemoryLoggerFactoryConfig( - logging_buffer_capacity=0, - logging_flush_level=logging.ERROR, - logging_log_level=logging.INFO, - log_stream=stream, - ), - ) + logger_factory = _make_factory(test_stream) + try: + test_logger = logger_factory("written_at_once") + test_logger.info("first") + assert test_stream.getvalue().splitlines() == ["first"] + test_logger.info("second") + assert test_stream.getvalue().splitlines() == ["first", "second"] + assert [type(handler) for handler in test_logger.handlers] == [logging.StreamHandler] + finally: + logger_factory.close_handlers() def test_memory_logger_factory_configures_each_logger_once() -> None: test_stream = StringIO() - logger_factory = _unbuffered_factory(test_stream) + logger_factory = _make_factory(test_stream) try: first = logger_factory("configured_once") second = logger_factory("configured_once") @@ -158,7 +121,7 @@ def test_memory_logger_factory_configures_each_logger_once() -> None: def test_memory_logger_factory_names_unnamed_logger_after_caller() -> None: - logger_factory = _unbuffered_factory(StringIO()) + logger_factory = _make_factory(StringIO()) try: assert logger_factory().name == __name__ finally: @@ -168,7 +131,7 @@ def test_memory_logger_factory_names_unnamed_logger_after_caller() -> None: def test_memory_logger_factory_keeps_a_level_set_beforehand() -> None: preset_logger = logging.getLogger("preset_level") preset_logger.setLevel(logging.DEBUG) - logger_factory = _unbuffered_factory(StringIO()) + logger_factory = _make_factory(StringIO()) try: assert logger_factory("preset_level").level == logging.DEBUG assert logger_factory("unset_level").level == logging.INFO @@ -179,7 +142,7 @@ def test_memory_logger_factory_keeps_a_level_set_beforehand() -> None: def test_memory_logger_factory_close_handlers_restores_the_level_it_set() -> None: - logger_factory = _unbuffered_factory(StringIO()) + logger_factory = _make_factory(StringIO()) logger_factory("restored_level") logger_factory.close_handlers() @@ -189,7 +152,6 @@ def test_memory_logger_factory_close_handlers_restores_the_level_it_set() -> Non def test_logging_instrument_lifecycle_replay(logging_mock: LoggingMock) -> None: instrument = LoggingInstrument( bootstrap_config=LoggingConfig( - logging_buffer_capacity=0, logging_extra_processors=[logging_mock], ), ) @@ -206,7 +168,7 @@ def test_logging_instrument_lifecycle_replay(logging_mock: LoggingMock) -> None: def test_logging_instrument_teardown_resets_factory_when_close_handlers_raises() -> None: instrument = LoggingInstrument( - bootstrap_config=LoggingConfig(logging_buffer_capacity=0), + bootstrap_config=LoggingConfig(), ) instrument.bootstrap() factory = instrument._logger_factory # noqa: SLF001 @@ -224,7 +186,7 @@ def test_logging_instrument_teardown_resets_factory_when_close_handlers_raises() def test_logging_instrument_teardown_aggregates_handler_close_errors() -> None: instrument = LoggingInstrument( - bootstrap_config=LoggingConfig(logging_buffer_capacity=0), + bootstrap_config=LoggingConfig(), ) instrument.bootstrap() root_logger = logging.getLogger() @@ -251,7 +213,7 @@ def test_logging_instrument_teardown_aggregates_handler_close_errors() -> None: def test_logging_instrument_teardown_aggregates_handler_and_factory_errors() -> None: instrument = LoggingInstrument( - bootstrap_config=LoggingConfig(logging_buffer_capacity=0), + bootstrap_config=LoggingConfig(), ) instrument.bootstrap() root_logger = logging.getLogger() @@ -274,9 +236,9 @@ def test_logging_instrument_teardown_aggregates_handler_and_factory_errors() -> def test_logging_instrument_binds_log_stream_at_bootstrap() -> None: - """The memory logger writes to the stdout in effect at bootstrap, not the one bound at import.""" + """The structlog logger writes to the stdout in effect at bootstrap, not the one bound at import.""" redirected_stdout = StringIO() - logging_instrument = LoggingInstrument(bootstrap_config=LoggingConfig(logging_buffer_capacity=0)) + logging_instrument = LoggingInstrument(bootstrap_config=LoggingConfig()) try: with contextlib.redirect_stdout(redirected_stdout): logging_instrument.bootstrap() @@ -300,7 +262,7 @@ def test_one_rendered_event_is_one_physical_line(capsys: pytest.CaptureFixture[s after the JSON and the same traceback ships twice. Every line-oriented log shipper reads the suffix as four malformed events. """ - logging_instrument = LoggingInstrument(bootstrap_config=LoggingConfig(logging_buffer_capacity=0)) + logging_instrument = LoggingInstrument(bootstrap_config=LoggingConfig()) try: logging_instrument.bootstrap() logger = structlog.getLogger("one_physical_line") @@ -322,7 +284,7 @@ def test_one_rendered_event_is_one_physical_line(capsys: pytest.CaptureFixture[s def test_foreign_logger_exception_is_one_physical_line(capsys: pytest.CaptureFixture[str]) -> None: """The same one-line contract holds for a plain stdlib logger going through the root handler.""" - logging_instrument = LoggingInstrument(bootstrap_config=LoggingConfig(logging_buffer_capacity=0)) + logging_instrument = LoggingInstrument(bootstrap_config=LoggingConfig()) try: logging_instrument.bootstrap() try: @@ -339,3 +301,20 @@ def test_foreign_logger_exception_is_one_physical_line(capsys: pytest.CaptureFix payload = json.loads(lines[0]) assert payload["event"] == "logging error" assert "ValueError: some error" in payload["exception"] + + +def test_structlog_lines_are_written_at_once_and_in_order_with_stdlib_lines( + capsys: pytest.CaptureFixture[str], +) -> None: + logging_instrument = LoggingInstrument(bootstrap_config=LoggingConfig()) + try: + logging_instrument.bootstrap() + structlog.getLogger("ordered_app").info("1") + logging.getLogger("ordered_lib").warning("2") + structlog.getLogger("ordered_app").info("3") + + events = [json.loads(line)["event"] for line in capsys.readouterr().out.splitlines()] + finally: + logging_instrument.teardown() + + assert events == ["1", "2", "3"] diff --git a/tests/instruments/test_logging_record_filters.py b/tests/instruments/test_logging_record_filters.py index 979a7b5..67bc232 100644 --- a/tests/instruments/test_logging_record_filters.py +++ b/tests/instruments/test_logging_record_filters.py @@ -85,7 +85,7 @@ def test_default_config_attaches_no_filters( """A config that does not ask for filters leaves loggers and rendered records untouched.""" package_logger = logging.getLogger("default_compat.package") filters_before = list(package_logger.filters) - instrument = LoggingInstrument(bootstrap_config=LoggingConfig(logging_buffer_capacity=0)) + instrument = LoggingInstrument(bootstrap_config=LoggingConfig()) try: instrument.bootstrap() package_logger.error("nothing filtered here") @@ -100,7 +100,6 @@ def test_filter_receives_records_from_its_exact_logger() -> None: record_filter = RecordingFilter() instrument = LoggingInstrument( bootstrap_config=LoggingConfig( - logging_buffer_capacity=0, logging_record_filters={"exact_match.package.child": (record_filter,)}, ), ) @@ -125,7 +124,6 @@ def test_filter_on_parent_logger_does_not_see_child_records() -> None: parent_filter = RecordingFilter() instrument = LoggingInstrument( bootstrap_config=LoggingConfig( - logging_buffer_capacity=0, logging_record_filters={"no_inheritance.package": (parent_filter,)}, ), ) @@ -155,7 +153,6 @@ def test_filter_demotes_level_before_handlers_render_it( ) -> None: instrument = LoggingInstrument( bootstrap_config=LoggingConfig( - logging_buffer_capacity=0, logging_record_filters={"demotion.target": (DemotingFilter("expected failure"),)}, ), ) @@ -191,7 +188,6 @@ def test_demoted_record_creates_no_sentry_issue_event( """ logging_instrument = LoggingInstrument( bootstrap_config=LoggingConfig( - logging_buffer_capacity=0, logging_record_filters={"sentry_demotion.target": (DemotingFilter("expected failure"),)}, ), ) @@ -222,7 +218,6 @@ def test_suppressing_filter_keeps_record_from_stream_and_sentry( ) -> None: logging_instrument = LoggingInstrument( bootstrap_config=LoggingConfig( - logging_buffer_capacity=0, logging_record_filters={"suppression.target": (SuppressingFilter("drop me"),)}, ), ) @@ -247,7 +242,6 @@ def test_non_matching_record_renders_identically_with_and_without_filters( def render_untouched(record_filters: dict[str, tuple[logging.Filter, ...]]) -> str: instrument = LoggingInstrument( bootstrap_config=LoggingConfig( - logging_buffer_capacity=0, logging_time_stamper=timestamper, logging_record_filters=record_filters, ), @@ -271,7 +265,6 @@ def test_teardown_removes_only_the_filters_it_attached() -> None: instrument = LoggingInstrument( bootstrap_config=LoggingConfig( - logging_buffer_capacity=0, logging_record_filters={"teardown_isolation.target": (configured_filter,)}, ), ) @@ -307,7 +300,6 @@ def close(self) -> None: instrument = LoggingInstrument( bootstrap_config=LoggingConfig( - logging_buffer_capacity=0, logging_record_filters={"teardown_despite_error.target": (configured_filter,)}, ), ) @@ -329,7 +321,6 @@ def test_bootstrap_teardown_bootstrap_attaches_each_filter_once() -> None: target_logger = logging.getLogger("filter_lifecycle.target") instrument = LoggingInstrument( bootstrap_config=LoggingConfig( - logging_buffer_capacity=0, logging_record_filters={"filter_lifecycle.target": (configured_filter,)}, ), ) @@ -355,20 +346,19 @@ def test_bootstrap_teardown_bootstrap_attaches_each_filter_once() -> None: def _build_free_bootstrapper(record_filters: dict[str, tuple[logging.Filter, ...]]) -> FreeBootstrapper: return FreeBootstrapper( - bootstrap_config=FreeConfig(logging_buffer_capacity=0, logging_record_filters=record_filters), + bootstrap_config=FreeConfig(logging_record_filters=record_filters), ) def _build_fastapi_bootstrapper(record_filters: dict[str, tuple[logging.Filter, ...]]) -> FastAPIBootstrapper: return FastAPIBootstrapper( - bootstrap_config=FastAPIConfig(logging_buffer_capacity=0, logging_record_filters=record_filters), + bootstrap_config=FastAPIConfig(logging_record_filters=record_filters), ) def _build_faststream_bootstrapper(record_filters: dict[str, tuple[logging.Filter, ...]]) -> FastStreamBootstrapper: return FastStreamBootstrapper( bootstrap_config=FastStreamConfig( - logging_buffer_capacity=0, logging_record_filters=record_filters, application=faststream.asgi.AsgiFastStream(RedisBroker()), ), @@ -377,14 +367,13 @@ def _build_faststream_bootstrapper(record_filters: dict[str, tuple[logging.Filte def _build_litestar_bootstrapper(record_filters: dict[str, tuple[logging.Filter, ...]]) -> LitestarBootstrapper: return LitestarBootstrapper( - bootstrap_config=LitestarConfig(logging_buffer_capacity=0, logging_record_filters=record_filters), + bootstrap_config=LitestarConfig(logging_record_filters=record_filters), ) def _build_fastmcp_bootstrapper(record_filters: dict[str, tuple[logging.Filter, ...]]) -> FastMcpBootstrapper: return FastMcpBootstrapper( bootstrap_config=FastMcpConfig( - logging_buffer_capacity=0, logging_record_filters=record_filters, application=FastMCP[typing.Any](name="microservice"), ), diff --git a/tests/instruments/test_sentry_instrument.py b/tests/instruments/test_sentry_instrument.py index 91a4b49..758ef80 100644 --- a/tests/instruments/test_sentry_instrument.py +++ b/tests/instruments/test_sentry_instrument.py @@ -55,7 +55,6 @@ def test_sentry_instrument_with_structlog_error( logging_instrument = LoggingInstrument( bootstrap_config=LoggingConfig( logging_unset_handlers=["uvicorn"], - logging_buffer_capacity=0, service_debug=False, logging_extra_processors=[logging_mock], ) diff --git a/tests/test_config.py b/tests/test_config.py index ff1d722..f3a31f9 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -16,7 +16,6 @@ def test_config_from_dict() -> None: "service_debug": False, "cors_allowed_origins": ["http://test"], "health_checks_path": "/custom-health/", - "logging_buffer_capacity": 0, "opentelemetry_endpoint": "otl", "opentelemetry_log_traces": True, "opentelemetry_instrumentors": [CustomInstrumentor()], @@ -40,7 +39,6 @@ def test_config_from_object() -> None: service_debug=False, cors_allowed_origins=["http://test"], health_checks_path="/custom-health/", - logging_buffer_capacity=0, opentelemetry_endpoint="otl", opentelemetry_instrumentors=[CustomInstrumentor()], opentelemetry_log_traces=True, diff --git a/tests/test_fastapi_bootstrap.py b/tests/test_fastapi_bootstrap.py index b756735..5aa3b55 100644 --- a/tests/test_fastapi_bootstrap.py +++ b/tests/test_fastapi_bootstrap.py @@ -54,7 +54,6 @@ def fastapi_config() -> FastAPIConfig: service_debug=False, cors_allowed_origins=["http://test"], health_checks_path="/custom-health/", - logging_buffer_capacity=0, opentelemetry_instrumentors=[CustomInstrumentor()], opentelemetry_log_traces=True, opentelemetry_generate_health_check_spans=False, @@ -617,7 +616,6 @@ def test_fastapi_otel_leaves_the_health_check_untraced_by_default() -> None: config = FastAPIConfig( service_name="microservice", health_checks_path="/custom-health/", - logging_buffer_capacity=0, opentelemetry_log_traces=True, ) diff --git a/tests/test_fastmcp_bootstrap.py b/tests/test_fastmcp_bootstrap.py index d9ace37..f80d681 100644 --- a/tests/test_fastmcp_bootstrap.py +++ b/tests/test_fastmcp_bootstrap.py @@ -183,7 +183,6 @@ def _make_test_config(**overrides: typing.Any) -> FastMcpConfig: # noqa: ANN401 base: dict[str, typing.Any] = { "service_name": "test-mcp", "service_version": "1.2.3", - "logging_buffer_capacity": 0, } base.update(overrides) return FastMcpConfig(**base) diff --git a/tests/test_faststream_bootstrap.py b/tests/test_faststream_bootstrap.py index ce5a1f8..5dd9856 100644 --- a/tests/test_faststream_bootstrap.py +++ b/tests/test_faststream_bootstrap.py @@ -1,6 +1,5 @@ import dataclasses import logging -import logging.handlers import sys import typing import uuid @@ -81,7 +80,6 @@ def build_faststream_config( sentry_dsn="https://testdsn@localhost/1", sentry_additional_params={"transport": SentryTestTransport()}, health_checks_path="/custom-health/", - logging_buffer_capacity=0, application=application, ) @@ -144,7 +142,6 @@ async def test_faststream_bootstrap_health_check_wo_broker() -> None: def test_faststream_logging_instrument_injects_structlog_logger(broker: RedisBroker) -> None: bootstrap_config = FastStreamConfig( service_debug=False, - logging_buffer_capacity=0, logging_log_level=logging.INFO, faststream_log_level=logging.WARNING, application=faststream.asgi.AsgiFastStream(broker), @@ -163,7 +160,6 @@ def test_faststream_logging_replaces_faststream_stderr_handler(broker: RedisBrok original_handlers = faststream_logger.handlers[:] bootstrapper = FastStreamBootstrapper( bootstrap_config=FastStreamConfig( - logging_buffer_capacity=0, faststream_log_level=logging.INFO, application=faststream.asgi.AsgiFastStream(broker), ) @@ -171,7 +167,7 @@ def test_faststream_logging_replaces_faststream_stderr_handler(broker: RedisBrok bootstrapper.bootstrap() try: assert not [one for one in faststream_logger.handlers if getattr(one, "stream", None) is sys.stderr] - assert [type(one) for one in faststream_logger.handlers].count(logging.handlers.MemoryHandler) == 1 + assert [type(one) for one in faststream_logger.handlers].count(logging.StreamHandler) == 1 finally: bootstrapper.teardown() @@ -396,7 +392,6 @@ def test_faststream_prometheus_is_skipped_without_metrics_path(broker: RedisBrok bootstrap_config = FastStreamConfig( application=faststream.asgi.AsgiFastStream(broker), prometheus_middleware_cls=RedisPrometheusMiddleware, - logging_buffer_capacity=0, ) bootstrapper = FastStreamBootstrapper(bootstrap_config=bootstrap_config) skipped = dict(bootstrapper.skipped_instruments) diff --git a/tests/test_free_bootstrap.py b/tests/test_free_bootstrap.py index 237e51e..94c1980 100644 --- a/tests/test_free_bootstrap.py +++ b/tests/test_free_bootstrap.py @@ -32,7 +32,6 @@ def free_bootstrapper_config() -> FreeConfig: opentelemetry_instrumentors=[CustomInstrumentor()], opentelemetry_log_traces=True, sentry_dsn="https://testdsn@localhost/1", - logging_buffer_capacity=0, ) @@ -59,7 +58,6 @@ def test_free_bootstrap_passes_sampler_to_tracer_provider() -> None: bootstrap_config=FreeConfig( opentelemetry_log_traces=True, opentelemetry_sampler=sampler, - logging_buffer_capacity=0, ), ) bootstrapper.bootstrap() @@ -80,7 +78,6 @@ def test_free_bootstrap_logging_disabled() -> None: opentelemetry_log_traces=True, sentry_dsn="https://testdsn@localhost/1", sentry_additional_params={"transport": SentryTestTransport()}, - logging_buffer_capacity=0, ), ) skipped_classes = {cls for cls, _ in bootstrapper.skipped_instruments} @@ -252,7 +249,6 @@ def test_build_summary_format() -> None: sentry_dsn="https://testdsn@localhost/1", sentry_additional_params={"transport": SentryTestTransport()}, logging_enabled=False, - logging_buffer_capacity=0, ), ) summary = bootstrapper.build_summary() @@ -269,7 +265,6 @@ def test_config_skip_emits_no_warning() -> None: bootstrapper = FreeBootstrapper( bootstrap_config=FreeConfig( logging_enabled=False, - logging_buffer_capacity=0, ), ) assert LoggingInstrument in {cls for cls, _ in bootstrapper.skipped_instruments} @@ -291,7 +286,7 @@ def test_only_the_silent_skip_path_lands_in_skipped_instruments() -> None: filtering on it would start seeing entries that mean the opposite of what it filtered for. """ config_skip = FreeBootstrapper( - bootstrap_config=FreeConfig(logging_enabled=False, logging_buffer_capacity=0), + bootstrap_config=FreeConfig(logging_enabled=False), ) assert LoggingInstrument in {cls for cls, _ in config_skip.skipped_instruments} @@ -303,7 +298,6 @@ def test_only_the_silent_skip_path_lands_in_skipped_instruments() -> None: bootstrap_config=FreeConfig( sentry_dsn="https://testdsn@localhost/1", logging_enabled=False, - logging_buffer_capacity=0, ), ) diff --git a/tests/test_litestar_bootstrap.py b/tests/test_litestar_bootstrap.py index 4c01ac2..335f3f1 100644 --- a/tests/test_litestar_bootstrap.py +++ b/tests/test_litestar_bootstrap.py @@ -71,7 +71,6 @@ def litestar_config() -> LitestarConfig: sentry_dsn="https://testdsn@localhost/1", sentry_additional_params={"transport": SentryTestTransport()}, swagger_offline_docs=True, - logging_buffer_capacity=0, ) @@ -346,7 +345,7 @@ async def _ping_handler() -> dict[str, bool]: with TestClient(app=application) as client: assert client.get("/ping").status_code == status_codes.HTTP_200_OK litestar_handlers = logging.getLogger("litestar").handlers - assert [type(handler) for handler in litestar_handlers] == [logging.handlers.MemoryHandler] + assert [type(handler) for handler in litestar_handlers] == [logging.StreamHandler] def test_litestar_access_logging_disabled_by_default(litestar_config: LitestarConfig) -> None: @@ -840,7 +839,7 @@ def test_litestar_health_check_runs_probes( def test_litestar_openapi_and_prometheus_fall_back_to_default_service_name() -> None: - application = LitestarBootstrapper(bootstrap_config=LitestarConfig(logging_buffer_capacity=0)).bootstrap() + application = LitestarBootstrapper(bootstrap_config=LitestarConfig()).bootstrap() assert application.openapi_config is not None assert application.openapi_config.title == "micro-service" assert application.openapi_config.version == "1.0.0" diff --git a/tests/test_litestar_sentry_capture.py b/tests/test_litestar_sentry_capture.py index ec441af..64bd0d3 100644 --- a/tests/test_litestar_sentry_capture.py +++ b/tests/test_litestar_sentry_capture.py @@ -132,7 +132,6 @@ def _build_config(transport: SentryTestTransport, **overrides: typing.Any) -> Li service_environment="test", sentry_dsn="https://testdsn@localhost/1", sentry_additional_params=sentry_additional_params, - logging_buffer_capacity=0, application_config=AppConfig( route_handlers=[ boom, @@ -187,7 +186,6 @@ def test_lean_capture_is_the_default_while_tracing_is_off(sentry_mock: SentryTes bootstrap_config=LitestarConfig( sentry_dsn="https://testdsn@localhost/1", sentry_additional_params={"transport": sentry_mock}, - logging_buffer_capacity=0, application_config=AppConfig(route_handlers=[boom, integrations]), ) ).bootstrap() diff --git a/tests/test_starlette_sentry_capture.py b/tests/test_starlette_sentry_capture.py index c0d52a5..e3280f6 100644 --- a/tests/test_starlette_sentry_capture.py +++ b/tests/test_starlette_sentry_capture.py @@ -154,7 +154,6 @@ def _build_config(transport: SentryTestTransport, **overrides: typing.Any) -> Fa service_environment="test", sentry_dsn="https://testdsn@localhost/1", sentry_additional_params=sentry_additional_params, - logging_buffer_capacity=0, application=application, **overrides, ) @@ -196,7 +195,6 @@ def test_lean_capture_is_the_default_on_fastapi_while_tracing_is_off(sentry_mock bootstrap_config=FastAPIConfig( sentry_dsn="https://testdsn@localhost/1", sentry_additional_params={"transport": sentry_mock}, - logging_buffer_capacity=0, application=application, ) ).bootstrap() @@ -637,7 +635,6 @@ async def integrations(_: Request) -> JSONResponse: service_environment="test", sentry_dsn="https://testdsn@localhost/1", sentry_additional_params={"transport": transport}, - logging_buffer_capacity=0, prometheus_metrics_path="", application=application, **overrides, diff --git a/tests/test_taskiq_recipe.py b/tests/test_taskiq_recipe.py index 6d2a6d1..110fe21 100644 --- a/tests/test_taskiq_recipe.py +++ b/tests/test_taskiq_recipe.py @@ -28,7 +28,7 @@ async def test_taskiq_recipe_traces_tasks_and_tears_down() -> None: async def add(left: int, right: int) -> int: return left + right - _register_recipe(broker, FreeConfig(opentelemetry_log_traces=True, logging_buffer_capacity=0)) + _register_recipe(broker, FreeConfig(opentelemetry_log_traces=True)) await broker.startup() try: