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, attach_main_logger=False) -> (host, port)启动日志服务子进程(始终使用spawn)。幂等。已通过atexit注册清理。port=0让操作系统挑选空闲端口;返回真实绑定到的(host, port)。host必须是 loopback——绑定非 loopback 地址会直接ValueError。 默认不动主进程 root logger;想让某个 logger 走 kitty_logger,请显式kitty_logger.getLogger(...)。如果希望主进程 root 也自动挂上 SocketHandler, 传attach_main_logger=True。getLogger(name=None, *, propagate=False) -> logging.Logger返回一个挂好SocketHandler、指向日志服务的 logger。 默认propagate=False:每个 logger 独立挂载,互不干扰;想让子 logger 通过祖先链冒泡到这个 logger 时(getLogger("myapp")接住myapp.svc.x等), 传propagate=True。对 root logger 该参数没有意义。shutdown_logging()— 显式停止日志服务子进程。
为什么只支持 spawn
fork 出来的子进程会继承父进程已经建立的 SocketHandler 及其底层 TCP
连接。父子进程会在同一个 socket 上交叉写 pickle 字节流,导致服务端反
序列化必然失败。此外 fork 在多线程父进程中不安全(其他线程持有的锁
会原样留在子进程里,引发死锁),且在 Windows 上不被支持。
请使用 multiprocessing.get_context("spawn"),或在顶层用
if __name__ == "__main__": 守卫配合 Python 默认行为。
注意事项
- 默认每个 logger 都是显式加入、互不传播的:业务代码里
kitty_logger.getLogger(__name__)得到的 logger 自带SocketHandler且propagate=False,第三方库(urllib3、httpx 等) 的日志不会被卷入。如果你更喜欢"包级挂一次、子模块走 stdlib + propagate"的传统模式, 调kitty_logger.getLogger("myapp", propagate=True)即可。 - 如果传了
attach_main_logger=True让主进程 root 也挂上 SocketHandler,请不要 在此之前调用logging.basicConfig()或自行给 root 挂StreamHandler,否则会出现 双倍输出。要么让 kitty_logger 做唯一入口,要么保持默认False自行管理 root。 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.dev1.tar.gz.
File metadata
- Download URL: kitty_logger-0.2.0.dev1.tar.gz
- Upload date:
- Size: 19.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 |
d732b76c70cd472907f24368d5b0092ca487e7a02af165aaea9287ba4f8fa61b
|
|
| MD5 |
714d93c5d07c29dd4cd7a83589e454d8
|
|
| BLAKE2b-256 |
67eab68d0afc215a5675592d2600fdd1f06c962ce7fd3c6ad2d596a6b1a76630
|
File details
Details for the file kitty_logger-0.2.0.dev1-py3-none-any.whl.
File metadata
- Download URL: kitty_logger-0.2.0.dev1-py3-none-any.whl
- Upload date:
- Size: 18.2 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 |
46021ec89e0be6809d2f59ed3813c6a3d63382d256015a3972bca583b94cac78
|
|
| MD5 |
cc10f3faa3cbc097836a0fc782df85c1
|
|
| BLAKE2b-256 |
3f5208769d3caacdfc975d1b1c17672ffb22c102304c6a24f6fda980a218cf13
|