farlog 1.1.7__py3-none-any.whl
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.
- farlog/__init__.py +3 -0
- farlog/core.py +109 -0
- farlog-1.1.7.dist-info/METADATA +135 -0
- farlog-1.1.7.dist-info/RECORD +7 -0
- farlog-1.1.7.dist-info/WHEEL +5 -0
- farlog-1.1.7.dist-info/licenses/LICENSE +21 -0
- farlog-1.1.7.dist-info/top_level.txt +1 -0
farlog/__init__.py
ADDED
farlog/core.py
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from threading import Lock
|
|
6
|
+
|
|
7
|
+
from loguru import logger
|
|
8
|
+
|
|
9
|
+
_DEFAULT_FORMAT = (
|
|
10
|
+
"{time:YYYY-MM-DD HH:mm:ss.SSS} |{level:8}| "
|
|
11
|
+
"{name} : {module}:{line:4} | {extra[module_name]} | - {message}"
|
|
12
|
+
)
|
|
13
|
+
_DEFAULT_FORMAT_COLOR = (
|
|
14
|
+
"{time:YYYY-MM-DD HH:mm:ss.SSS} |<lvl>{level:8}</>| "
|
|
15
|
+
"{name} : {module}:{line:4} | <cyan>{extra[module_name]}</> | - <lvl>{message}</>"
|
|
16
|
+
)
|
|
17
|
+
_log_dir = Path("logs")
|
|
18
|
+
_loggers = {}
|
|
19
|
+
_lock = Lock()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _ensure_log_dir(log_dir: str | Path) -> Path:
|
|
23
|
+
path = Path(log_dir)
|
|
24
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
25
|
+
return path
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _add_file_handler(name: str, level: str, formatter: str) -> int:
|
|
29
|
+
return logger.add(
|
|
30
|
+
sink=_log_dir / f"{name}.log",
|
|
31
|
+
format=formatter,
|
|
32
|
+
filter=lambda record, _name=name: record["extra"].get("module_name") == _name,
|
|
33
|
+
level=level,
|
|
34
|
+
rotation="00:00",
|
|
35
|
+
compression="gz",
|
|
36
|
+
retention=7,
|
|
37
|
+
colorize=False,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def configure(log_dir: str | Path = "logs") -> None:
|
|
42
|
+
"""Explicitly configure console and aggregate file logging."""
|
|
43
|
+
global _log_dir
|
|
44
|
+
|
|
45
|
+
with _lock:
|
|
46
|
+
path = _ensure_log_dir(log_dir)
|
|
47
|
+
logger.configure(
|
|
48
|
+
handlers=[
|
|
49
|
+
{
|
|
50
|
+
"sink": sys.stderr,
|
|
51
|
+
"format": _DEFAULT_FORMAT_COLOR,
|
|
52
|
+
"colorize": True,
|
|
53
|
+
"level": "INFO",
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"sink": path / "all.log",
|
|
57
|
+
"format": _DEFAULT_FORMAT,
|
|
58
|
+
"colorize": False,
|
|
59
|
+
"rotation": "00:00",
|
|
60
|
+
"compression": "gz",
|
|
61
|
+
"retention": 30,
|
|
62
|
+
"level": "INFO",
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
extra={"module_name": "-"},
|
|
66
|
+
)
|
|
67
|
+
_log_dir = path
|
|
68
|
+
|
|
69
|
+
for name, (level, formatter, _, bound_logger) in list(_loggers.items()):
|
|
70
|
+
handler_id = _add_file_handler(name, level, formatter)
|
|
71
|
+
_loggers[name] = (level, formatter, handler_id, bound_logger)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _validate_name(name: str) -> None:
|
|
75
|
+
if (
|
|
76
|
+
not isinstance(name, str)
|
|
77
|
+
or not name
|
|
78
|
+
or name in {".", ".."}
|
|
79
|
+
or Path(name).name != name
|
|
80
|
+
or "\0" in name
|
|
81
|
+
):
|
|
82
|
+
raise ValueError("logger name must be a non-empty file name")
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def get_logger(
|
|
86
|
+
name: str = "default",
|
|
87
|
+
level: str = "INFO",
|
|
88
|
+
formatter: str | None = None,
|
|
89
|
+
):
|
|
90
|
+
"""Get a named logger with one rotating file handler."""
|
|
91
|
+
_validate_name(name)
|
|
92
|
+
selected_formatter = formatter or _DEFAULT_FORMAT
|
|
93
|
+
|
|
94
|
+
with _lock:
|
|
95
|
+
current = _loggers.get(name)
|
|
96
|
+
if current and current[:2] == (level, selected_formatter):
|
|
97
|
+
return current[3]
|
|
98
|
+
|
|
99
|
+
_ensure_log_dir(_log_dir)
|
|
100
|
+
handler_id = _add_file_handler(name, level, selected_formatter)
|
|
101
|
+
bound_logger = current[3] if current else logger.bind(module_name=name)
|
|
102
|
+
if current:
|
|
103
|
+
logger.remove(current[2])
|
|
104
|
+
_loggers[name] = (level, selected_formatter, handler_id, bound_logger)
|
|
105
|
+
return bound_logger
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
# Backward-compatible alias
|
|
109
|
+
getLogger = get_logger
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: farlog
|
|
3
|
+
Version: 1.1.7
|
|
4
|
+
Summary: Small Loguru helper for named rotating log files
|
|
5
|
+
Author-email: 牛哥 <niuliangtao@qq.com>, farfarfun <farfarfun@qq.com>
|
|
6
|
+
Maintainer-email: 牛哥 <niuliangtao@qq.com>, farfarfun <farfarfun@qq.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Project-URL: Organization, https://github.com/farfarfun
|
|
9
|
+
Project-URL: Repository, https://github.com/farfarfun/nltlog
|
|
10
|
+
Project-URL: Releases, https://github.com/farfarfun/nltlog/releases
|
|
11
|
+
Keywords: logging,loguru,rotation
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
|
+
Classifier: Topic :: System :: Logging
|
|
17
|
+
Requires-Python: >=3.9
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: loguru>=0.7.3
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
|
|
23
|
+
# farlog
|
|
24
|
+
|
|
25
|
+
`farlog` 是一个轻量的 [Loguru](https://github.com/Delgan/loguru) 辅助库,用于按名称拆分日志文件,并提供开箱即用的按日轮转、压缩和保留策略。
|
|
26
|
+
|
|
27
|
+
## 特性
|
|
28
|
+
|
|
29
|
+
- 导入包时不创建目录、不写文件,也不修改 Loguru 的全局 handler
|
|
30
|
+
- 每个 logger 名称对应一个独立日志文件
|
|
31
|
+
- 日志按日轮转,历史文件自动使用 gzip 压缩
|
|
32
|
+
- 可选生成聚合日志 `all.log`,同时统一控制台输出格式
|
|
33
|
+
- 重复获取同名 logger 不会重复添加 handler
|
|
34
|
+
- 兼容旧接口 `getLogger`
|
|
35
|
+
|
|
36
|
+
## 环境要求
|
|
37
|
+
|
|
38
|
+
- Python 3.9 或更高版本
|
|
39
|
+
|
|
40
|
+
## 安装
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install farlog
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## 快速开始
|
|
47
|
+
|
|
48
|
+
### 仅使用命名日志
|
|
49
|
+
|
|
50
|
+
直接调用 `get_logger()` 会保留应用已有的 Loguru handler,并在默认的 `logs/` 目录中创建命名日志文件。
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
from farlog import get_logger
|
|
54
|
+
|
|
55
|
+
log = get_logger("worker")
|
|
56
|
+
log.info("任务开始")
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
生成的文件:
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
logs/
|
|
63
|
+
└── worker.log
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 配置控制台和聚合日志
|
|
67
|
+
|
|
68
|
+
需要统一控制台格式或生成 `all.log` 时,在应用启动阶段显式调用 `configure()`:
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
from farlog import configure, get_logger
|
|
72
|
+
|
|
73
|
+
configure("logs")
|
|
74
|
+
|
|
75
|
+
log = get_logger("worker", level="DEBUG")
|
|
76
|
+
log.debug("调试信息")
|
|
77
|
+
log.info("任务开始")
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
生成的文件:
|
|
81
|
+
|
|
82
|
+
```text
|
|
83
|
+
logs/
|
|
84
|
+
├── all.log
|
|
85
|
+
└── worker.log
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
`configure()` 会替换 Loguru 的全局 handler。未绑定 `module_name` 的普通 Loguru 日志仍可正常输出,并在格式中显示为 `-`。
|
|
89
|
+
|
|
90
|
+
## API
|
|
91
|
+
|
|
92
|
+
### `configure(log_dir="logs")`
|
|
93
|
+
|
|
94
|
+
配置彩色控制台输出和聚合日志,并设置后续命名日志使用的目录。
|
|
95
|
+
|
|
96
|
+
- `log_dir`:日志目录,支持字符串或 `pathlib.Path`
|
|
97
|
+
- `all.log`:记录 `INFO` 及以上级别,按日轮转,保留最近 30 个文件
|
|
98
|
+
- 如果已经创建过命名 logger,其文件 handler 会切换到新目录
|
|
99
|
+
|
|
100
|
+
### `get_logger(name="default", level="INFO", formatter=None)`
|
|
101
|
+
|
|
102
|
+
获取带有独立文件 handler 的 Loguru logger。
|
|
103
|
+
|
|
104
|
+
- `name`:logger 名称,同时作为日志文件名;只允许普通文件名,不允许传入路径
|
|
105
|
+
- `level`:该命名日志文件的最低记录级别
|
|
106
|
+
- `formatter`:可选的 Loguru 格式字符串
|
|
107
|
+
- 命名日志按日轮转并压缩,保留最近 7 个文件
|
|
108
|
+
- 重复调用会复用同名 logger;修改 `level` 或 `formatter` 时会替换旧文件 handler
|
|
109
|
+
|
|
110
|
+
非法名称会抛出 `ValueError`:
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
get_logger("../outside") # ValueError
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
旧接口仍然可用:
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
from farlog import getLogger
|
|
120
|
+
|
|
121
|
+
log = getLogger("worker")
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## 开发
|
|
125
|
+
|
|
126
|
+
运行回归测试和静态检查:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
python -m unittest discover -s tests -v
|
|
130
|
+
ruff check .
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## 许可证
|
|
134
|
+
|
|
135
|
+
本项目使用 [MIT License](LICENSE)。
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
farlog/__init__.py,sha256=eUmH2zadWHXX4pbjxBpYgPSSzInxp4ToQgC17Psr9aI,103
|
|
2
|
+
farlog/core.py,sha256=oJf-mFNdBRRbRRvUh-1eZp1cGjV35weOqNVI6Wsry3M,3166
|
|
3
|
+
farlog-1.1.7.dist-info/licenses/LICENSE,sha256=BvvS-yeQjeaYgHQW2Vh7Msedpzoc-r7mnjNCpqUUbgM,1066
|
|
4
|
+
farlog-1.1.7.dist-info/METADATA,sha256=TNdNkC7t_v8My-wYGWg-wcvpg1m2yZtm9lFtseyqNko,3613
|
|
5
|
+
farlog-1.1.7.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
6
|
+
farlog-1.1.7.dist-info/top_level.txt,sha256=gF4NFCRgZnlro-8kPMBsdk83hVzC-G5Fsn2h3AWubVA,7
|
|
7
|
+
farlog-1.1.7.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 farfarfun
|
|
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.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
farlog
|