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.
Files changed (17) hide show
  1. {kitty_logger-0.2.0.dev0/src/kitty_logger.egg-info → kitty_logger-0.2.0.dev1}/PKG-INFO +16 -8
  2. {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/README.md +15 -7
  3. {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/pyproject.toml +1 -1
  4. {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/src/kitty_logger/__init__.py +1 -1
  5. {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/src/kitty_logger/_client.py +11 -5
  6. {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/src/kitty_logger/_setup.py +6 -2
  7. {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1/src/kitty_logger.egg-info}/PKG-INFO +16 -8
  8. {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/tests/test_kitty_logger.py +3 -1
  9. {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/LICENSE +0 -0
  10. {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/setup.cfg +0 -0
  11. {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/src/kitty_logger/_env.py +0 -0
  12. {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/src/kitty_logger/_formatters.py +0 -0
  13. {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/src/kitty_logger/_server.py +0 -0
  14. {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/src/kitty_logger.egg-info/SOURCES.txt +0 -0
  15. {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/src/kitty_logger.egg-info/dependency_links.txt +0 -0
  16. {kitty_logger-0.2.0.dev0 → kitty_logger-0.2.0.dev1}/src/kitty_logger.egg-info/requires.txt +0 -0
  17. {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.dev0
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=True) -> (host, port)`
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
- - `getLogger(name=None) -> logging.Logger`
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
- - **不要**在 `setup_logging(attach_main_logger=True)` 之前调用
78
- `logging.basicConfig()`(或自行给 root logger `StreamHandler`)——
79
- 否则主进程会把每条记录输出两次:一次走本地 root handler,一次走日志
80
- 服务。要么让 kitty_logger 做唯一的配置入口,要么传
81
- `attach_main_logger=False` 自行管理主进程的 handler。
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=True) -> (host, port)`
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
- - `getLogger(name=None) -> logging.Logger`
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
- - **不要**在 `setup_logging(attach_main_logger=True)` 之前调用
65
- `logging.basicConfig()`(或自行给 root logger `StreamHandler`)——
66
- 否则主进程会把每条记录输出两次:一次走本地 root handler,一次走日志
67
- 服务。要么让 kitty_logger 做唯一的配置入口,要么传
68
- `attach_main_logger=False` 自行管理主进程的 handler。
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.dev0"
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"
@@ -28,4 +28,4 @@ from ._client import getLogger
28
28
  from ._setup import setup_logging, shutdown_logging
29
29
 
30
30
  __all__ = ["setup_logging", "shutdown_logging", "getLogger"]
31
- __version__ = "0.2.0.dev0"
31
+ __version__ = "0.2.0.dev1"
@@ -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
- # 关闭向 root 的传播,避免与已存在的 root handler(比如调用过
78
- # ``basicConfig``)造成重复输出。root 自身没有父级,跳过此项。
78
+ # 默认关闭向上传播:每个 logger 独立挂 SocketHandler,互不干扰,
79
+ # 也避免与第三方库共用 root handler 时的串扰。root 自身没有父级,
80
+ # 跳过此项。需要让子 logger 通过祖先链冒泡上来时显式 propagate=True。
79
81
  if logger is not logging.getLogger():
80
- logger.propagate = False
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 = True,
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(logging.getLogger(), bound_host, bound_port, level)
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.dev0
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=True) -> (host, port)`
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
- - `getLogger(name=None) -> logging.Logger`
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
- - **不要**在 `setup_logging(attach_main_logger=True)` 之前调用
78
- `logging.basicConfig()`(或自行给 root logger `StreamHandler`)——
79
- 否则主进程会把每条记录输出两次:一次走本地 root handler,一次走日志
80
- 服务。要么让 kitty_logger 做唯一的配置入口,要么传
81
- `attach_main_logger=False` 自行管理主进程的 handler。
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(log_file=str(log_path), stream=False)
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")