Skip to content

Commit f9ee273

Browse files
authored
Write structlog lines through a plain StreamHandler and remove logging_buffer_capacity and logging_flush_level (#378)
1 parent 6f07863 commit f9ee273

21 files changed

Lines changed: 57 additions & 142 deletions

‎benchmarks/README.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -619,15 +619,15 @@ record per MCP message), FastStream's own "Received" and "Processed" (filtered a
619619

620620
Linux, a 2-CPU container on the same Apple M2 under OrbStack, CPython 3.14.9, structlog 26.1.0,
621621
orjson 3.11.9, sentry-sdk 2.67.1, opentelemetry-sdk 1.44.0. Output to a real `/dev/null` file,
622-
50000 calls per round, loop overhead (0.06 µs) subtracted.
622+
50000 calls per round, loop overhead (0.06 µs) subtracted. The `MemoryHandler` was removed afterwards
623+
(#377), and 2.0 writes through the `StreamHandler` directly; the rows have not been rerun.
623624

624625
| call | µs/call |
625626
|---|---:|
626627
| `log.info("did a thing", a=1)` through lite-bootstrap's chain | 9.5 |
627628
| same with 5 keyword values | 10.4 |
628629
| `log.debug(...)` at INFO, filtered | 1.1 |
629630
| info, JSON through stdlib `json` (the fallback without orjson) | 11.5 |
630-
| info, `logging_buffer_capacity=1` | 10.5 |
631631
| info inside a recording OpenTelemetry span | 10.7 |
632632
| info with Sentry's LoggingIntegration, breadcrumb level INFO (default) | 15.7 |
633633
| info with Sentry, `sentry_logging_breadcrumb_level=None` | 10.5 |

‎benchmarks/frameworks/logging_suite.py‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ class LogScenario:
2828
span: bool = False
2929
native: bool = False
3030
stdlib_json: bool = False
31-
buffer_capacity: int = 10
3231

3332

3433
SCENARIOS: typing.Final = {
@@ -37,7 +36,6 @@ class LogScenario:
3736
"info_kw5": LogScenario(call="info_kw5"),
3837
"debug_filtered": LogScenario(call="debug"),
3938
"info_stdjson": LogScenario(call="info", stdlib_json=True),
40-
"info_capacity1": LogScenario(call="info", buffer_capacity=1),
4139
"info_span": LogScenario(call="info", span=True),
4240
"info_sentry": LogScenario(call="info", sentry={}),
4341
"info_sentry_nocrumb": LogScenario(call="info", sentry={"sentry_logging_breadcrumb_level": None}),
@@ -113,7 +111,7 @@ def setup(scenario: LogScenario) -> list[typing.Callable[[], object]]:
113111
configure_native(devnull_bytes)
114112
elif scenario.call != "noop":
115113
with contextlib.redirect_stdout(devnull):
116-
config = LoggingConfig(logging_enabled=True, logging_buffer_capacity=scenario.buffer_capacity)
114+
config = LoggingConfig(logging_enabled=True)
117115
LoggingInstrument(bootstrap_config=config).bootstrap()
118116

119117
if scenario.sentry is not None:

‎docs/integrations/fastmcp.md‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ bootstrapper_config = FastMcpConfig(
3636
sentry_dsn="https://testdsn@localhost/1",
3737
prometheus_metrics_path="/custom-metrics/",
3838
health_checks_path="/custom-health/",
39-
logging_buffer_capacity=0,
4039
)
4140
bootstrapper = FastMcpBootstrapper(bootstrap_config=bootstrapper_config)
4241
application: FastMCP = bootstrapper.bootstrap()

‎docs/integrations/faststream.md‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ bootstrapper_config = FastStreamConfig(
4343
prometheus_middleware_cls=RedisPrometheusMiddleware,
4444
sentry_dsn="https://testdsn@localhost/1",
4545
health_checks_path="/custom-health/",
46-
logging_buffer_capacity=0,
4746
application=AsgiFastStream(broker),
4847
)
4948
bootstrapper = FastStreamBootstrapper(bootstrapper_config)

‎docs/introduction/configuration.md‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -352,8 +352,6 @@ Additional parameters:
352352

353353
- `logging_enabled` - whether to configure structlog (default: `True`).
354354
- `logging_log_level`
355-
- `logging_flush_level`
356-
- `logging_buffer_capacity`
357355
- `logging_extra_processors`
358356
- `logging_unset_handlers`
359357
- `logging_record_filters` - standard-library `logging.Filter` instances to attach to named loggers (see below).

‎lite_bootstrap/instruments/logging_factory.py‎

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import dataclasses
22
import json
33
import logging
4-
import logging.handlers
54
import sys
65
import typing
76

@@ -14,8 +13,6 @@
1413

1514
@dataclasses.dataclass(kw_only=True, slots=True, frozen=True)
1615
class _MemoryLoggerFactoryConfig:
17-
logging_buffer_capacity: int
18-
logging_flush_level: int
1916
logging_log_level: int
2017
# default_factory, not a bare default: a bare one binds sys.stdout at import time, so a
2118
# process that rebinds stdout before bootstrap would keep logging to the stale stream.
@@ -102,20 +99,15 @@ def __init__(
10299
kwargs["ignore_frame_names"] = [*(kwargs.get("ignore_frame_names") or ()), __name__]
103100
super().__init__(*args, **kwargs)
104101
self.config = config
105-
self._created_handlers: dict[logging.Logger, logging.handlers.MemoryHandler] = {}
102+
self._created_handlers: dict[logging.Logger, logging.StreamHandler[typing.Any]] = {}
106103
self._leveled_loggers: set[logging.Logger] = set()
107104

108105
def __call__(self, *args: typing.Any) -> logging.Logger: # noqa: ANN401
109106
logger: typing.Final = super().__call__(*args)
110107
if logger in self._created_handlers:
111108
return logger
112-
stream_handler: typing.Final = logging.StreamHandler(stream=self.config.log_stream)
113-
stream_handler.setFormatter(_RenderedLineFormatter())
114-
handler: typing.Final = logging.handlers.MemoryHandler(
115-
capacity=self.config.logging_buffer_capacity,
116-
flushLevel=self.config.logging_flush_level,
117-
target=stream_handler,
118-
)
109+
handler: typing.Final = logging.StreamHandler(stream=self.config.log_stream)
110+
handler.setFormatter(_RenderedLineFormatter())
119111
logger.addHandler(handler)
120112
if logger.level == logging.NOTSET:
121113
logger.setLevel(self.config.logging_log_level)
@@ -130,9 +122,6 @@ def close_handlers(self) -> None:
130122
created_logger.propagate = True
131123
if created_logger in self._leveled_loggers:
132124
created_logger.setLevel(logging.NOTSET)
133-
target = handler.target
134125
handler.close()
135-
if target is not None:
136-
target.close()
137126
self._created_handlers.clear()
138127
self._leveled_loggers.clear()

‎lite_bootstrap/instruments/logging_instrument.py‎

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,6 @@ def tracer_injection(_: "WrappedLogger", __: str, event_dict: "EventDict") -> "E
6161
@dataclasses.dataclass(kw_only=True, frozen=True)
6262
class LoggingConfig(BaseConfig):
6363
logging_log_level: int = logging.INFO
64-
logging_flush_level: int = logging.ERROR
65-
logging_buffer_capacity: int = 10
6664
logging_extra_processors: list[typing.Any] = dataclasses.field(default_factory=list)
6765
logging_unset_handlers: list[str] = dataclasses.field(
6866
default_factory=list,
@@ -150,8 +148,6 @@ def memory_logger_factory(self) -> "MemoryLoggerFactory":
150148
config = self.bootstrap_config
151149
cached = MemoryLoggerFactory(
152150
config=_MemoryLoggerFactoryConfig(
153-
logging_buffer_capacity=config.logging_buffer_capacity,
154-
logging_flush_level=config.logging_flush_level,
155151
logging_log_level=config.logging_log_level,
156152
),
157153
)

‎scripts/floor_smoke.py‎

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,6 @@ def _free() -> None:
138138
service_name="floor-smoke",
139139
service_version="1.0.0",
140140
service_environment="test",
141-
logging_buffer_capacity=0,
142141
sentry_dsn=SENTRY_DSN,
143142
sentry_additional_params=SENTRY_PARAMS,
144143
sentry_tags={"floor": "smoke"},
@@ -170,7 +169,6 @@ async def floor_error() -> None:
170169
bootstrap_config=FastAPIConfig(
171170
service_name="floor-smoke",
172171
service_version="1.0.0",
173-
logging_buffer_capacity=0,
174172
sentry_dsn=SENTRY_DSN,
175173
sentry_additional_params=SENTRY_PARAMS,
176174
application=application,
@@ -189,7 +187,6 @@ def _fastapi() -> None:
189187
service_name="floor-smoke",
190188
service_version="1.0.0",
191189
service_debug=False,
192-
logging_buffer_capacity=0,
193190
cors_allowed_origins=["http://test"],
194191
health_checks_path=HEALTH_PATH,
195192
health_checks_include_in_schema=True,
@@ -225,7 +222,6 @@ async def floor_error() -> None:
225222
service_name="floor-smoke",
226223
service_version="1.0.0",
227224
service_debug=False,
228-
logging_buffer_capacity=0,
229225
sentry_dsn=SENTRY_DSN,
230226
sentry_additional_params=SENTRY_PARAMS,
231227
application_config=AppConfig(route_handlers=[floor_error]),
@@ -244,7 +240,6 @@ def _litestar() -> None:
244240
service_name="floor-smoke",
245241
service_version="1.0.0",
246242
service_debug=False,
247-
logging_buffer_capacity=0,
248243
cors_allowed_origins=["http://test"],
249244
health_checks_path=HEALTH_PATH,
250245
sentry_dsn=SENTRY_DSN,
@@ -267,7 +262,6 @@ def _faststream() -> None:
267262
bootstrap_config=FastStreamConfig(
268263
service_name="floor-smoke",
269264
service_version="1.0.0",
270-
logging_buffer_capacity=0,
271265
health_checks_path=HEALTH_PATH,
272266
sentry_dsn=SENTRY_DSN,
273267
sentry_additional_params=SENTRY_PARAMS,
@@ -290,7 +284,6 @@ def _fastmcp_lean_sentry_capture() -> None:
290284
bootstrap_config=FastMcpConfig(
291285
service_name="floor-smoke",
292286
service_version="1.0.0",
293-
logging_buffer_capacity=0,
294287
sentry_dsn=SENTRY_DSN,
295288
sentry_additional_params=SENTRY_PARAMS,
296289
)
@@ -314,7 +307,6 @@ def _fastmcp() -> None:
314307
bootstrap_config=FastMcpConfig(
315308
service_name="floor-smoke",
316309
service_version="1.0.0",
317-
logging_buffer_capacity=0,
318310
health_checks_path=HEALTH_PATH,
319311
sentry_dsn=SENTRY_DSN,
320312
sentry_additional_params=SENTRY_PARAMS,

‎scripts/ft_smoke.py‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ def main() -> None:
3030
bootstrap_config=FastAPIConfig(
3131
service_name="ft-smoke",
3232
service_debug=False,
33-
logging_buffer_capacity=0,
3433
health_checks_path="/health/",
3534
)
3635
)

0 commit comments

Comments
 (0)