kitty-logger 0.2.0.dev4__tar.gz → 0.2.0.dev6__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.dev6/LICENSE +9 -0
- {kitty_logger-0.2.0.dev4/src/kitty_logger.egg-info → kitty_logger-0.2.0.dev6}/PKG-INFO +1 -1
- {kitty_logger-0.2.0.dev4 → kitty_logger-0.2.0.dev6}/pyproject.toml +1 -1
- {kitty_logger-0.2.0.dev4 → kitty_logger-0.2.0.dev6}/src/kitty_logger/__init__.py +1 -1
- {kitty_logger-0.2.0.dev4 → kitty_logger-0.2.0.dev6}/src/kitty_logger/_client.py +49 -18
- {kitty_logger-0.2.0.dev4 → kitty_logger-0.2.0.dev6/src/kitty_logger.egg-info}/PKG-INFO +1 -1
- {kitty_logger-0.2.0.dev4 → kitty_logger-0.2.0.dev6}/tests/test_kitty_logger.py +29 -3
- kitty_logger-0.2.0.dev4/LICENSE +0 -21
- {kitty_logger-0.2.0.dev4 → kitty_logger-0.2.0.dev6}/README.md +0 -0
- {kitty_logger-0.2.0.dev4 → kitty_logger-0.2.0.dev6}/setup.cfg +0 -0
- {kitty_logger-0.2.0.dev4 → kitty_logger-0.2.0.dev6}/src/kitty_logger/_env.py +0 -0
- {kitty_logger-0.2.0.dev4 → kitty_logger-0.2.0.dev6}/src/kitty_logger/_formatters.py +0 -0
- {kitty_logger-0.2.0.dev4 → kitty_logger-0.2.0.dev6}/src/kitty_logger/_server.py +0 -0
- {kitty_logger-0.2.0.dev4 → kitty_logger-0.2.0.dev6}/src/kitty_logger/_server_main.py +0 -0
- {kitty_logger-0.2.0.dev4 → kitty_logger-0.2.0.dev6}/src/kitty_logger/_setup.py +0 -0
- {kitty_logger-0.2.0.dev4 → kitty_logger-0.2.0.dev6}/src/kitty_logger.egg-info/SOURCES.txt +0 -0
- {kitty_logger-0.2.0.dev4 → kitty_logger-0.2.0.dev6}/src/kitty_logger.egg-info/dependency_links.txt +0 -0
- {kitty_logger-0.2.0.dev4 → kitty_logger-0.2.0.dev6}/src/kitty_logger.egg-info/requires.txt +0 -0
- {kitty_logger-0.2.0.dev4 → kitty_logger-0.2.0.dev6}/src/kitty_logger.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kitty
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -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.dev6"
|
|
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"
|
|
@@ -32,16 +32,18 @@ KITTY_NAMESPACE = "kitty"
|
|
|
32
32
|
_lock = threading.Lock()
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
def _read_endpoint() -> tuple[str, int]:
|
|
36
|
-
"""从环境变量读出 ``(host, port)
|
|
35
|
+
def _read_endpoint() -> tuple[str, int] | None:
|
|
36
|
+
"""从环境变量读出 ``(host, port)``;未设置则返回 ``None``。
|
|
37
|
+
|
|
38
|
+
返回 ``None`` 表示当前进程树尚未调用 :func:`setup_logging`。这是
|
|
39
|
+
合法状态——用户可能在模块顶层先 ``log = getLogger(__name__)``、
|
|
40
|
+
后续才调 ``setup_logging``,期间发出的日志按"无 handler"处理,
|
|
41
|
+
不强制报错。
|
|
42
|
+
"""
|
|
37
43
|
host = os.environ.get(ENV_HOST)
|
|
38
44
|
port = os.environ.get(ENV_PORT)
|
|
39
45
|
if not host or not port:
|
|
40
|
-
|
|
41
|
-
"kitty_logger 尚未在当前进程树中初始化。"
|
|
42
|
-
+ "请先在主进程调用 kitty_logger.setup_logging(),"
|
|
43
|
-
+ "再创建(spawn)子进程或调用 getLogger()。"
|
|
44
|
-
)
|
|
46
|
+
return None
|
|
45
47
|
return host, int(port)
|
|
46
48
|
|
|
47
49
|
|
|
@@ -58,10 +60,17 @@ def _read_level() -> int:
|
|
|
58
60
|
|
|
59
61
|
|
|
60
62
|
def _ensure_kitty_handler() -> logging.Logger:
|
|
61
|
-
"""
|
|
63
|
+
"""尽力保证本进程内 ``kitty`` logger 已挂上指向日志服务的 SocketHandler。
|
|
64
|
+
|
|
65
|
+
幂等且容忍未初始化:
|
|
62
66
|
|
|
63
|
-
|
|
64
|
-
|
|
67
|
+
- 已经挂过 SocketHandler:直接返回。
|
|
68
|
+
- ENV 中没有端点(尚未 ``setup_logging``):返回未挂 handler 的
|
|
69
|
+
``kitty`` logger。此时 ``kitty`` 仍保持默认 ``propagate=True``,
|
|
70
|
+
用户在 ``setup_logging`` 之前发出的日志会冒到 root(沿用标准
|
|
71
|
+
库行为),等到 ``setup_logging`` 真正调用时再来一次本函数完成
|
|
72
|
+
挂载与 ``propagate=False`` 的切换。
|
|
73
|
+
- ENV 存在:装 SocketHandler、按需设置 level、关闭 propagate。
|
|
65
74
|
|
|
66
75
|
.. note::
|
|
67
76
|
:class:`logging.handlers.SocketHandler` 直接 pickle ``LogRecord``
|
|
@@ -76,7 +85,14 @@ def _ensure_kitty_handler() -> logging.Logger:
|
|
|
76
85
|
if isinstance(h, SocketHandler):
|
|
77
86
|
return kitty
|
|
78
87
|
|
|
79
|
-
|
|
88
|
+
endpoint = _read_endpoint()
|
|
89
|
+
if endpoint is None:
|
|
90
|
+
# 尚未 setup_logging:保持 ``kitty`` 处于"无 handler、向 root
|
|
91
|
+
# 冒泡"的标准状态,让用户即使在 setup 之前调 getLogger 也不
|
|
92
|
+
# 会炸。后续调 setup_logging 时会再次进入本函数完成真正挂载。
|
|
93
|
+
return kitty
|
|
94
|
+
|
|
95
|
+
host, port = endpoint
|
|
80
96
|
level = _read_level()
|
|
81
97
|
|
|
82
98
|
kitty.addHandler(SocketHandler(host, port))
|
|
@@ -94,19 +110,34 @@ def _ensure_kitty_handler() -> logging.Logger:
|
|
|
94
110
|
return kitty
|
|
95
111
|
|
|
96
112
|
|
|
97
|
-
def getLogger(
|
|
98
|
-
|
|
113
|
+
def getLogger(
|
|
114
|
+
name: str | None = None,
|
|
115
|
+
*,
|
|
116
|
+
level: int | str | None = None,
|
|
117
|
+
) -> logging.Logger:
|
|
118
|
+
"""返回挂在 ``kitty`` 命名空间下的 logger。
|
|
119
|
+
|
|
120
|
+
可在 :func:`kitty_logger.setup_logging` 之前调用——例如在模块顶层
|
|
121
|
+
写 ``log = getLogger(__name__)``。此时拿到的 logger 还没有连上日志
|
|
122
|
+
服务,等 ``setup_logging`` 实际执行后会自动生效(通过 ``kitty``
|
|
123
|
+
祖先 logger 上的 SocketHandler)。
|
|
99
124
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
125
|
+
本库只支持 ``spawn`` 启动方式;spawn 出来的子进程模块级状态天然为
|
|
126
|
+
空,第一次调用 ``getLogger`` 时会按需完成 SocketHandler 挂载(依赖
|
|
127
|
+
父进程通过 ENV 传入的端点)。
|
|
103
128
|
|
|
104
129
|
:param name: 业务名;``None`` 表示直接返回 ``kitty`` 本身。``"foo"``
|
|
105
130
|
会被转换为 ``logging.getLogger("kitty.foo")``——日志记录里
|
|
106
131
|
``%(name)s`` 字段会带 ``kitty.`` 前缀,这是有意保留的标记,方便
|
|
107
132
|
和第三方库日志区分。
|
|
108
|
-
:
|
|
133
|
+
:param level: 可选;为该 logger 设置 level。等价于 ``getLogger(name)``
|
|
134
|
+
之后再调 ``.setLevel(level)``。``None`` 表示保持默认 ``NOTSET``,
|
|
135
|
+
向上沿用 ``kitty`` 根 logger 的级别。支持 ``logging.DEBUG`` 这样
|
|
136
|
+
的整数,也支持 ``"DEBUG"`` 这样的级别名(大小写不敏感)。
|
|
109
137
|
"""
|
|
110
138
|
_ensure_kitty_handler()
|
|
111
139
|
full = KITTY_NAMESPACE if not name else f"{KITTY_NAMESPACE}.{name}"
|
|
112
|
-
|
|
140
|
+
logger = logging.getLogger(full)
|
|
141
|
+
if level is not None:
|
|
142
|
+
logger.setLevel(level)
|
|
143
|
+
return logger
|
|
@@ -111,12 +111,38 @@ def test_shutdown_logging_idempotent(tmp_path: Path):
|
|
|
111
111
|
kitty_logger.shutdown_logging()
|
|
112
112
|
|
|
113
113
|
|
|
114
|
-
def
|
|
114
|
+
def test_get_logger_before_setup_works(tmp_path: Path):
|
|
115
|
+
"""允许在 ``setup_logging`` 之前 ``getLogger``——典型用法是模块顶层
|
|
116
|
+
``log = getLogger(__name__)``。setup 之后日志应能正常落到服务端。"""
|
|
115
117
|
# 必须没有环境变量。
|
|
116
118
|
for k in ("KITTY_LOGGER_HOST", "KITTY_LOGGER_PORT"):
|
|
117
119
|
os.environ.pop(k, None)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
+
|
|
121
|
+
# 还没 setup 就 getLogger:不应抛错,拿到的 logger 暂无 SocketHandler。
|
|
122
|
+
log = kitty_logger.getLogger("early")
|
|
123
|
+
assert not any(
|
|
124
|
+
isinstance(h, logging.handlers.SocketHandler)
|
|
125
|
+
for h in logging.getLogger("kitty").handlers
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
# setup 之后再用同一个 logger 写日志:应当落到文件。
|
|
129
|
+
log_path = tmp_path / "app.log"
|
|
130
|
+
kitty_logger.setup_logging(log_file=str(log_path), stream=False)
|
|
131
|
+
log.info("late-binding-ok")
|
|
132
|
+
_wait_for_lines(log_path, lambda t: "late-binding-ok" in t)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def test_get_logger_level_param():
|
|
136
|
+
"""``level=`` 参数等价于 ``.setLevel(level)``,支持整数与级别名。"""
|
|
137
|
+
log_int = kitty_logger.getLogger("lvl.int", level=logging.DEBUG)
|
|
138
|
+
assert log_int.level == logging.DEBUG
|
|
139
|
+
|
|
140
|
+
log_str = kitty_logger.getLogger("lvl.str", level="WARNING")
|
|
141
|
+
assert log_str.level == logging.WARNING
|
|
142
|
+
|
|
143
|
+
# 不传 level:保持默认 NOTSET,沿用祖先级别。
|
|
144
|
+
log_default = kitty_logger.getLogger("lvl.default")
|
|
145
|
+
assert log_default.level == logging.NOTSET
|
|
120
146
|
|
|
121
147
|
|
|
122
148
|
def test_non_loopback_raises(tmp_path: Path):
|
kitty_logger-0.2.0.dev4/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Kitty
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kitty_logger-0.2.0.dev4 → kitty_logger-0.2.0.dev6}/src/kitty_logger.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|