Cross-process logging via a dedicated log server process and SocketHandler.
Project description
kitty_logger
单机跨进程的 Python 日志库。主进程启动一个独立的"日志服务"子进程,所有
通过 spawn 创建的子进程把 LogRecord 经 logging.handlers.SocketHandler
发到这里,由它统一落盘 / 输出到 stderr,不会出现多进程并发写文件的
错行或丢失问题。
适用范围。 公司内部研发协作环境:单台主机、本机所有进程都互相信任、 追求"用起来简单"而不是"对抗外部威胁"。不适用于生产部署或多租户机器 等不能信任本机其他进程的场景。
安装
pip install kitty-logger
用法
# main.py
import multiprocessing as mp
import kitty_logger
def worker(i):
log = kitty_logger.getLogger(f"worker.{i}")
log.info("hello from worker %d", i)
if __name__ == "__main__":
kitty_logger.setup_logging(log_file="app.log")
log = kitty_logger.getLogger("main")
log.info("starting")
with mp.get_context("spawn").Pool(4) as pool:
pool.map(worker, range(4))
setup_logging 会写入环境变量
KITTY_LOGGER_HOST / KITTY_LOGGER_PORT / KITTY_LOGGER_LEVEL;任意层级
spawn 出来的后代进程会自动继承,从而能在零配置的情况下连上日志服务。
API
setup_logging(log_file=None, level=logging.INFO, host="127.0.0.1", port=0, stream=True, console_fmt=..., file_fmt=..., datefmt=None) -> (host, port)启动日志服务子进程(始终使用spawn)。幂等。已通过atexit注册清理。port=0让操作系统挑选空闲端口;返回真实绑定到的(host, port)。host必须是 loopback——绑定非 loopback 地址会直接ValueError。 同时把主进程内logging.getLogger("kitty")这一个 logger 初始化好——挂上SocketHandler、设置 level、关闭propagate。不动 root logger。 在multiprocessing启动的子进程里再次调用本函数会自动 no-op,仅返回 从父进程继承的(host, port),因此可以直接放在模块顶层而不必用if __name__ == "__main__":包裹。getLogger(name=None) -> logging.Logger返回挂在kitty命名空间下的 logger:getLogger("foo")实际拿到的是logging.getLogger("kitty.foo"),getLogger()拿到的是kitty本身。 整个进程内只有kitty持有SocketHandler,子 logger 通过标准库的祖先链 冒泡上来,无需重复挂载。shutdown_logging()— 显式停止日志服务子进程。
为什么只支持 spawn
fork 出来的子进程会继承父进程已经建立的 SocketHandler 及其底层 TCP
连接。父子进程会在同一个 socket 上交叉写 pickle 字节流,导致服务端反
序列化必然失败。此外 fork 在多线程父进程中不安全(其他线程持有的锁
会原样留在子进程里,引发死锁),且在 Windows 上不被支持。
请使用 multiprocessing.get_context("spawn"),或在顶层用
if __name__ == "__main__": 守卫配合 Python 默认行为。
注意事项
- 所有 logger 名都带
kitty.前缀,这是有意保留的标记:日志记录里%(name)s字段一眼可以和第三方库(urllib3、httpx 等)的输出区分。getLogger(__name__)在模块myapp.svc下实际得到的是kitty.myapp.svc。 kitty子树不向 root 冒泡:第三方库挂在 root 上的 handler 不会收到 kitty_logger 的日志,反之 root 上输出的日志也不会被 kitty_logger 转发。 两条输出渠道互不干扰。shutdown_logging()会卸载本进程内 kitty_logger 自己挂的SocketHandler,并清理KITTY_LOGGER_*环境变量,确保进程状态与setup_logging对称。如果你额外挂了别的 handler,仍由你自己负责清理。
安全性
服务端用 pickle.loads 反序列化收到的字节流——这等价于在本机上对攻击者
可控的输入做"任意代码执行"。为了让这个能力永远不会跨出本机,
setup_logging 在打开 socket 之前就会直接拒绝任何非 loopback 绑定
(ValueError)。监听端口仅本机可达;请把它视为受信任的内部接口,不要
在不能信任本机其他进程的多租户机器上运行。
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file kitty_logger-0.2.0.dev2.tar.gz.
File metadata
- Download URL: kitty_logger-0.2.0.dev2.tar.gz
- Upload date:
- Size: 21.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2b7e8f4bfc6f7dde206fcac7cbbf28eb027f7f7d0999702df2e5de9800bda14e
|
|
| MD5 |
304fe81f94ae943bbc703227e984d621
|
|
| BLAKE2b-256 |
861105594c8979ba7c5afa2c3e84f515a9816acdde8f0a5f1f2f0114083cae31
|
File details
Details for the file kitty_logger-0.2.0.dev2-py3-none-any.whl.
File metadata
- Download URL: kitty_logger-0.2.0.dev2-py3-none-any.whl
- Upload date:
- Size: 19.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
da2a4e73d3162bedea515d529f8ce39bc7873544477b98891c6c6a8f440ae1ef
|
|
| MD5 |
7ec8604281f1d761587f3b0a4cacdc74
|
|
| BLAKE2b-256 |
5a0d9340b21399d829109907317f8de23c4af00659e955eb31574922dee3d593
|