zjs-kit 0.1.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.
- zjs_kit-0.1.0/PKG-INFO +6 -0
- zjs_kit-0.1.0/README.md +14 -0
- zjs_kit-0.1.0/pyproject.toml +13 -0
- zjs_kit-0.1.0/setup.cfg +4 -0
- zjs_kit-0.1.0/src/zjs_kit/Logger.py +453 -0
- zjs_kit-0.1.0/src/zjs_kit/__init__.py +38 -0
- zjs_kit-0.1.0/src/zjs_kit/utils.py +47 -0
- zjs_kit-0.1.0/src/zjs_kit.egg-info/PKG-INFO +6 -0
- zjs_kit-0.1.0/src/zjs_kit.egg-info/SOURCES.txt +9 -0
- zjs_kit-0.1.0/src/zjs_kit.egg-info/dependency_links.txt +1 -0
- zjs_kit-0.1.0/src/zjs_kit.egg-info/top_level.txt +1 -0
zjs_kit-0.1.0/PKG-INFO
ADDED
zjs_kit-0.1.0/README.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "zjs-kit"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Jenson Zhang Kit"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [{ name = "Jenson Zhang", email = "zhang.jinshuo@163.com" }]
|
|
7
|
+
requires-python = ">=3.8"
|
|
8
|
+
license = { text = "MIT" }
|
|
9
|
+
keywords = ["logging", "utils", "tools"]
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Programming Language :: Python :: 3",
|
|
12
|
+
"License :: OSI Approved :: MIT License",
|
|
13
|
+
"Operating System :: OS Independent",
|
|
14
|
+
]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "zjs-kit"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Jenson Zhang Kit"
|
|
9
|
+
authors = [{ name = "Jenson Zhang" }]
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
|
|
12
|
+
[tool.setuptools.packages.find]
|
|
13
|
+
where = ["src"]
|
zjs_kit-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# ========================================
|
|
4
|
+
# @Created : 2026/8/21 16:35
|
|
5
|
+
# @File : Logger.py
|
|
6
|
+
# @Project : None
|
|
7
|
+
# @Author : Jenson Zhang
|
|
8
|
+
# @Contact : zhang.jinshuo@163.com
|
|
9
|
+
# @Software : PyCharm
|
|
10
|
+
# @Purpose :
|
|
11
|
+
# ----------------------------------------
|
|
12
|
+
# Updated : 2026/8/21 16:35 (v1.0.0)
|
|
13
|
+
# Upd. Cont.: 初始版本
|
|
14
|
+
# Introduce :
|
|
15
|
+
# ========================================
|
|
16
|
+
|
|
17
|
+
import os
|
|
18
|
+
import sys
|
|
19
|
+
import time
|
|
20
|
+
import shutil
|
|
21
|
+
import socket
|
|
22
|
+
import getpass
|
|
23
|
+
import platform
|
|
24
|
+
import threading
|
|
25
|
+
import inspect
|
|
26
|
+
from datetime import datetime, timedelta
|
|
27
|
+
from pathlib import Path
|
|
28
|
+
from typing import Optional
|
|
29
|
+
|
|
30
|
+
try:
|
|
31
|
+
import colorama
|
|
32
|
+
colorama.init()
|
|
33
|
+
HAS_COLORAMA = True
|
|
34
|
+
except ImportError:
|
|
35
|
+
HAS_COLORAMA = False
|
|
36
|
+
|
|
37
|
+
# 日志级别定义
|
|
38
|
+
class ELogLevel:
|
|
39
|
+
""" 日志级别枚举 """
|
|
40
|
+
LOG_DEBUG = 0
|
|
41
|
+
LOG_INFO = 1
|
|
42
|
+
LOG_WARN = 2
|
|
43
|
+
LOG_ERROR = 3
|
|
44
|
+
|
|
45
|
+
# 为方便使用,定义模块级常量
|
|
46
|
+
LOG_DEBUG = ELogLevel.LOG_DEBUG
|
|
47
|
+
LOG_INFO = ELogLevel.LOG_INFO
|
|
48
|
+
LOG_WARN = ELogLevel.LOG_WARN
|
|
49
|
+
LOG_ERROR = ELogLevel.LOG_ERROR
|
|
50
|
+
|
|
51
|
+
# 全局状态
|
|
52
|
+
_logger_lock = threading.RLock() # 保护全局状态的锁
|
|
53
|
+
_logger_initialized = False # 是否已初始化
|
|
54
|
+
_log_file = None # 日志文件对象
|
|
55
|
+
_logger_path = "" # 日志根目录
|
|
56
|
+
_logger_name = "" # 日志名称(子目录名)
|
|
57
|
+
_logger_keep_days = 3 # 日志保留天数
|
|
58
|
+
_en_con = True # 是否启用控制台输出
|
|
59
|
+
_file_log_level = LOG_DEBUG # 文件输出最低级别
|
|
60
|
+
_con_log_level = LOG_DEBUG # 控制台输出最低级别
|
|
61
|
+
_current_log_date = "" # 当前日志文件对应的日期,用于跨天切换
|
|
62
|
+
|
|
63
|
+
# 内部工具函数
|
|
64
|
+
def _get_date_str() -> str:
|
|
65
|
+
"""
|
|
66
|
+
返回当前日期字符串
|
|
67
|
+
"""
|
|
68
|
+
return datetime.now().strftime("%Y%m%d")
|
|
69
|
+
|
|
70
|
+
def _get_time_str() -> str:
|
|
71
|
+
"""
|
|
72
|
+
返回当前时间字符串
|
|
73
|
+
"""
|
|
74
|
+
return datetime.now().strftime("%H%M_%S")
|
|
75
|
+
|
|
76
|
+
def _get_timestamp_str() -> str:
|
|
77
|
+
"""
|
|
78
|
+
返回完整时间戳字符串
|
|
79
|
+
"""
|
|
80
|
+
now = datetime.now()
|
|
81
|
+
return f"[{now.year:04d}-{now.month:02d}-{now.day:02d}] ({now.hour:02d}:{now.minute:02d}:{now.second:02d})"
|
|
82
|
+
|
|
83
|
+
def _get_level_text(level: int) -> str:
|
|
84
|
+
"""
|
|
85
|
+
返回日志级别文本
|
|
86
|
+
"""
|
|
87
|
+
if level == LOG_DEBUG:
|
|
88
|
+
return "[DEBUG]"
|
|
89
|
+
elif level == LOG_INFO:
|
|
90
|
+
return "[INFO ]"
|
|
91
|
+
elif level == LOG_WARN:
|
|
92
|
+
return "[WARN ]"
|
|
93
|
+
elif level == LOG_ERROR:
|
|
94
|
+
return "[ERROR]"
|
|
95
|
+
else:
|
|
96
|
+
return "[UNK ]"
|
|
97
|
+
|
|
98
|
+
def _get_level_color(level: int) -> str:
|
|
99
|
+
"""
|
|
100
|
+
返回控制台颜色代码
|
|
101
|
+
"""
|
|
102
|
+
if not HAS_COLORAMA:
|
|
103
|
+
return ""
|
|
104
|
+
# 使用 colorama 颜色常量
|
|
105
|
+
if level == LOG_DEBUG:
|
|
106
|
+
return colorama.Style.DIM # 灰色
|
|
107
|
+
elif level == LOG_INFO:
|
|
108
|
+
return colorama.Fore.GREEN # 绿色
|
|
109
|
+
elif level == LOG_WARN:
|
|
110
|
+
return colorama.Fore.YELLOW # 黄色
|
|
111
|
+
elif level == LOG_ERROR:
|
|
112
|
+
return colorama.Fore.RED # 红色
|
|
113
|
+
else:
|
|
114
|
+
return colorama.Fore.RESET
|
|
115
|
+
|
|
116
|
+
def _reset_color() -> str:
|
|
117
|
+
""" 恢复颜色 """
|
|
118
|
+
if HAS_COLORAMA:
|
|
119
|
+
return colorama.Style.RESET_ALL
|
|
120
|
+
return ""
|
|
121
|
+
|
|
122
|
+
def _get_mac_address() -> str:
|
|
123
|
+
"""
|
|
124
|
+
获取 MAC 地址
|
|
125
|
+
"""
|
|
126
|
+
try:
|
|
127
|
+
import uuid
|
|
128
|
+
mac = uuid.getnode()
|
|
129
|
+
if mac == 0:
|
|
130
|
+
return "None"
|
|
131
|
+
# 转换为 6 字节
|
|
132
|
+
mac_hex = f"{mac:012x}"
|
|
133
|
+
return "-".join(mac_hex[i:i+2].upper() for i in range(0, 12, 2))
|
|
134
|
+
except Exception:
|
|
135
|
+
return "None"
|
|
136
|
+
|
|
137
|
+
def _get_computer_name() -> str:
|
|
138
|
+
"""
|
|
139
|
+
获取计算机名
|
|
140
|
+
"""
|
|
141
|
+
return socket.gethostname()
|
|
142
|
+
|
|
143
|
+
def _get_user_name() -> str:
|
|
144
|
+
"""
|
|
145
|
+
获取当前用户名
|
|
146
|
+
"""
|
|
147
|
+
try:
|
|
148
|
+
return getpass.getuser()
|
|
149
|
+
except Exception:
|
|
150
|
+
return "Unknown"
|
|
151
|
+
|
|
152
|
+
def _get_program_name() -> str:
|
|
153
|
+
"""
|
|
154
|
+
获取当前程序名称
|
|
155
|
+
"""
|
|
156
|
+
# 尝试获取主脚本路径
|
|
157
|
+
try:
|
|
158
|
+
main_script = sys.argv[0]
|
|
159
|
+
if main_script:
|
|
160
|
+
return os.path.basename(main_script)
|
|
161
|
+
except Exception:
|
|
162
|
+
pass
|
|
163
|
+
return "Python"
|
|
164
|
+
|
|
165
|
+
def _create_multi_dir(path: str) -> None:
|
|
166
|
+
"""
|
|
167
|
+
递归创建多级目录
|
|
168
|
+
"""
|
|
169
|
+
if path:
|
|
170
|
+
os.makedirs(path, exist_ok=True)
|
|
171
|
+
|
|
172
|
+
def _delete_folder(folder_path: str) -> None:
|
|
173
|
+
"""
|
|
174
|
+
删除整个文件夹
|
|
175
|
+
"""
|
|
176
|
+
if os.path.exists(folder_path):
|
|
177
|
+
shutil.rmtree(folder_path, ignore_errors=True)
|
|
178
|
+
|
|
179
|
+
def _clean_old_logs() -> None:
|
|
180
|
+
"""
|
|
181
|
+
清理过期日志文件夹
|
|
182
|
+
"""
|
|
183
|
+
if not _logger_path or not _logger_name:
|
|
184
|
+
return
|
|
185
|
+
|
|
186
|
+
logger_base_dir = os.path.join(_logger_path, _logger_name)
|
|
187
|
+
if not os.path.isdir(logger_base_dir):
|
|
188
|
+
return
|
|
189
|
+
|
|
190
|
+
today = datetime.now().date()
|
|
191
|
+
for item in os.listdir(logger_base_dir):
|
|
192
|
+
item_path = os.path.join(logger_base_dir, item)
|
|
193
|
+
if os.path.isdir(item_path):
|
|
194
|
+
try:
|
|
195
|
+
# 尝试解析目录名为日期 YYYYMMDD
|
|
196
|
+
folder_date = datetime.strptime(item, "%Y%m%d").date()
|
|
197
|
+
diff_days = (today - folder_date).days
|
|
198
|
+
if diff_days > _logger_keep_days:
|
|
199
|
+
_delete_folder(item_path)
|
|
200
|
+
except ValueError:
|
|
201
|
+
# 目录名不是日期格式,忽略
|
|
202
|
+
continue
|
|
203
|
+
|
|
204
|
+
def _write_header_info() -> None:
|
|
205
|
+
"""
|
|
206
|
+
写入日志头信息到文件和控制台
|
|
207
|
+
"""
|
|
208
|
+
global _log_file, _en_con
|
|
209
|
+
|
|
210
|
+
if _log_file is None:
|
|
211
|
+
return
|
|
212
|
+
|
|
213
|
+
# 如果文件已有内容,则跳过头部
|
|
214
|
+
_log_file.seek(0, os.SEEK_END)
|
|
215
|
+
if _log_file.tell() > 0:
|
|
216
|
+
_log_file.seek(0, os.SEEK_END)
|
|
217
|
+
return
|
|
218
|
+
|
|
219
|
+
now = datetime.now()
|
|
220
|
+
mac = _get_mac_address()
|
|
221
|
+
comp_name = _get_computer_name()
|
|
222
|
+
user_name = _get_user_name()
|
|
223
|
+
prog_name = _get_program_name()
|
|
224
|
+
|
|
225
|
+
header1 = f"=== MAC: {mac} || PC Name: {comp_name} || User Name: {user_name} ==="
|
|
226
|
+
header2 = f"=== Init Time: [{now.year:04d}-{now.month:02d}-{now.day:02d}]({now.hour:02d}:{now.minute:02d}:{now.second:02d}) || EXE Name: {prog_name} ==="
|
|
227
|
+
|
|
228
|
+
# 写入文件
|
|
229
|
+
_log_file.write(header1 + "\n")
|
|
230
|
+
_log_file.write(header2 + "\n")
|
|
231
|
+
_log_file.flush()
|
|
232
|
+
|
|
233
|
+
# 输出到控制台
|
|
234
|
+
if _en_con:
|
|
235
|
+
if HAS_COLORAMA:
|
|
236
|
+
print(colorama.Fore.BLUE + header1 + _reset_color())
|
|
237
|
+
print(colorama.Fore.BLUE + header2 + _reset_color())
|
|
238
|
+
else:
|
|
239
|
+
print(header1)
|
|
240
|
+
print(header2)
|
|
241
|
+
|
|
242
|
+
def _open_new_log_file() -> None:
|
|
243
|
+
"""
|
|
244
|
+
根据当前日期和时间打开新的日志文件
|
|
245
|
+
"""
|
|
246
|
+
global _log_file, _current_log_date
|
|
247
|
+
|
|
248
|
+
date_str = _get_date_str()
|
|
249
|
+
time_str = _get_time_str()
|
|
250
|
+
|
|
251
|
+
# 构建日志目录
|
|
252
|
+
log_dir = os.path.join(_logger_path, _logger_name, date_str)
|
|
253
|
+
_create_multi_dir(log_dir)
|
|
254
|
+
|
|
255
|
+
# 日志文件完整路径
|
|
256
|
+
log_file_path = os.path.join(log_dir, f"{time_str}.log")
|
|
257
|
+
|
|
258
|
+
# 打开文件
|
|
259
|
+
try:
|
|
260
|
+
_log_file = open(log_file_path, "a+", encoding="utf-8")
|
|
261
|
+
_current_log_date = date_str
|
|
262
|
+
except Exception as e:
|
|
263
|
+
_log_file = None
|
|
264
|
+
error_msg = f"[Logger] Failed to open log file: {log_file_path}, error: {e}"
|
|
265
|
+
if _en_con:
|
|
266
|
+
if HAS_COLORAMA:
|
|
267
|
+
print(colorama.Fore.RED + error_msg + _reset_color())
|
|
268
|
+
else:
|
|
269
|
+
print(error_msg)
|
|
270
|
+
else:
|
|
271
|
+
# 输出到调试器(这里使用 stderr 代替)
|
|
272
|
+
sys.stderr.write(error_msg + "\n")
|
|
273
|
+
return
|
|
274
|
+
|
|
275
|
+
# 写入日志头
|
|
276
|
+
_write_header_info()
|
|
277
|
+
|
|
278
|
+
def _maybe_rotate_log_file() -> None:
|
|
279
|
+
"""
|
|
280
|
+
如果日期变化,则切换新日志文件
|
|
281
|
+
"""
|
|
282
|
+
global _log_file, _current_log_date
|
|
283
|
+
today = _get_date_str()
|
|
284
|
+
if today != _current_log_date:
|
|
285
|
+
# 关闭旧文件,打开新文件
|
|
286
|
+
if _log_file:
|
|
287
|
+
_log_file.close()
|
|
288
|
+
_log_file = None
|
|
289
|
+
_open_new_log_file()
|
|
290
|
+
# 顺便清理旧日志
|
|
291
|
+
_clean_old_logs()
|
|
292
|
+
|
|
293
|
+
# 公共接口
|
|
294
|
+
def Logger_Init(
|
|
295
|
+
logger_path: str = ".",
|
|
296
|
+
logger_name: str = "zjs_kit",
|
|
297
|
+
logger_keep_days: int = 3,
|
|
298
|
+
en_con: bool = True,
|
|
299
|
+
file_log_level: int = LOG_DEBUG,
|
|
300
|
+
con_log_level: int = LOG_DEBUG
|
|
301
|
+
) -> None:
|
|
302
|
+
"""
|
|
303
|
+
初始化日志系统
|
|
304
|
+
"""
|
|
305
|
+
global _logger_initialized, _logger_path, _logger_name, _logger_keep_days
|
|
306
|
+
global _en_con, _file_log_level, _con_log_level, _log_file, _current_log_date
|
|
307
|
+
|
|
308
|
+
with _logger_lock:
|
|
309
|
+
if _logger_initialized:
|
|
310
|
+
return # 防止重复初始化
|
|
311
|
+
|
|
312
|
+
# 处理日志根目录
|
|
313
|
+
if not logger_path or logger_path == ".":
|
|
314
|
+
# 使用当前脚本所在目录
|
|
315
|
+
try:
|
|
316
|
+
script_path = os.path.dirname(os.path.abspath(sys.argv[0]))
|
|
317
|
+
logger_path = script_path
|
|
318
|
+
except Exception:
|
|
319
|
+
logger_path = os.getcwd()
|
|
320
|
+
|
|
321
|
+
_logger_path = logger_path
|
|
322
|
+
_logger_name = logger_name
|
|
323
|
+
_logger_keep_days = logger_keep_days
|
|
324
|
+
_en_con = en_con
|
|
325
|
+
_file_log_level = file_log_level
|
|
326
|
+
_con_log_level = con_log_level
|
|
327
|
+
|
|
328
|
+
# 打开日志文件
|
|
329
|
+
_open_new_log_file()
|
|
330
|
+
|
|
331
|
+
# 清理旧日志
|
|
332
|
+
_clean_old_logs()
|
|
333
|
+
|
|
334
|
+
_logger_initialized = True
|
|
335
|
+
|
|
336
|
+
def Logger_Uninit() -> None:
|
|
337
|
+
"""
|
|
338
|
+
关闭日志系统
|
|
339
|
+
"""
|
|
340
|
+
global _logger_initialized, _log_file
|
|
341
|
+
|
|
342
|
+
with _logger_lock:
|
|
343
|
+
if not _logger_initialized:
|
|
344
|
+
return
|
|
345
|
+
|
|
346
|
+
if _log_file:
|
|
347
|
+
_log_file.close()
|
|
348
|
+
_log_file = None
|
|
349
|
+
|
|
350
|
+
_logger_initialized = False
|
|
351
|
+
|
|
352
|
+
def Logger_Write(
|
|
353
|
+
log_level: int,
|
|
354
|
+
class_name: Optional[str],
|
|
355
|
+
func_name: Optional[str],
|
|
356
|
+
fmt: str,
|
|
357
|
+
*args
|
|
358
|
+
) -> None:
|
|
359
|
+
"""
|
|
360
|
+
写日志
|
|
361
|
+
"""
|
|
362
|
+
global _logger_initialized, _file_log_level, _con_log_level, _log_file, _en_con
|
|
363
|
+
|
|
364
|
+
if not _logger_initialized:
|
|
365
|
+
return
|
|
366
|
+
|
|
367
|
+
# 如果文件和控制台都不需要输出,直接返回
|
|
368
|
+
if log_level < _file_log_level and log_level < _con_log_level:
|
|
369
|
+
return
|
|
370
|
+
|
|
371
|
+
with _logger_lock:
|
|
372
|
+
# 跨天自动切换日志文件
|
|
373
|
+
_maybe_rotate_log_file()
|
|
374
|
+
|
|
375
|
+
timestamp = _get_timestamp_str()
|
|
376
|
+
level_text = _get_level_text(log_level)
|
|
377
|
+
|
|
378
|
+
# 构建上下文:类名.函数名
|
|
379
|
+
context = ""
|
|
380
|
+
if class_name and func_name:
|
|
381
|
+
context = f"{class_name}.{func_name}"
|
|
382
|
+
elif class_name:
|
|
383
|
+
context = class_name
|
|
384
|
+
elif func_name:
|
|
385
|
+
context = func_name
|
|
386
|
+
|
|
387
|
+
# 格式化用户消息
|
|
388
|
+
try:
|
|
389
|
+
if args:
|
|
390
|
+
user_msg = fmt % args
|
|
391
|
+
else:
|
|
392
|
+
user_msg = fmt
|
|
393
|
+
except Exception:
|
|
394
|
+
user_msg = fmt # 格式化失败就保留原始字符串
|
|
395
|
+
|
|
396
|
+
# 组装完整日志行
|
|
397
|
+
if context:
|
|
398
|
+
full_line = f"{timestamp} {level_text} - {context} - {user_msg}"
|
|
399
|
+
else:
|
|
400
|
+
full_line = f"{timestamp} {level_text} - {user_msg}"
|
|
401
|
+
|
|
402
|
+
# 输出到文件
|
|
403
|
+
if _log_file and log_level >= _file_log_level:
|
|
404
|
+
_log_file.write(full_line + "\n")
|
|
405
|
+
_log_file.flush()
|
|
406
|
+
|
|
407
|
+
# 输出到控制台(带颜色)
|
|
408
|
+
if _en_con and log_level >= _con_log_level:
|
|
409
|
+
if HAS_COLORAMA:
|
|
410
|
+
color = _get_level_color(log_level)
|
|
411
|
+
reset = _reset_color()
|
|
412
|
+
print(color + full_line + reset)
|
|
413
|
+
else:
|
|
414
|
+
print(full_line)
|
|
415
|
+
|
|
416
|
+
def Get_Exe_Path() -> str:
|
|
417
|
+
"""
|
|
418
|
+
获取当前程序
|
|
419
|
+
"""
|
|
420
|
+
try:
|
|
421
|
+
return os.path.abspath(sys.argv[0])
|
|
422
|
+
except Exception:
|
|
423
|
+
return ""
|
|
424
|
+
|
|
425
|
+
# 便捷日志函数
|
|
426
|
+
def log_debug(class_name: Optional[str], func_name: Optional[str], fmt: str, *args):
|
|
427
|
+
"""Debug 级别日志"""
|
|
428
|
+
Logger_Write(LOG_DEBUG, class_name, func_name, fmt, *args)
|
|
429
|
+
|
|
430
|
+
def log_info(class_name: Optional[str], func_name: Optional[str], fmt: str, *args):
|
|
431
|
+
"""Info 级别日志"""
|
|
432
|
+
Logger_Write(LOG_INFO, class_name, func_name, fmt, *args)
|
|
433
|
+
|
|
434
|
+
def log_warn(class_name: Optional[str], func_name: Optional[str], fmt: str, *args):
|
|
435
|
+
"""Warn 级别日志"""
|
|
436
|
+
Logger_Write(LOG_WARN, class_name, func_name, fmt, *args)
|
|
437
|
+
|
|
438
|
+
def log_error(class_name: Optional[str], func_name: Optional[str], fmt: str, *args):
|
|
439
|
+
"""Error 级别日志"""
|
|
440
|
+
Logger_Write(LOG_ERROR, class_name, func_name, fmt, *args)
|
|
441
|
+
|
|
442
|
+
# 自动获取函数名的装饰器/辅助函数
|
|
443
|
+
def auto_log(level: int, fmt: str, *args):
|
|
444
|
+
"""
|
|
445
|
+
自动获取调用者的函数名
|
|
446
|
+
"""
|
|
447
|
+
frame = inspect.currentframe().f_back
|
|
448
|
+
func_name = frame.f_code.co_name
|
|
449
|
+
class_name = None
|
|
450
|
+
# 尝试从 self 参数获取类名(仅当在方法中调用时有效)
|
|
451
|
+
if 'self' in frame.f_locals:
|
|
452
|
+
class_name = frame.f_locals['self'].__class__.__name__
|
|
453
|
+
Logger_Write(level, class_name, func_name, fmt, *args)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# ========================================
|
|
4
|
+
# @Created : 2026/8/21 16:24
|
|
5
|
+
# @File : __init__.py
|
|
6
|
+
# @Project : None
|
|
7
|
+
# @Author : Jenson Zhang
|
|
8
|
+
# @Contact : zhang.jinshuo@163.com
|
|
9
|
+
# @Software : PyCharm
|
|
10
|
+
# @Purpose :
|
|
11
|
+
# ----------------------------------------
|
|
12
|
+
# Updated : 2026/8/21 16:24 (v1.0.0)
|
|
13
|
+
# Upd. Cont.: 初始版本
|
|
14
|
+
# Introduce :
|
|
15
|
+
# ========================================
|
|
16
|
+
from .Logger import (
|
|
17
|
+
Logger_Init,
|
|
18
|
+
Logger_Uninit,
|
|
19
|
+
Logger_Write,
|
|
20
|
+
Get_Exe_Path,
|
|
21
|
+
log_debug,
|
|
22
|
+
log_info,
|
|
23
|
+
log_warn,
|
|
24
|
+
log_error,
|
|
25
|
+
auto_log,
|
|
26
|
+
LOG_DEBUG,
|
|
27
|
+
LOG_INFO,
|
|
28
|
+
LOG_WARN,
|
|
29
|
+
LOG_ERROR,
|
|
30
|
+
)
|
|
31
|
+
from .utils import read_json, write_json, timestamp, timestamp_ms
|
|
32
|
+
|
|
33
|
+
__all__ = [
|
|
34
|
+
"Logger_Init", "Logger_Uninit", "Logger_Write", "Get_Exe_Path",
|
|
35
|
+
"log_debug", "log_info", "log_warn", "log_error", "auto_log",
|
|
36
|
+
"LOG_DEBUG", "LOG_INFO", "LOG_WARN", "LOG_ERROR",
|
|
37
|
+
"read_json", "write_json", "timestamp", "timestamp_ms",
|
|
38
|
+
]
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# ========================================
|
|
4
|
+
# @Created : 2026/8/21 16:37
|
|
5
|
+
# @File : utils.py
|
|
6
|
+
# @Project : None
|
|
7
|
+
# @Author : Jenson Zhang
|
|
8
|
+
# @Contact : zhang.jinshuo@163.com
|
|
9
|
+
# @Software : PyCharm
|
|
10
|
+
# @Purpose :
|
|
11
|
+
# ----------------------------------------
|
|
12
|
+
# Updated : 2026/8/21 16:37 (v1.0.0)
|
|
13
|
+
# Upd. Cont.: 初始版本
|
|
14
|
+
# Introduce :
|
|
15
|
+
# ========================================
|
|
16
|
+
import json
|
|
17
|
+
import time
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import Any
|
|
20
|
+
|
|
21
|
+
def read_json(file_path: str) -> Any:
|
|
22
|
+
"""
|
|
23
|
+
读取 JSON 文件并返回解析结果
|
|
24
|
+
"""
|
|
25
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
|
26
|
+
return json.load(f)
|
|
27
|
+
|
|
28
|
+
def write_json(file_path: str, data: Any, indent: int = 2, ensure_ascii: bool = False) -> None:
|
|
29
|
+
"""
|
|
30
|
+
将数据写入 JSON 文件
|
|
31
|
+
"""
|
|
32
|
+
Path(file_path).parent.mkdir(parents=True, exist_ok=True)
|
|
33
|
+
with open(file_path, "w", encoding="utf-8") as f:
|
|
34
|
+
json.dump(data, f, ensure_ascii=ensure_ascii, indent=indent)
|
|
35
|
+
|
|
36
|
+
def timestamp() -> int:
|
|
37
|
+
"""
|
|
38
|
+
返回当前 Unix 时间戳 [s]
|
|
39
|
+
"""
|
|
40
|
+
return int(time.time())
|
|
41
|
+
|
|
42
|
+
def timestamp_ms() -> int:
|
|
43
|
+
"""
|
|
44
|
+
返回当前 Unix 时间戳 [ms]
|
|
45
|
+
"""
|
|
46
|
+
return int(time.time() * 1000)
|
|
47
|
+
return int(time.time() * 1000)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
zjs_kit
|