kitty-logger 0.2.0.dev0__tar.gz → 0.2.0.dev1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {kitty_logger-0.2.0.dev0/src/kitty_logger.egg-info → kitty_logger-0.2.0.dev1}/PKG-INFO +16 -8
- {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/README.md +15 -7
- {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/pyproject.toml +1 -1
- {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/src/kitty_logger/__init__.py +1 -1
- {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/src/kitty_logger/_client.py +11 -5
- {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/src/kitty_logger/_setup.py +6 -2
- {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1/src/kitty_logger.egg-info}/PKG-INFO +16 -8
- {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/tests/test_kitty_logger.py +3 -1
- {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/LICENSE +0 -0
- {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/setup.cfg +0 -0
- {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/src/kitty_logger/_env.py +0 -0
- {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/src/kitty_logger/_formatters.py +0 -0
- {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/src/kitty_logger/_server.py +0 -0
- {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/src/kitty_logger.egg-info/SOURCES.txt +0 -0
- {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/src/kitty_logger.egg-info/dependency_links.txt +0 -0
- {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/src/kitty_logger.egg-info/requires.txt +0 -0
- {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/src/kitty_logger.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kitty_logger
|
|
3
|
-
Version: 0.2.0.
|
|
3
|
+
Version: 0.2.0.dev1
|
|
4
4
|
Summary: Cross-process logging via a dedicated log server process and SocketHandler.
|
|
5
5
|
Author: Kitty
|
|
6
6
|
License: MIT
|
|
@@ -54,12 +54,18 @@ if __name__ == "__main__":
|
|
|
54
54
|
|
|
55
55
|
## API
|
|
56
56
|
|
|
57
|
-
- `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=
|
|
57
|
+
- `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)`
|
|
58
58
|
启动日志服务子进程(始终使用 `spawn`)。幂等。已通过 `atexit` 注册清理。
|
|
59
59
|
`port=0` 让操作系统挑选空闲端口;返回真实绑定到的 `(host, port)`。
|
|
60
60
|
**`host` 必须是 loopback**——绑定非 loopback 地址会直接 `ValueError`。
|
|
61
|
-
|
|
61
|
+
默认**不动**主进程 root logger;想让某个 logger 走 kitty_logger,请显式
|
|
62
|
+
`kitty_logger.getLogger(...)`。如果希望主进程 root 也自动挂上 SocketHandler,
|
|
63
|
+
传 `attach_main_logger=True`。
|
|
64
|
+
- `getLogger(name=None, *, propagate=False) -> logging.Logger`
|
|
62
65
|
返回一个挂好 `SocketHandler`、指向日志服务的 logger。
|
|
66
|
+
默认 **`propagate=False`**:每个 logger 独立挂载,互不干扰;想让子 logger
|
|
67
|
+
通过祖先链冒泡到这个 logger 时(`getLogger("myapp")` 接住 `myapp.svc.x` 等),
|
|
68
|
+
传 `propagate=True`。对 root logger 该参数没有意义。
|
|
63
69
|
- `shutdown_logging()` — 显式停止日志服务子进程。
|
|
64
70
|
|
|
65
71
|
## 为什么只支持 spawn
|
|
@@ -74,11 +80,13 @@ if __name__ == "__main__":
|
|
|
74
80
|
|
|
75
81
|
## 注意事项
|
|
76
82
|
|
|
77
|
-
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
83
|
+
- 默认每个 logger 都是**显式加入、互不传播**的:业务代码里 `kitty_logger.getLogger(__name__)`
|
|
84
|
+
得到的 logger 自带 `SocketHandler` 且 `propagate=False`,第三方库(urllib3、httpx 等)
|
|
85
|
+
的日志不会被卷入。如果你更喜欢"包级挂一次、子模块走 stdlib + propagate"的传统模式,
|
|
86
|
+
调 `kitty_logger.getLogger("myapp", propagate=True)` 即可。
|
|
87
|
+
- 如果传了 `attach_main_logger=True` 让主进程 root 也挂上 SocketHandler,请**不要**
|
|
88
|
+
在此之前调用 `logging.basicConfig()` 或自行给 root 挂 `StreamHandler`,否则会出现
|
|
89
|
+
双倍输出。要么让 kitty_logger 做唯一入口,要么保持默认 `False` 自行管理 root。
|
|
82
90
|
- `shutdown_logging()` 会卸载本进程内 kitty_logger 自己挂的
|
|
83
91
|
`SocketHandler`,并清理 `KITTY_LOGGER_*` 环境变量,确保进程状态与
|
|
84
92
|
`setup_logging` 对称。如果你额外挂了别的 handler,仍由你自己负责清理。
|
|
@@ -41,12 +41,18 @@ if __name__ == "__main__":
|
|
|
41
41
|
|
|
42
42
|
## API
|
|
43
43
|
|
|
44
|
-
- `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=
|
|
44
|
+
- `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)`
|
|
45
45
|
启动日志服务子进程(始终使用 `spawn`)。幂等。已通过 `atexit` 注册清理。
|
|
46
46
|
`port=0` 让操作系统挑选空闲端口;返回真实绑定到的 `(host, port)`。
|
|
47
47
|
**`host` 必须是 loopback**——绑定非 loopback 地址会直接 `ValueError`。
|
|
48
|
-
|
|
48
|
+
默认**不动**主进程 root logger;想让某个 logger 走 kitty_logger,请显式
|
|
49
|
+
`kitty_logger.getLogger(...)`。如果希望主进程 root 也自动挂上 SocketHandler,
|
|
50
|
+
传 `attach_main_logger=True`。
|
|
51
|
+
- `getLogger(name=None, *, propagate=False) -> logging.Logger`
|
|
49
52
|
返回一个挂好 `SocketHandler`、指向日志服务的 logger。
|
|
53
|
+
默认 **`propagate=False`**:每个 logger 独立挂载,互不干扰;想让子 logger
|
|
54
|
+
通过祖先链冒泡到这个 logger 时(`getLogger("myapp")` 接住 `myapp.svc.x` 等),
|
|
55
|
+
传 `propagate=True`。对 root logger 该参数没有意义。
|
|
50
56
|
- `shutdown_logging()` — 显式停止日志服务子进程。
|
|
51
57
|
|
|
52
58
|
## 为什么只支持 spawn
|
|
@@ -61,11 +67,13 @@ if __name__ == "__main__":
|
|
|
61
67
|
|
|
62
68
|
## 注意事项
|
|
63
69
|
|
|
64
|
-
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
70
|
+
- 默认每个 logger 都是**显式加入、互不传播**的:业务代码里 `kitty_logger.getLogger(__name__)`
|
|
71
|
+
得到的 logger 自带 `SocketHandler` 且 `propagate=False`,第三方库(urllib3、httpx 等)
|
|
72
|
+
的日志不会被卷入。如果你更喜欢"包级挂一次、子模块走 stdlib + propagate"的传统模式,
|
|
73
|
+
调 `kitty_logger.getLogger("myapp", propagate=True)` 即可。
|
|
74
|
+
- 如果传了 `attach_main_logger=True` 让主进程 root 也挂上 SocketHandler,请**不要**
|
|
75
|
+
在此之前调用 `logging.basicConfig()` 或自行给 root 挂 `StreamHandler`,否则会出现
|
|
76
|
+
双倍输出。要么让 kitty_logger 做唯一入口,要么保持默认 `False` 自行管理 root。
|
|
69
77
|
- `shutdown_logging()` 会卸载本进程内 kitty_logger 自己挂的
|
|
70
78
|
`SocketHandler`,并清理 `KITTY_LOGGER_*` 环境变量,确保进程状态与
|
|
71
79
|
`setup_logging` 对称。如果你额外挂了别的 handler,仍由你自己负责清理。
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "kitty_logger"
|
|
7
|
-
version = "0.2.0.
|
|
7
|
+
version = "0.2.0.dev1"
|
|
8
8
|
description = "Cross-process logging via a dedicated log server process and SocketHandler."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.12"
|
|
@@ -51,6 +51,7 @@ def _attach_socket_handler(
|
|
|
51
51
|
host: str,
|
|
52
52
|
port: int,
|
|
53
53
|
level: int,
|
|
54
|
+
propagate: bool,
|
|
54
55
|
) -> None:
|
|
55
56
|
"""给 ``logger`` 挂上指向日志服务的 :class:`SocketHandler`。
|
|
56
57
|
|
|
@@ -74,13 +75,14 @@ def _attach_socket_handler(
|
|
|
74
75
|
if logger.level == logging.NOTSET:
|
|
75
76
|
logger.setLevel(level)
|
|
76
77
|
|
|
77
|
-
#
|
|
78
|
-
#
|
|
78
|
+
# 默认关闭向上传播:每个 logger 独立挂 SocketHandler,互不干扰,
|
|
79
|
+
# 也避免与第三方库共用 root handler 时的串扰。root 自身没有父级,
|
|
80
|
+
# 跳过此项。需要让子 logger 通过祖先链冒泡上来时显式 propagate=True。
|
|
79
81
|
if logger is not logging.getLogger():
|
|
80
|
-
logger.propagate =
|
|
82
|
+
logger.propagate = propagate
|
|
81
83
|
|
|
82
84
|
|
|
83
|
-
def getLogger(name: str | None = None) -> logging.Logger:
|
|
85
|
+
def getLogger(name: str | None = None, *, propagate: bool = False) -> logging.Logger:
|
|
84
86
|
"""返回一个会把日志通过 :class:`SocketHandler` 发送到日志服务的 logger。
|
|
85
87
|
|
|
86
88
|
必须在父进程已经调用过 :func:`kitty_logger.setup_logging` 之后才能
|
|
@@ -88,6 +90,10 @@ def getLogger(name: str | None = None) -> logging.Logger:
|
|
|
88
90
|
天然为空,因此不需要处理"继承自父进程的 SocketHandler"问题。
|
|
89
91
|
|
|
90
92
|
:param name: logger 名;``None`` 表示 root logger。
|
|
93
|
+
:param propagate: 是否允许该 logger 把记录继续向上传播给父级 logger。
|
|
94
|
+
默认 ``False``——每个 logger 独立挂 SocketHandler,互不干扰;
|
|
95
|
+
想让子 logger 通过祖先链冒泡到这个 logger 时设为 ``True``。
|
|
96
|
+
对 root logger 该参数没有意义(root 没有父级),会被忽略。
|
|
91
97
|
:raises RuntimeError: 当前进程树尚未调用 ``setup_logging``。
|
|
92
98
|
"""
|
|
93
99
|
host, port = _read_endpoint()
|
|
@@ -97,6 +103,6 @@ def getLogger(name: str | None = None) -> logging.Logger:
|
|
|
97
103
|
with _lock:
|
|
98
104
|
key = name or ""
|
|
99
105
|
if key not in _configured_loggers:
|
|
100
|
-
_attach_socket_handler(logger, host, port, level)
|
|
106
|
+
_attach_socket_handler(logger, host, port, level, propagate)
|
|
101
107
|
_configured_loggers.add(key)
|
|
102
108
|
return logger
|
|
@@ -128,7 +128,7 @@ def setup_logging(
|
|
|
128
128
|
console_fmt: str = DEFAULT_CONSOLE_FMT,
|
|
129
129
|
file_fmt: str = DEFAULT_FILE_FMT,
|
|
130
130
|
datefmt: str | None = None,
|
|
131
|
-
attach_main_logger: bool =
|
|
131
|
+
attach_main_logger: bool = False,
|
|
132
132
|
) -> tuple[str, int]:
|
|
133
133
|
"""在主进程里启动跨进程日志服务,返回服务真实绑定到的 ``(host, port)``。
|
|
134
134
|
|
|
@@ -154,6 +154,8 @@ def setup_logging(
|
|
|
154
154
|
:param datefmt: 时间戳的 ``strftime`` 格式;``None`` 走默认值。
|
|
155
155
|
:param attach_main_logger: 是否给主进程的 root logger 也挂一个
|
|
156
156
|
:class:`SocketHandler`,让主进程自身的日志走同一个服务。
|
|
157
|
+
默认 ``False``——主进程 root 保持不动;想让某个 logger 走
|
|
158
|
+
kitty_logger,请显式调用 :func:`kitty_logger.getLogger`。
|
|
157
159
|
:return: 服务真实绑定到的 ``(host, port)``。
|
|
158
160
|
|
|
159
161
|
.. note::
|
|
@@ -230,7 +232,9 @@ def setup_logging(
|
|
|
230
232
|
# 让主进程自身的日志也走同一个服务,避免输出渠道分裂。
|
|
231
233
|
from ._client import _attach_socket_handler
|
|
232
234
|
|
|
233
|
-
_attach_socket_handler(
|
|
235
|
+
_attach_socket_handler(
|
|
236
|
+
logging.getLogger(), bound_host, bound_port, level, propagate=False
|
|
237
|
+
)
|
|
234
238
|
|
|
235
239
|
_ = atexit.register(shutdown_logging)
|
|
236
240
|
return bound_host, bound_port
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kitty_logger
|
|
3
|
-
Version: 0.2.0.
|
|
3
|
+
Version: 0.2.0.dev1
|
|
4
4
|
Summary: Cross-process logging via a dedicated log server process and SocketHandler.
|
|
5
5
|
Author: Kitty
|
|
6
6
|
License: MIT
|
|
@@ -54,12 +54,18 @@ if __name__ == "__main__":
|
|
|
54
54
|
|
|
55
55
|
## API
|
|
56
56
|
|
|
57
|
-
- `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=
|
|
57
|
+
- `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)`
|
|
58
58
|
启动日志服务子进程(始终使用 `spawn`)。幂等。已通过 `atexit` 注册清理。
|
|
59
59
|
`port=0` 让操作系统挑选空闲端口;返回真实绑定到的 `(host, port)`。
|
|
60
60
|
**`host` 必须是 loopback**——绑定非 loopback 地址会直接 `ValueError`。
|
|
61
|
-
|
|
61
|
+
默认**不动**主进程 root logger;想让某个 logger 走 kitty_logger,请显式
|
|
62
|
+
`kitty_logger.getLogger(...)`。如果希望主进程 root 也自动挂上 SocketHandler,
|
|
63
|
+
传 `attach_main_logger=True`。
|
|
64
|
+
- `getLogger(name=None, *, propagate=False) -> logging.Logger`
|
|
62
65
|
返回一个挂好 `SocketHandler`、指向日志服务的 logger。
|
|
66
|
+
默认 **`propagate=False`**:每个 logger 独立挂载,互不干扰;想让子 logger
|
|
67
|
+
通过祖先链冒泡到这个 logger 时(`getLogger("myapp")` 接住 `myapp.svc.x` 等),
|
|
68
|
+
传 `propagate=True`。对 root logger 该参数没有意义。
|
|
63
69
|
- `shutdown_logging()` — 显式停止日志服务子进程。
|
|
64
70
|
|
|
65
71
|
## 为什么只支持 spawn
|
|
@@ -74,11 +80,13 @@ if __name__ == "__main__":
|
|
|
74
80
|
|
|
75
81
|
## 注意事项
|
|
76
82
|
|
|
77
|
-
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
83
|
+
- 默认每个 logger 都是**显式加入、互不传播**的:业务代码里 `kitty_logger.getLogger(__name__)`
|
|
84
|
+
得到的 logger 自带 `SocketHandler` 且 `propagate=False`,第三方库(urllib3、httpx 等)
|
|
85
|
+
的日志不会被卷入。如果你更喜欢"包级挂一次、子模块走 stdlib + propagate"的传统模式,
|
|
86
|
+
调 `kitty_logger.getLogger("myapp", propagate=True)` 即可。
|
|
87
|
+
- 如果传了 `attach_main_logger=True` 让主进程 root 也挂上 SocketHandler,请**不要**
|
|
88
|
+
在此之前调用 `logging.basicConfig()` 或自行给 root 挂 `StreamHandler`,否则会出现
|
|
89
|
+
双倍输出。要么让 kitty_logger 做唯一入口,要么保持默认 `False` 自行管理 root。
|
|
82
90
|
- `shutdown_logging()` 会卸载本进程内 kitty_logger 自己挂的
|
|
83
91
|
`SocketHandler`,并清理 `KITTY_LOGGER_*` 环境变量,确保进程状态与
|
|
84
92
|
`setup_logging` 对称。如果你额外挂了别的 handler,仍由你自己负责清理。
|
|
@@ -218,7 +218,9 @@ def test_level_env_accepts_name(tmp_path: Path):
|
|
|
218
218
|
def test_shutdown_cleans_state(tmp_path: Path):
|
|
219
219
|
"""shutdown 后:root 上的 SocketHandler 被卸载、ENV 被清、_configured_loggers 清空。"""
|
|
220
220
|
log_path = tmp_path / "app.log"
|
|
221
|
-
kitty_logger.setup_logging(
|
|
221
|
+
kitty_logger.setup_logging(
|
|
222
|
+
log_file=str(log_path), stream=False, attach_main_logger=True
|
|
223
|
+
)
|
|
222
224
|
_ = kitty_logger.getLogger("svc.a")
|
|
223
225
|
|
|
224
226
|
assert os.environ.get("KITTY_LOGGER_HOST")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/src/kitty_logger.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|