Process log forwarding¶
Logs emitted inside ProcessPoolExecutor workers are created in child
processes. They do not automatically flow through the parent application’s
logger handlers.
leasepool provides optional process log forwarding for the process backend.
It installs a queue handler in each worker and a queue listener in the parent
process.
Explicit configuration¶
Use ProcessLoggingConfig when you want one object that documents the logging
bridge configuration:
"""
Forward logs emitted by ProcessPoolExecutor workers.
Normal leasepool logs are emitted by the parent process. Logs created inside a
process worker need an explicit queue bridge. Use ProcessLoggingConfig when you
want the parent application logger to receive worker log records.
Run this file directly:
python examples/13_process_log_forwarding.py
"""
from __future__ import annotations
import asyncio
import logging
from leasepool import LeasedExecutorManager, ProcessLoggingConfig
LOGGER_NAME = "leasepool.examples.process.worker"
def logged_cpu_work(value: int) -> int:
logger = logging.getLogger(LOGGER_NAME)
logger.info("worker received value=%s", value)
total = 0
for item in range(value):
total += item * item
logger.info("worker finished value=%s", value)
return total
async def main() -> None:
logging.basicConfig(
level=logging.INFO,
format="%(processName)s %(name)s %(levelname)s: %(message)s",
)
parent_logger = logging.getLogger("leasepool.examples.process.parent")
manager = LeasedExecutorManager(
backend="process",
max_pools=1,
min_pools=1,
workers_per_pool=2,
process_logging=ProcessLoggingConfig(
enabled=True,
level="INFO",
target_logger=parent_logger,
),
)
await manager.start()
try:
async with await manager.acquire(owner="process-log-demo") as lease:
first, second = await asyncio.gather(
lease.run(logged_cpu_work, 10_000),
lease.run(logged_cpu_work, 12_000),
)
print("Results:", first, second)
finally:
await manager.stop()
if __name__ == "__main__":
asyncio.run(main())
Convenience configuration¶
For shorter setup, pass the convenience arguments directly to the manager:
import logging
from leasepool import LeasedExecutorManager
manager = LeasedExecutorManager(
backend="process",
max_pools=1,
min_pools=1,
workers_per_pool=2,
forward_process_logs=True,
process_log_level="INFO",
process_log_target_logger=logging.getLogger("myapp.process-workers"),
)
Do not pass both process_logging and the convenience arguments in the same
manager.
Configuration fields¶
enabledEnable child-process log forwarding.
levelMinimum level configured on the child-process root logger. Accepts an integer logging level or a standard level name such as
"INFO".target_loggerParent-process logger that receives worker log records. If omitted, the manager’s logger is used.
clear_child_handlersRemove existing child-process root handlers before installing the queue handler. Defaults to
Trueto avoid duplicate records after fork.
Composing worker initializers¶
If you pass initializer and initargs to the process executor, leasepool
preserves them when log forwarding is enabled:
manager = LeasedExecutorManager(
backend="process",
max_pools=1,
forward_process_logs=True,
initializer=configure_worker,
initargs=("worker-config",),
)
The leasepool logging initializer runs first, then your initializer runs.
When to enable it¶
Enable process log forwarding when worker logs are important for debugging, monitoring, or audit trails.
Leave it disabled when workers do not log or when you have your own process-aware logging setup.