LogFly 2.5__tar.gz → 2.6.0__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.
- logfly-2.6.0/PKG-INFO +176 -0
- logfly-2.6.0/README.md +146 -0
- logfly-2.6.0/pyproject.toml +10 -0
- {logfly-2.5 → logfly-2.6.0}/setup.py +4 -3
- logfly-2.6.0/src/logfly/__init__.py +89 -0
- logfly-2.6.0/src/logfly/clock.py +120 -0
- logfly-2.6.0/src/logfly/errors.py +22 -0
- logfly-2.6.0/src/logfly/logger.py +196 -0
- logfly-2.6.0/src/logfly/options.py +61 -0
- logfly-2.6.0/src/logfly/sinks.py +71 -0
- logfly-2.6.0/src/logfly/tools.py +148 -0
- logfly-2.6.0/src/logfly.egg-info/PKG-INFO +176 -0
- {logfly-2.5 → logfly-2.6.0}/src/logfly.egg-info/SOURCES.txt +8 -1
- logfly-2.6.0/src/logfly.egg-info/requires.txt +4 -0
- logfly-2.6.0/tests/test_logfly.py +315 -0
- logfly-2.5/PKG-INFO +0 -53
- logfly-2.5/README.md +0 -38
- logfly-2.5/pyproject.toml +0 -6
- logfly-2.5/src/logfly/__init__.py +0 -305
- logfly-2.5/src/logfly.egg-info/PKG-INFO +0 -53
- logfly-2.5/src/logfly.egg-info/requires.txt +0 -1
- {logfly-2.5 → logfly-2.6.0}/LICENSE +0 -0
- {logfly-2.5 → logfly-2.6.0}/setup.cfg +0 -0
- {logfly-2.5 → logfly-2.6.0}/src/logfly.egg-info/dependency_links.txt +0 -0
- {logfly-2.5 → logfly-2.6.0}/src/logfly.egg-info/top_level.txt +0 -0
logfly-2.6.0/PKG-INFO
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: logfly
|
|
3
|
+
Version: 2.6.0
|
|
4
|
+
Summary: A simple log tool by python
|
|
5
|
+
Home-page: https://about.guki.me
|
|
6
|
+
Author: Yuan Sui
|
|
7
|
+
Author-email: orisui@icloud.com
|
|
8
|
+
Project-URL: Github, https://github.com/tinqlo/logfly
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.7
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Requires-Dist: colorama
|
|
16
|
+
Provides-Extra: dev
|
|
17
|
+
Requires-Dist: pytest; extra == "dev"
|
|
18
|
+
Dynamic: author
|
|
19
|
+
Dynamic: author-email
|
|
20
|
+
Dynamic: classifier
|
|
21
|
+
Dynamic: description
|
|
22
|
+
Dynamic: description-content-type
|
|
23
|
+
Dynamic: home-page
|
|
24
|
+
Dynamic: license-file
|
|
25
|
+
Dynamic: project-url
|
|
26
|
+
Dynamic: provides-extra
|
|
27
|
+
Dynamic: requires-dist
|
|
28
|
+
Dynamic: requires-python
|
|
29
|
+
Dynamic: summary
|
|
30
|
+
|
|
31
|
+
# logfly
|
|
32
|
+
|
|
33
|
+
一个给 Python 入门项目用的轻量日志工具:一行调用,同时写终端和文件,按天归档。
|
|
34
|
+
|
|
35
|
+
- 版本:2.6.0
|
|
36
|
+
- Python:>= 3.7
|
|
37
|
+
- 依赖:`colorama`(可选安装,装上后老式 Windows 控制台也能显示颜色)
|
|
38
|
+
|
|
39
|
+
## 安装
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install -e .
|
|
43
|
+
|
|
44
|
+
# 需要跑测试时
|
|
45
|
+
pip install -e ".[dev]"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## 快速开始
|
|
49
|
+
|
|
50
|
+
最简写法,和 2.x 完全一致:
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
import logfly
|
|
54
|
+
|
|
55
|
+
logfly.write_log('app', 'fileCLI', 'info', '程序启动')
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
同一类日志反复写时,把配置绑一次:
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
log = logfly.get_logger(folder_name='myapp') # 默认同时写终端和文件
|
|
62
|
+
|
|
63
|
+
log.info('程序启动')
|
|
64
|
+
log.warning('磁盘快满了')
|
|
65
|
+
log.error('请求失败')
|
|
66
|
+
log.success('检查全部通过')
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## 日志写在哪
|
|
70
|
+
|
|
71
|
+
`position` 决定日志出现在哪:
|
|
72
|
+
|
|
73
|
+
| 取值 | 终端 | 文件 |
|
|
74
|
+
| --- | :---: | :---: |
|
|
75
|
+
| `'CLI'` | 有 | 无 |
|
|
76
|
+
| `'file'` | 无 | 有 |
|
|
77
|
+
| `'fileCLI'` | 有 | 有 |
|
|
78
|
+
|
|
79
|
+
文件路径:
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
./logs/<folder_name>/<YYYY-MM-DD>/<name>-<YYYY-MM-DD>.log
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
`hidden='yes'` 时再存一份到用户主目录:
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
~/.1o9f1y/<folder_name>/<YYYY-MM-DD>/<name>-<YYYY-MM-DD>.log
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## write_log 参数
|
|
92
|
+
|
|
93
|
+
| 参数 | 默认值 | 说明 |
|
|
94
|
+
| --- | --- | --- |
|
|
95
|
+
| `name` | 必填 | 日志文件名,日期和 `.log` 自动拼接 |
|
|
96
|
+
| `position` | 必填 | `'CLI'` / `'file'` / `'fileCLI'` |
|
|
97
|
+
| `level` | 必填 | 自定义级别,写入时转大写并加方括号 |
|
|
98
|
+
| `message` | 必填 | 日志正文 |
|
|
99
|
+
| `mode` | `'add'` | `'add'` 按天追加;`'new'` 每次调用生成新文件(文件名带 `YYYYMMDDHHMMSS`) |
|
|
100
|
+
| `folder_name` | `'default-log'` | `logs` 下的子目录名 |
|
|
101
|
+
| `hidden` | `'no'` | `'yes'` 时在主目录再存一份副本 |
|
|
102
|
+
| `color` | `'yes'` | 终端输出是否带颜色 |
|
|
103
|
+
| `str_message` | `'yes'` | 是否先对 `message` 调用 `str()`;设为 `'no'` 时 `message` 必须是 `str` |
|
|
104
|
+
| `base_dir` | `None` | 日志根目录,默认 `./logs` |
|
|
105
|
+
|
|
106
|
+
几个补充:
|
|
107
|
+
|
|
108
|
+
- 所有 `'yes'` / `'no'` 开关也接受 `True` / `False`;`position` 和 `mode` 不区分大小写。
|
|
109
|
+
- 返回写入的日志文件路径;只写终端时返回 `None`。
|
|
110
|
+
- 参数不合法抛 `logfly.ParameterError`(`ValueError` 子类),不再静默返回 `None`。
|
|
111
|
+
|
|
112
|
+
## 日志格式
|
|
113
|
+
|
|
114
|
+
文件里每行长这样:
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
2023-08-07 18:30:05 [INFO] message
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
终端输出会多带一个文件名:
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
app 2023-08-07 18:30:05 [INFO] message
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
文件行尾用 CRLF,和 2.x 生成的日志保持一致,旧日志的解析脚本不用改。
|
|
127
|
+
|
|
128
|
+
## 其他工具函数
|
|
129
|
+
|
|
130
|
+
| 函数 | 作用 |
|
|
131
|
+
| --- | --- |
|
|
132
|
+
| `create_or_check_file('file' 或 'path', name, warning='yes')` | 文件/目录不存在就创建;原本已存在时按 `warning` 提示 |
|
|
133
|
+
| `create_log_folder(folder_name, hidden='no', base_dir=None)` | 建好当天要用的日志目录,返回路径 |
|
|
134
|
+
| `mv_file(src, dst, folder_name='mv_file')` | 移动文件并记一条日志 |
|
|
135
|
+
| `run_cmd(cmd, timeout=None, check=False, base_dir=None)` | 执行命令,逐行打印并记录,返回完整标准输出 |
|
|
136
|
+
| `get_time(flag)` | 取 `'datetime'` / `'date'` / `'times'` / `'datetimefile'` / `'timestamp'` |
|
|
137
|
+
| `timestamp_to_datetime(ts)` | 时间戳(秒级或毫秒级)转 `YYYY-MM-DD HH:MM:SS` |
|
|
138
|
+
| `datetime_to_timestamp(s)` | `YYYY-MM-DD HH:MM:SS` 或 `datetime` 对象转时间戳 |
|
|
139
|
+
| `time_transfer(ts, flag)` | 上面两个的 2.x 兼容写法 |
|
|
140
|
+
|
|
141
|
+
## 2.6 的改动
|
|
142
|
+
|
|
143
|
+
- **出错抛异常**:参数不合法抛 `ParameterError`,不再打印一行后返回 `None`。旧名 `ParameterERROR` 仍可用。
|
|
144
|
+
- **新增 `base_dir`**:日志目录可配置,测试因此不依赖当前工作目录。
|
|
145
|
+
- **`run_cmd` 返回完整输出**:原来只 `readline()` 一次就返回,多行输出会丢;解码顺序也从 GBK 优先改成 UTF-8 优先,修掉中文乱码。
|
|
146
|
+
- **`create_or_check_file`**:创建成功后不再误报 `already exists`。
|
|
147
|
+
- **`mv_file`**:移动成功记 `info`,原来错记为 `error`。
|
|
148
|
+
- **并发安全**:多线程写同一个文件不会出现半行交错。
|
|
149
|
+
- **路径校验**:`name` / `folder_name` 拒绝 `/`、`\`、`..`,日志不会写到目录外。
|
|
150
|
+
|
|
151
|
+
刻意保留的行为:`mode='new'` 每次调用覆盖同名文件;隐藏副本始终追加。
|
|
152
|
+
|
|
153
|
+
## 项目结构
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
src/logfly/
|
|
157
|
+
├── __init__.py 公开接口(只做导出)
|
|
158
|
+
├── errors.py ParameterError
|
|
159
|
+
├── options.py 'yes'/'no' 与固定取值的校验
|
|
160
|
+
├── clock.py 时间格式化与时间戳换算
|
|
161
|
+
├── sinks.py 把一行日志写到终端或文件
|
|
162
|
+
├── logger.py 路径解析 + 写入编排(核心)
|
|
163
|
+
└── tools.py 建文件/目录、移动文件、执行命令
|
|
164
|
+
tests/
|
|
165
|
+
└── test_logfly.py
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## 运行测试
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
pytest
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## 许可证
|
|
175
|
+
|
|
176
|
+
MIT
|
logfly-2.6.0/README.md
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# logfly
|
|
2
|
+
|
|
3
|
+
一个给 Python 入门项目用的轻量日志工具:一行调用,同时写终端和文件,按天归档。
|
|
4
|
+
|
|
5
|
+
- 版本:2.6.0
|
|
6
|
+
- Python:>= 3.7
|
|
7
|
+
- 依赖:`colorama`(可选安装,装上后老式 Windows 控制台也能显示颜色)
|
|
8
|
+
|
|
9
|
+
## 安装
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install -e .
|
|
13
|
+
|
|
14
|
+
# 需要跑测试时
|
|
15
|
+
pip install -e ".[dev]"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## 快速开始
|
|
19
|
+
|
|
20
|
+
最简写法,和 2.x 完全一致:
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
import logfly
|
|
24
|
+
|
|
25
|
+
logfly.write_log('app', 'fileCLI', 'info', '程序启动')
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
同一类日志反复写时,把配置绑一次:
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
log = logfly.get_logger(folder_name='myapp') # 默认同时写终端和文件
|
|
32
|
+
|
|
33
|
+
log.info('程序启动')
|
|
34
|
+
log.warning('磁盘快满了')
|
|
35
|
+
log.error('请求失败')
|
|
36
|
+
log.success('检查全部通过')
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## 日志写在哪
|
|
40
|
+
|
|
41
|
+
`position` 决定日志出现在哪:
|
|
42
|
+
|
|
43
|
+
| 取值 | 终端 | 文件 |
|
|
44
|
+
| --- | :---: | :---: |
|
|
45
|
+
| `'CLI'` | 有 | 无 |
|
|
46
|
+
| `'file'` | 无 | 有 |
|
|
47
|
+
| `'fileCLI'` | 有 | 有 |
|
|
48
|
+
|
|
49
|
+
文件路径:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
./logs/<folder_name>/<YYYY-MM-DD>/<name>-<YYYY-MM-DD>.log
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`hidden='yes'` 时再存一份到用户主目录:
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
~/.1o9f1y/<folder_name>/<YYYY-MM-DD>/<name>-<YYYY-MM-DD>.log
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## write_log 参数
|
|
62
|
+
|
|
63
|
+
| 参数 | 默认值 | 说明 |
|
|
64
|
+
| --- | --- | --- |
|
|
65
|
+
| `name` | 必填 | 日志文件名,日期和 `.log` 自动拼接 |
|
|
66
|
+
| `position` | 必填 | `'CLI'` / `'file'` / `'fileCLI'` |
|
|
67
|
+
| `level` | 必填 | 自定义级别,写入时转大写并加方括号 |
|
|
68
|
+
| `message` | 必填 | 日志正文 |
|
|
69
|
+
| `mode` | `'add'` | `'add'` 按天追加;`'new'` 每次调用生成新文件(文件名带 `YYYYMMDDHHMMSS`) |
|
|
70
|
+
| `folder_name` | `'default-log'` | `logs` 下的子目录名 |
|
|
71
|
+
| `hidden` | `'no'` | `'yes'` 时在主目录再存一份副本 |
|
|
72
|
+
| `color` | `'yes'` | 终端输出是否带颜色 |
|
|
73
|
+
| `str_message` | `'yes'` | 是否先对 `message` 调用 `str()`;设为 `'no'` 时 `message` 必须是 `str` |
|
|
74
|
+
| `base_dir` | `None` | 日志根目录,默认 `./logs` |
|
|
75
|
+
|
|
76
|
+
几个补充:
|
|
77
|
+
|
|
78
|
+
- 所有 `'yes'` / `'no'` 开关也接受 `True` / `False`;`position` 和 `mode` 不区分大小写。
|
|
79
|
+
- 返回写入的日志文件路径;只写终端时返回 `None`。
|
|
80
|
+
- 参数不合法抛 `logfly.ParameterError`(`ValueError` 子类),不再静默返回 `None`。
|
|
81
|
+
|
|
82
|
+
## 日志格式
|
|
83
|
+
|
|
84
|
+
文件里每行长这样:
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
2023-08-07 18:30:05 [INFO] message
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
终端输出会多带一个文件名:
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
app 2023-08-07 18:30:05 [INFO] message
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
文件行尾用 CRLF,和 2.x 生成的日志保持一致,旧日志的解析脚本不用改。
|
|
97
|
+
|
|
98
|
+
## 其他工具函数
|
|
99
|
+
|
|
100
|
+
| 函数 | 作用 |
|
|
101
|
+
| --- | --- |
|
|
102
|
+
| `create_or_check_file('file' 或 'path', name, warning='yes')` | 文件/目录不存在就创建;原本已存在时按 `warning` 提示 |
|
|
103
|
+
| `create_log_folder(folder_name, hidden='no', base_dir=None)` | 建好当天要用的日志目录,返回路径 |
|
|
104
|
+
| `mv_file(src, dst, folder_name='mv_file')` | 移动文件并记一条日志 |
|
|
105
|
+
| `run_cmd(cmd, timeout=None, check=False, base_dir=None)` | 执行命令,逐行打印并记录,返回完整标准输出 |
|
|
106
|
+
| `get_time(flag)` | 取 `'datetime'` / `'date'` / `'times'` / `'datetimefile'` / `'timestamp'` |
|
|
107
|
+
| `timestamp_to_datetime(ts)` | 时间戳(秒级或毫秒级)转 `YYYY-MM-DD HH:MM:SS` |
|
|
108
|
+
| `datetime_to_timestamp(s)` | `YYYY-MM-DD HH:MM:SS` 或 `datetime` 对象转时间戳 |
|
|
109
|
+
| `time_transfer(ts, flag)` | 上面两个的 2.x 兼容写法 |
|
|
110
|
+
|
|
111
|
+
## 2.6 的改动
|
|
112
|
+
|
|
113
|
+
- **出错抛异常**:参数不合法抛 `ParameterError`,不再打印一行后返回 `None`。旧名 `ParameterERROR` 仍可用。
|
|
114
|
+
- **新增 `base_dir`**:日志目录可配置,测试因此不依赖当前工作目录。
|
|
115
|
+
- **`run_cmd` 返回完整输出**:原来只 `readline()` 一次就返回,多行输出会丢;解码顺序也从 GBK 优先改成 UTF-8 优先,修掉中文乱码。
|
|
116
|
+
- **`create_or_check_file`**:创建成功后不再误报 `already exists`。
|
|
117
|
+
- **`mv_file`**:移动成功记 `info`,原来错记为 `error`。
|
|
118
|
+
- **并发安全**:多线程写同一个文件不会出现半行交错。
|
|
119
|
+
- **路径校验**:`name` / `folder_name` 拒绝 `/`、`\`、`..`,日志不会写到目录外。
|
|
120
|
+
|
|
121
|
+
刻意保留的行为:`mode='new'` 每次调用覆盖同名文件;隐藏副本始终追加。
|
|
122
|
+
|
|
123
|
+
## 项目结构
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
src/logfly/
|
|
127
|
+
├── __init__.py 公开接口(只做导出)
|
|
128
|
+
├── errors.py ParameterError
|
|
129
|
+
├── options.py 'yes'/'no' 与固定取值的校验
|
|
130
|
+
├── clock.py 时间格式化与时间戳换算
|
|
131
|
+
├── sinks.py 把一行日志写到终端或文件
|
|
132
|
+
├── logger.py 路径解析 + 写入编排(核心)
|
|
133
|
+
└── tools.py 建文件/目录、移动文件、执行命令
|
|
134
|
+
tests/
|
|
135
|
+
└── test_logfly.py
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## 运行测试
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
pytest
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## 许可证
|
|
145
|
+
|
|
146
|
+
MIT
|
|
@@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
|
|
|
5
5
|
|
|
6
6
|
setuptools.setup(
|
|
7
7
|
name="logfly",
|
|
8
|
-
version="2.
|
|
8
|
+
version="2.6.0",
|
|
9
9
|
author="Yuan Sui",
|
|
10
10
|
author_email="orisui@icloud.com",
|
|
11
11
|
description="A simple log tool by python",
|
|
@@ -22,6 +22,7 @@ setuptools.setup(
|
|
|
22
22
|
],
|
|
23
23
|
package_dir={"": "src"},
|
|
24
24
|
packages=setuptools.find_packages(where="src"),
|
|
25
|
-
python_requires=">=3.
|
|
26
|
-
install_requires=['colorama']
|
|
25
|
+
python_requires=">=3.7",
|
|
26
|
+
install_requires=['colorama'],
|
|
27
|
+
extras_require={"dev": ["pytest"]},
|
|
27
28
|
)
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#####################
|
|
2
|
+
# Author: Yuki Sui
|
|
3
|
+
# Date: 2023-8-7
|
|
4
|
+
#####################
|
|
5
|
+
"""logfly —— 给 Python 入门项目用的简易日志工具。
|
|
6
|
+
|
|
7
|
+
模块分工::
|
|
8
|
+
|
|
9
|
+
logfly.errors 异常类型
|
|
10
|
+
logfly.options 'yes'/'no' 与固定取值的校验
|
|
11
|
+
logfly.clock 时间格式化与时间戳换算
|
|
12
|
+
logfly.sinks 把一行日志写到终端或文件
|
|
13
|
+
logfly.logger 路径解析 + 写入编排(核心)
|
|
14
|
+
logfly.tools 建文件/目录、移动文件、执行命令
|
|
15
|
+
|
|
16
|
+
2.x 的调用方式全部保留::
|
|
17
|
+
|
|
18
|
+
import logfly
|
|
19
|
+
logfly.write_log('name', 'fileCLI', 'info', 'hello')
|
|
20
|
+
|
|
21
|
+
新增的写法(推荐)::
|
|
22
|
+
|
|
23
|
+
log = logfly.get_logger(folder_name='myapp')
|
|
24
|
+
log.info('程序启动')
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from .clock import (
|
|
28
|
+
format_compact,
|
|
29
|
+
format_date,
|
|
30
|
+
format_datetime,
|
|
31
|
+
format_time,
|
|
32
|
+
get_time,
|
|
33
|
+
time_transfer,
|
|
34
|
+
timestamp_to_datetime,
|
|
35
|
+
datetime_to_timestamp,
|
|
36
|
+
)
|
|
37
|
+
from .errors import ParameterERROR, ParameterError
|
|
38
|
+
from .logger import (
|
|
39
|
+
DEFAULT_FOLDER,
|
|
40
|
+
DEFAULT_LOG_DIR,
|
|
41
|
+
HIDDEN_DIR,
|
|
42
|
+
LOG_FILE_STEM,
|
|
43
|
+
Logger,
|
|
44
|
+
create_log_folder,
|
|
45
|
+
get_logger,
|
|
46
|
+
hidden_root,
|
|
47
|
+
log_root,
|
|
48
|
+
write_log,
|
|
49
|
+
)
|
|
50
|
+
from .sinks import HAS_COLORAMA
|
|
51
|
+
from .tools import create_or_check_file, error, mv_file, run_cmd
|
|
52
|
+
|
|
53
|
+
__version__ = '2.6.0'
|
|
54
|
+
#: 2.x 的旧变量名,表示 colorama 是否可用。
|
|
55
|
+
__colorama_init__ = HAS_COLORAMA
|
|
56
|
+
|
|
57
|
+
__all__ = [
|
|
58
|
+
# 主接口
|
|
59
|
+
'write_log',
|
|
60
|
+
'get_logger',
|
|
61
|
+
'Logger',
|
|
62
|
+
# 工具
|
|
63
|
+
'create_or_check_file',
|
|
64
|
+
'create_log_folder',
|
|
65
|
+
'mv_file',
|
|
66
|
+
'run_cmd',
|
|
67
|
+
'error',
|
|
68
|
+
# 时间
|
|
69
|
+
'get_time',
|
|
70
|
+
'time_transfer',
|
|
71
|
+
'format_datetime',
|
|
72
|
+
'format_date',
|
|
73
|
+
'format_time',
|
|
74
|
+
'format_compact',
|
|
75
|
+
'timestamp_to_datetime',
|
|
76
|
+
'datetime_to_timestamp',
|
|
77
|
+
# 路径
|
|
78
|
+
'log_root',
|
|
79
|
+
'hidden_root',
|
|
80
|
+
# 常量与异常
|
|
81
|
+
'DEFAULT_FOLDER',
|
|
82
|
+
'DEFAULT_LOG_DIR',
|
|
83
|
+
'HIDDEN_DIR',
|
|
84
|
+
'LOG_FILE_STEM',
|
|
85
|
+
'ParameterError',
|
|
86
|
+
'ParameterERROR',
|
|
87
|
+
'HAS_COLORAMA',
|
|
88
|
+
'__version__',
|
|
89
|
+
]
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"""时间格式化与时间戳换算。
|
|
2
|
+
|
|
3
|
+
2.x 用一条 ``flag`` 字符串在 ``get_time`` / ``time_transfer`` 里分支,
|
|
4
|
+
拼错时同样静默返回 ``None``(于是 ``'\\\\.1o9f1y\\\\' + None`` 才炸)。
|
|
5
|
+
这里改成分工明确的小函数,非法输入立刻抛异常;
|
|
6
|
+
``get_time`` / ``time_transfer`` 作为兼容包装保留下来。
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import time
|
|
10
|
+
|
|
11
|
+
from .errors import ParameterError
|
|
12
|
+
|
|
13
|
+
#: 写进日志文件的时间格式,例如 ``2023-08-07 18:30:05``。
|
|
14
|
+
DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S'
|
|
15
|
+
#: 日期目录名,例如 ``2023-08-07``。
|
|
16
|
+
DATE_FORMAT = '%Y-%m-%d'
|
|
17
|
+
#: 只到秒的时间,例如 ``18:30:05``。
|
|
18
|
+
TIME_FORMAT = '%H:%M:%S'
|
|
19
|
+
#: ``mode='new'`` 时用的紧凑时间,例如 ``20230807183005``。
|
|
20
|
+
COMPACT_FORMAT = '%Y%m%d%H%M%S'
|
|
21
|
+
|
|
22
|
+
#: 时间戳超过这个量级就当作毫秒。
|
|
23
|
+
#: 2.x 用 ``len(str(ts)) == 13`` 判断,2033 年之后 10 位秒级时间戳会变成
|
|
24
|
+
#: 11 位,那种长度判断就失效了;按数值判断不会过时。
|
|
25
|
+
_MILLISECOND_THRESHOLD = 1e11
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def format_datetime(when=None):
|
|
29
|
+
"""返回 ``YYYY-MM-DD HH:MM:SS``。``when`` 为空表示当前时间。"""
|
|
30
|
+
return time.strftime(DATETIME_FORMAT, time.localtime(when))
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def format_date(when=None):
|
|
34
|
+
"""返回 ``YYYY-MM-DD``,用于日志目录名。"""
|
|
35
|
+
return time.strftime(DATE_FORMAT, time.localtime(when))
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def format_time(when=None):
|
|
39
|
+
"""返回 ``HH:MM:SS``。"""
|
|
40
|
+
return time.strftime(TIME_FORMAT, time.localtime(when))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def format_compact(when=None):
|
|
44
|
+
"""返回 ``YYYYMMDDHHMMSS``,用于 ``mode='new'`` 的文件名。"""
|
|
45
|
+
return time.strftime(COMPACT_FORMAT, time.localtime(when))
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def timestamp():
|
|
49
|
+
"""返回当前 Unix 时间戳(浮点秒)。"""
|
|
50
|
+
return time.time()
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _to_seconds(value):
|
|
54
|
+
"""把秒级或毫秒级时间戳统一成秒。"""
|
|
55
|
+
try:
|
|
56
|
+
number = float(value)
|
|
57
|
+
except (TypeError, ValueError):
|
|
58
|
+
raise ParameterError(
|
|
59
|
+
'参数 time_stamp 必须是数字(秒级或毫秒级时间戳),收到 {0!r}'.format(value)
|
|
60
|
+
)
|
|
61
|
+
if abs(number) >= _MILLISECOND_THRESHOLD:
|
|
62
|
+
number /= 1000.0
|
|
63
|
+
return number
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def timestamp_to_datetime(value):
|
|
67
|
+
"""秒级 / 毫秒级时间戳 -> ``YYYY-MM-DD HH:MM:SS``。"""
|
|
68
|
+
return time.strftime(DATETIME_FORMAT, time.localtime(_to_seconds(value)))
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def datetime_to_timestamp(value):
|
|
72
|
+
"""``YYYY-MM-DD HH:MM:SS`` -> 秒级时间戳。
|
|
73
|
+
|
|
74
|
+
也接受 :class:`datetime.datetime` 对象,省得调用方自己转字符串。
|
|
75
|
+
"""
|
|
76
|
+
if hasattr(value, 'timetuple'): # datetime / date 对象
|
|
77
|
+
return time.mktime(value.timetuple())
|
|
78
|
+
if isinstance(value, str):
|
|
79
|
+
try:
|
|
80
|
+
return time.mktime(time.strptime(value, DATETIME_FORMAT))
|
|
81
|
+
except ValueError:
|
|
82
|
+
raise ParameterError(
|
|
83
|
+
'参数 time_stamp 必须形如 "2023-08-07 18:30:05",收到 {0!r}'.format(value)
|
|
84
|
+
)
|
|
85
|
+
raise ParameterError(
|
|
86
|
+
'参数 time_stamp 必须是 "YYYY-MM-DD HH:MM:SS" 字符串或 datetime,收到 {0!r}'.format(value)
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def get_time(flag):
|
|
91
|
+
"""2.x 兼容接口:按 ``flag`` 取不同粒度的时间。
|
|
92
|
+
|
|
93
|
+
支持 ``'datetime'`` / ``'date'`` / ``'times'`` / ``'datetimefile'`` /
|
|
94
|
+
``'timestamp'``。新代码建议直接调用上面那些具体函数。
|
|
95
|
+
"""
|
|
96
|
+
if flag == 'datetime':
|
|
97
|
+
return format_datetime()
|
|
98
|
+
if flag == 'date':
|
|
99
|
+
return format_date()
|
|
100
|
+
if flag == 'times':
|
|
101
|
+
return format_time()
|
|
102
|
+
if flag == 'datetimefile':
|
|
103
|
+
return format_compact()
|
|
104
|
+
if flag == 'timestamp':
|
|
105
|
+
return timestamp()
|
|
106
|
+
raise ParameterError(
|
|
107
|
+
'参数 flag 必须是 "datetime" / "date" / "times" / "datetimefile" / "timestamp" 之一,'
|
|
108
|
+
'收到 {0!r}'.format(flag)
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def time_transfer(time_stamp, flag='timestamp2datetime'):
|
|
113
|
+
"""2.x 兼容接口:时间戳与日期时间字符串互转。"""
|
|
114
|
+
if flag == 'timestamp2datetime':
|
|
115
|
+
return timestamp_to_datetime(time_stamp)
|
|
116
|
+
if flag == 'datetime2timestamp':
|
|
117
|
+
return datetime_to_timestamp(time_stamp)
|
|
118
|
+
raise ParameterError(
|
|
119
|
+
'参数 flag 必须是 "timestamp2datetime" 或 "datetime2timestamp",收到 {0!r}'.format(flag)
|
|
120
|
+
)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""logfly 用到的异常类型。
|
|
2
|
+
|
|
3
|
+
单独一个模块,是为了让 options / clock / logger 这些模块都能引用它,
|
|
4
|
+
又不会互相 import 成环。
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ParameterError(ValueError):
|
|
9
|
+
"""参数不合法时抛出。
|
|
10
|
+
|
|
11
|
+
继承 ``ValueError`` 有两个好处:
|
|
12
|
+
|
|
13
|
+
* 想精确处理时用 ``except ParameterError``;
|
|
14
|
+
* 想粗略兜住时 ``except ValueError`` 也能捕获,和 Python 内建习惯一致。
|
|
15
|
+
|
|
16
|
+
2.x 里参数错了只是打印一行错误然后返回 ``None``,调用方无法判断成败。
|
|
17
|
+
现在统一抛异常,让错误在调用处立刻暴露。
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
#: 2.x 的旧名字(全大写),保留一个别名,老代码 ``except logfly.ParameterERROR`` 仍然有效。
|
|
22
|
+
ParameterERROR = ParameterError
|