unitlog 0.0.2__py3-none-any.whl → 0.0.4__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.
- unitlog/__init__.py +1 -1
- unitlog/unit.py +105 -3
- {unitlog-0.0.2.dist-info → unitlog-0.0.4.dist-info}/METADATA +10 -2
- unitlog-0.0.4.dist-info/RECORD +9 -0
- {unitlog-0.0.2.dist-info → unitlog-0.0.4.dist-info}/WHEEL +1 -1
- unitlog-0.0.2.dist-info/RECORD +0 -9
- {unitlog-0.0.2.dist-info → unitlog-0.0.4.dist-info/licenses}/LICENSE +0 -0
- {unitlog-0.0.2.dist-info → unitlog-0.0.4.dist-info}/top_level.txt +0 -0
unitlog/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.0.
|
|
1
|
+
__version__ = "0.0.4"
|
unitlog/unit.py
CHANGED
|
@@ -35,7 +35,7 @@ class UnitLog(object):
|
|
|
35
35
|
self.started: Event = mp.Event()
|
|
36
36
|
self.stopped: Event = mp.Event()
|
|
37
37
|
self.log_num = mp.Value('i', 0)
|
|
38
|
-
self.worker = mp.Process(target=self.listening_log_msg, daemon=
|
|
38
|
+
self.worker = mp.Process(target=self.listening_log_msg, daemon=True)
|
|
39
39
|
self._proxy_handler_map = {}
|
|
40
40
|
|
|
41
41
|
def _init_proxy_handler(self, log_box: LogBox) -> PoxyConsoleLogWriter:
|
|
@@ -66,6 +66,8 @@ class UnitLog(object):
|
|
|
66
66
|
if self.stopped.is_set():
|
|
67
67
|
break
|
|
68
68
|
continue
|
|
69
|
+
except KeyboardInterrupt:
|
|
70
|
+
continue
|
|
69
71
|
try:
|
|
70
72
|
handler = self._init_proxy_handler(log_box)
|
|
71
73
|
|
|
@@ -81,7 +83,8 @@ class UnitLog(object):
|
|
|
81
83
|
def register_logger(self, name, level=logging.INFO,
|
|
82
84
|
console_log=True, file_log=False, file_log_mode="a",
|
|
83
85
|
log_filepath=None,
|
|
84
|
-
parent_logger_name=None
|
|
86
|
+
parent_logger_name=None,
|
|
87
|
+
force_all_console_log_to_file=False) -> logging.Logger:
|
|
85
88
|
if not self.started.is_set():
|
|
86
89
|
self.worker.start()
|
|
87
90
|
if not self.started.wait(timeout=3):
|
|
@@ -116,12 +119,111 @@ class UnitLog(object):
|
|
|
116
119
|
logger.handlers.append(file_handler)
|
|
117
120
|
logger.info("\nLog_filename: {}".format(log_filepath))
|
|
118
121
|
|
|
122
|
+
if force_all_console_log_to_file: # 强制控制所有标准输出到 文件
|
|
123
|
+
self.force_all_console_log_to_file(log_filepath)
|
|
124
|
+
|
|
119
125
|
return logger
|
|
120
126
|
|
|
121
127
|
|
|
128
|
+
@classmethod
|
|
129
|
+
def force_all_console_log_to_file(cls, log_filepath):
|
|
130
|
+
# ==========================================
|
|
131
|
+
# 新增函数:重定向底层 C/C++ 输出
|
|
132
|
+
# ==========================================
|
|
133
|
+
def _redirect_c_libraries_output(log_path):
|
|
134
|
+
"""
|
|
135
|
+
使用 os.dup2 强制将底层 C/C++ 的 stdout/stderr 重定向到日志文件。
|
|
136
|
+
解决 sherpa-onnx, PyQt, OpenCV 等 C 库打印无法被 Python 捕获的问题。
|
|
137
|
+
"""
|
|
138
|
+
# 1. 打开日志文件 (使用 append 模式)
|
|
139
|
+
# 这里的 buffer 设置为 0 (unbuffered) 或者 line buffered,确保 C 代码崩溃前能写入
|
|
140
|
+
try:
|
|
141
|
+
# 打开文件获取文件描述符
|
|
142
|
+
# distinct file object specifically for low-level redirection
|
|
143
|
+
log_file = open(log_path, 'a+')
|
|
144
|
+
log_fd = log_file.fileno()
|
|
145
|
+
|
|
146
|
+
# 2. 刷新 Python 的缓冲区,防止重定向导致之前的日志丢失
|
|
147
|
+
sys.stdout.flush()
|
|
148
|
+
sys.stderr.flush()
|
|
149
|
+
|
|
150
|
+
# 3. 核心:重定向 FD 1 (stdout) 和 FD 2 (stderr)
|
|
151
|
+
# 这一步之后,所有的 C printf/std::cout 都会直接写进文件
|
|
152
|
+
os.dup2(log_fd, 1)
|
|
153
|
+
os.dup2(log_fd, 2)
|
|
154
|
+
|
|
155
|
+
# 保持 log_file 对象引用,防止被垃圾回收导致 FD 关闭
|
|
156
|
+
return log_file
|
|
157
|
+
except Exception as e:
|
|
158
|
+
print(f"Failed to redirect C logs: {e}")
|
|
159
|
+
return None
|
|
160
|
+
|
|
161
|
+
class Logger(object):
|
|
162
|
+
def __init__(self, filename):
|
|
163
|
+
self.terminal = sys.stdout # 记录原来的控制台,防止 IDE 里看不到了
|
|
164
|
+
self.log = open(filename, "a", encoding="utf-8") # 'a' 追加模式
|
|
165
|
+
|
|
166
|
+
def write(self, message):
|
|
167
|
+
# 1. 尝试写回控制台(方便开发调试)
|
|
168
|
+
try:
|
|
169
|
+
if self.terminal:
|
|
170
|
+
self.terminal.write(message)
|
|
171
|
+
except:
|
|
172
|
+
pass # 打包成 no console 后这里可能会报错,直接忽略
|
|
173
|
+
|
|
174
|
+
# 2. 写入文件
|
|
175
|
+
try:
|
|
176
|
+
self.log.write(message)
|
|
177
|
+
# 【关键】立即刷新缓冲区,否则崩溃瞬间可能来不及写入文件
|
|
178
|
+
self.log.flush()
|
|
179
|
+
except:
|
|
180
|
+
pass
|
|
181
|
+
|
|
182
|
+
def flush(self):
|
|
183
|
+
# 兼容性函数,必须保留
|
|
184
|
+
try:
|
|
185
|
+
if self.terminal:
|
|
186
|
+
self.terminal.flush()
|
|
187
|
+
self.log.flush()
|
|
188
|
+
except:
|
|
189
|
+
pass
|
|
190
|
+
|
|
191
|
+
# 3. 【关键改动】区分环境进行重定向
|
|
192
|
+
# 判断是否是打包后的环境
|
|
193
|
+
# 逻辑:如果是 PyInstaller 打包 (frozen) 或者 环境变量 MIT_LOG=1,都视为需要重定向
|
|
194
|
+
FORCE_ALL_CONSOLE_LOG_TO_FILE = os.environ.get("FORCE_ALL_CONSOLE_LOG_TO_FILE") == "1"
|
|
195
|
+
IS_FROZEN = getattr(sys, 'frozen', False) or FORCE_ALL_CONSOLE_LOG_TO_FILE
|
|
196
|
+
print(f"FORCE_ALL_CONSOLE_LOG_TO_FILE: {FORCE_ALL_CONSOLE_LOG_TO_FILE} \t IS_FROZEN: {IS_FROZEN}")
|
|
197
|
+
|
|
198
|
+
if IS_FROZEN:
|
|
199
|
+
# --- 打包环境 (Exe) ---
|
|
200
|
+
# 1. 接管 Python 层面 (你原来的做法)
|
|
201
|
+
sys.stdout = Logger(log_filepath)
|
|
202
|
+
sys.stderr = sys.stdout
|
|
203
|
+
|
|
204
|
+
# 2. 接管 C/C++ 层面 (新增的做法)
|
|
205
|
+
# 这会让 sherpa-onnx 的报错也进文件
|
|
206
|
+
# 注意:在 Linux/Mac 上非常有效,Windows 上通常也有效
|
|
207
|
+
_c_log_ref = _redirect_c_libraries_output(log_filepath)
|
|
208
|
+
|
|
209
|
+
print(f"Native C++ stdout/stderr redirected to {log_filepath}")
|
|
210
|
+
|
|
211
|
+
else:
|
|
212
|
+
# --- 开发环境 (IDE) ---
|
|
213
|
+
# 在开发时,我们通常不希望 C++ 输出消失在控制台
|
|
214
|
+
# 所以这里我们 *只* 使用你原来的 Logger 记录 Python print
|
|
215
|
+
# 这样 IDE 控制台里既能看到 Python print,也能看到 C++ print (IDE 会自己捕获 FD)
|
|
216
|
+
# 同时 Python print 也会被写入文件
|
|
217
|
+
|
|
218
|
+
# 如果你确实希望开发时文件里也有 sherpa-onnx 的日志,
|
|
219
|
+
# 你可以把上面的 redirect_c_libraries_output 打开,
|
|
220
|
+
# 但代价是你的 PyCharm 控制台里那行红色的警告会消失。
|
|
221
|
+
sys.stdout = Logger(log_filepath)
|
|
222
|
+
sys.stderr = sys.stdout
|
|
223
|
+
|
|
122
224
|
DEFAULT_LOG = UnitLog()
|
|
123
225
|
|
|
124
|
-
register_logger = DEFAULT_LOG.register_logger
|
|
226
|
+
register_logger: UnitLog.register_logger = DEFAULT_LOG.register_logger
|
|
125
227
|
atexit.register(lambda: DEFAULT_LOG.stopped.set())
|
|
126
228
|
|
|
127
229
|
if __name__ == "__main__":
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: unitlog
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4
|
|
4
4
|
Home-page: https://github.com/yujun2647/unitlog
|
|
5
5
|
Download-URL:
|
|
6
6
|
Author: walkerjun
|
|
@@ -9,6 +9,14 @@ License: Apache-2.0
|
|
|
9
9
|
Requires-Python: >=3.6
|
|
10
10
|
Description-Content-Type: text/markdown
|
|
11
11
|
License-File: LICENSE
|
|
12
|
+
Dynamic: author
|
|
13
|
+
Dynamic: author-email
|
|
14
|
+
Dynamic: description
|
|
15
|
+
Dynamic: description-content-type
|
|
16
|
+
Dynamic: home-page
|
|
17
|
+
Dynamic: license
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
Dynamic: requires-python
|
|
12
20
|
|
|
13
21
|
# unitlog
|
|
14
22
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
unitlog/__init__.py,sha256=1mptEzQihbdyqqzMgdns_j5ZGK9gz7hR2bsgA_TnjO4,22
|
|
2
|
+
unitlog/handlers.py,sha256=K0ph6OxZey8AA7ZuxEycqEkEgZnckghsmN0NKxNg_bI,1768
|
|
3
|
+
unitlog/unit.py,sha256=KPOvRePRIEDgmzj6LRb3uGdpMGYrm-7V0_w59AR9Ejk,9469
|
|
4
|
+
unitlog/util_log.py,sha256=dbdImt7acamMl1u2HaHgj1Lf0-EF9KnqcLOGr9yPDi8,5202
|
|
5
|
+
unitlog-0.0.4.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
6
|
+
unitlog-0.0.4.dist-info/METADATA,sha256=Mz8CTKIU5zRsij6QjByYLSX20VmQcl16P6zj2KIvsZo,750
|
|
7
|
+
unitlog-0.0.4.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
|
|
8
|
+
unitlog-0.0.4.dist-info/top_level.txt,sha256=u_R9qvDeq23Wg6BGAP1QB7CuDosByWfI-EfXWa2MO-c,8
|
|
9
|
+
unitlog-0.0.4.dist-info/RECORD,,
|
unitlog-0.0.2.dist-info/RECORD
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
unitlog/__init__.py,sha256=QvlVh4JTl3JL7jQAja76yKtT-IvF4631ASjWY1wS6AQ,22
|
|
2
|
-
unitlog/handlers.py,sha256=K0ph6OxZey8AA7ZuxEycqEkEgZnckghsmN0NKxNg_bI,1768
|
|
3
|
-
unitlog/unit.py,sha256=4JhqZFc-dIpho95_ckwm_P2MU8YkgIJ5ia5lz2K-6Dw,4691
|
|
4
|
-
unitlog/util_log.py,sha256=dbdImt7acamMl1u2HaHgj1Lf0-EF9KnqcLOGr9yPDi8,5202
|
|
5
|
-
unitlog-0.0.2.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
6
|
-
unitlog-0.0.2.dist-info/METADATA,sha256=bRR-kKwSnPRTVw18zBO1gfwDrUv4qMawT6nlHI8y3Yk,574
|
|
7
|
-
unitlog-0.0.2.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
8
|
-
unitlog-0.0.2.dist-info/top_level.txt,sha256=u_R9qvDeq23Wg6BGAP1QB7CuDosByWfI-EfXWa2MO-c,8
|
|
9
|
-
unitlog-0.0.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|