bb536a51 by huangyf2

异常处理,记录日志

1 parent 0e90a8e9
Showing 1 changed file with 90 additions and 30 deletions
...@@ -66,7 +66,8 @@ async def _log_writer_loop(): ...@@ -66,7 +66,8 @@ async def _log_writer_loop():
66 log_message_sync(direction, message) 66 log_message_sync(direction, message)
67 except asyncio.CancelledError: 67 except asyncio.CancelledError:
68 break 68 break
69 except Exception: 69 except Exception as e:
70 await log_exception_async(e, "日志写入循环")
70 await asyncio.sleep(0.05) 71 await asyncio.sleep(0.05)
71 72
72 async def log_message(direction, message): 73 async def log_message(direction, message):
...@@ -85,6 +86,34 @@ async def log_message(direction, message): ...@@ -85,6 +86,34 @@ async def log_message(direction, message):
85 if _log_dropped_count % 100 == 1: 86 if _log_dropped_count % 100 == 1:
86 print(f"警告: 日志队列已满,已丢弃 {_log_dropped_count} 条日志") 87 print(f"警告: 日志队列已满,已丢弃 {_log_dropped_count} 条日志")
87 88
89 async def log_exception_async(exc, context=""):
90 """异步记录异常到日志"""
91 try:
92 exc_type = type(exc).__name__
93 exc_msg = str(exc)
94 exc_traceback = traceback.format_exc()
95 error_msg = f"异常[{context}]: {exc_type}: {exc_msg}\n堆栈:\n{exc_traceback}"
96 await log_message("异常", error_msg)
97 except Exception:
98 pass # 记录异常失败时pass,避免循环异常
99
100 def log_exception_sync_to_async(exc, context=""):
101 """同步函数中将异常放入异步日志队列"""
102 try:
103 exc_type = type(exc).__name__
104 exc_msg = str(exc)
105 exc_traceback = traceback.format_exc()
106 error_msg = f"异常[{context}]: {exc_type}: {exc_msg}\n堆栈:\n{exc_traceback}"
107
108 global _log_queue, _log_task
109 if _log_queue is not None:
110 try:
111 _log_queue.put_nowait(("异常", error_msg))
112 except asyncio.QueueFull:
113 pass # 队列满时pass
114 except Exception:
115 pass # 记录异常失败时pass
116
88 def is_port_in_use(port, host='localhost'): 117 def is_port_in_use(port, host='localhost'):
89 """检查端口是否被占用""" 118 """检查端口是否被占用"""
90 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 119 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
...@@ -110,11 +139,13 @@ async def self_test(websocket): ...@@ -110,11 +139,13 @@ async def self_test(websocket):
110 response = await asyncio.wait_for(websocket.recv(), timeout=5.0) 139 response = await asyncio.wait_for(websocket.recv(), timeout=5.0)
111 await log_message("自测响应", response) 140 await log_message("自测响应", response)
112 return True 141 return True
113 except asyncio.TimeoutError: 142 except asyncio.TimeoutError as e:
114 await log_message("自测", "自测超时,未收到响应") 143 await log_exception_async(e, "自测超时")
144 pass
115 return False 145 return False
116 except Exception as e: 146 except Exception as e:
117 await log_message("自测", f"自测异常: {str(e)}") 147 await log_exception_async(e, "自测")
148 pass
118 return False 149 return False
119 150
120 class BLEClient: 151 class BLEClient:
...@@ -140,8 +171,9 @@ class BLEClient: ...@@ -140,8 +171,9 @@ class BLEClient:
140 loop = asyncio.get_event_loop() 171 loop = asyncio.get_event_loop()
141 if loop.is_running(): 172 if loop.is_running():
142 loop.create_task(self.close_websocket()) 173 loop.create_task(self.close_websocket())
143 except Exception: 174 except Exception as e:
144 # 如果没有事件循环,直接设置为None(延迟清理) 175 # 如果没有事件循环,直接设置为None(延迟清理)
176 log_exception_sync_to_async(e, "on_disconnect获取事件循环")
145 pass 177 pass
146 178
147 async def close_websocket(self): 179 async def close_websocket(self):
...@@ -153,7 +185,8 @@ class BLEClient: ...@@ -153,7 +185,8 @@ class BLEClient:
153 await self.websocket.close(code=1000, reason="BLE connection closed") 185 await self.websocket.close(code=1000, reason="BLE connection closed")
154 print("WebSocket连接已关闭") 186 print("WebSocket连接已关闭")
155 except Exception as e: 187 except Exception as e:
156 print(f"关闭WebSocket时出错: {e}") 188 await log_exception_async(e, "关闭WebSocket")
189 pass
157 finally: 190 finally:
158 self.websocket = None 191 self.websocket = None
159 self._shutdown = True 192 self._shutdown = True
...@@ -189,7 +222,8 @@ class BLEClient: ...@@ -189,7 +222,8 @@ class BLEClient:
189 if self._scanner is not None: 222 if self._scanner is not None:
190 # 在事件循环中停止扫描,避免阻塞回调 223 # 在事件循环中停止扫描,避免阻塞回调
191 asyncio.create_task(self._stop_scan_early()) 224 asyncio.create_task(self._stop_scan_early())
192 except Exception: 225 except Exception as e:
226 log_exception_sync_to_async(e, "detection_callback停止扫描")
193 pass 227 pass
194 return self.target_device 228 return self.target_device
195 229
...@@ -197,7 +231,8 @@ class BLEClient: ...@@ -197,7 +231,8 @@ class BLEClient:
197 try: 231 try:
198 if self._scanner is not None: 232 if self._scanner is not None:
199 await self._scanner.stop() 233 await self._scanner.stop()
200 except Exception: 234 except Exception as e:
235 await log_exception_async(e, "_stop_scan_early")
201 pass 236 pass
202 237
203 async def handle_client(self, websocket, path): 238 async def handle_client(self, websocket, path):
...@@ -248,7 +283,8 @@ class BLEClient: ...@@ -248,7 +283,8 @@ class BLEClient:
248 finally: 283 finally:
249 try: 284 try:
250 await self._scanner.stop() 285 await self._scanner.stop()
251 except Exception: 286 except Exception as e:
287 await log_exception_async(e, "扫描停止")
252 pass 288 pass
253 self._scanner = None 289 self._scanner = None
254 290
...@@ -291,7 +327,8 @@ class BLEClient: ...@@ -291,7 +327,8 @@ class BLEClient:
291 if self.client and self.client.is_connected: 327 if self.client and self.client.is_connected:
292 try: 328 try:
293 await self.client.disconnect() 329 await self.client.disconnect()
294 except Exception: 330 except Exception as e:
331 await log_exception_async(e, "connect断开旧连接")
295 pass 332 pass
296 333
297 try: 334 try:
...@@ -318,6 +355,7 @@ class BLEClient: ...@@ -318,6 +355,7 @@ class BLEClient:
318 if not websocket.closed: 355 if not websocket.closed:
319 await websocket.send(error_response) 356 await websocket.send(error_response)
320 except Exception as e: 357 except Exception as e:
358 await log_exception_async(e, "connect连接BLE")
321 error_response = json.dumps({ 359 error_response = json.dumps({
322 "jsonrpc": "2.0", 360 "jsonrpc": "2.0",
323 "result": None, 361 "result": None,
...@@ -328,6 +366,7 @@ class BLEClient: ...@@ -328,6 +366,7 @@ class BLEClient:
328 await websocket.send(error_response) 366 await websocket.send(error_response)
329 if self.client: 367 if self.client:
330 self.client = None 368 self.client = None
369 pass
331 370
332 elif method == "write": 371 elif method == "write":
333 service_id = params.get("serviceId") 372 service_id = params.get("serviceId")
...@@ -354,6 +393,7 @@ class BLEClient: ...@@ -354,6 +393,7 @@ class BLEClient:
354 if not websocket.closed: 393 if not websocket.closed:
355 await websocket.send(response) 394 await websocket.send(response)
356 except Exception as e: 395 except Exception as e:
396 await log_exception_async(e, "write写入特征值")
357 error_response = json.dumps({ 397 error_response = json.dumps({
358 "jsonrpc": "2.0", 398 "jsonrpc": "2.0",
359 "result": None, 399 "result": None,
...@@ -362,6 +402,7 @@ class BLEClient: ...@@ -362,6 +402,7 @@ class BLEClient:
362 await log_message("下发", error_response) 402 await log_message("下发", error_response)
363 if not websocket.closed: 403 if not websocket.closed:
364 await websocket.send(error_response) 404 await websocket.send(error_response)
405 pass
365 else: 406 else:
366 error_response = json.dumps({ 407 error_response = json.dumps({
367 "jsonrpc": "2.0", 408 "jsonrpc": "2.0",
...@@ -397,7 +438,8 @@ class BLEClient: ...@@ -397,7 +438,8 @@ class BLEClient:
397 # 检查WebSocket状态后再发送 438 # 检查WebSocket状态后再发送
398 if not websocket.closed: 439 if not websocket.closed:
399 await websocket.send(response) 440 await websocket.send(response)
400 except asyncio.TimeoutError: 441 except asyncio.TimeoutError as e:
442 await log_exception_async(e, "read读取超时")
401 error_response = json.dumps({ 443 error_response = json.dumps({
402 "jsonrpc": "2.0", 444 "jsonrpc": "2.0",
403 "result": None, 445 "result": None,
...@@ -406,7 +448,9 @@ class BLEClient: ...@@ -406,7 +448,9 @@ class BLEClient:
406 await log_message("下发", error_response) 448 await log_message("下发", error_response)
407 if not websocket.closed: 449 if not websocket.closed:
408 await websocket.send(error_response) 450 await websocket.send(error_response)
451 pass
409 except Exception as e: 452 except Exception as e:
453 await log_exception_async(e, "read读取特征值")
410 error_response = json.dumps({ 454 error_response = json.dumps({
411 "jsonrpc": "2.0", 455 "jsonrpc": "2.0",
412 "result": None, 456 "result": None,
...@@ -416,6 +460,7 @@ class BLEClient: ...@@ -416,6 +460,7 @@ class BLEClient:
416 # 检查WebSocket状态后再发送 460 # 检查WebSocket状态后再发送
417 if not websocket.closed: 461 if not websocket.closed:
418 await websocket.send(error_response) 462 await websocket.send(error_response)
463 pass
419 else: 464 else:
420 error_response = json.dumps({ 465 error_response = json.dumps({
421 "jsonrpc": "2.0", 466 "jsonrpc": "2.0",
...@@ -436,7 +481,8 @@ class BLEClient: ...@@ -436,7 +481,8 @@ class BLEClient:
436 if characteristic_id in self._notification_callbacks: 481 if characteristic_id in self._notification_callbacks:
437 try: 482 try:
438 await self.client.stop_notify(characteristic_id) 483 await self.client.stop_notify(characteristic_id)
439 except Exception: 484 except Exception as e:
485 await log_exception_async(e, "startNotifications停止旧通知")
440 pass 486 pass
441 487
442 # 创建新的通知处理器 488 # 创建新的通知处理器
...@@ -453,6 +499,7 @@ class BLEClient: ...@@ -453,6 +499,7 @@ class BLEClient:
453 if not websocket.closed: 499 if not websocket.closed:
454 await websocket.send(response) 500 await websocket.send(response)
455 except Exception as e: 501 except Exception as e:
502 await log_exception_async(e, "startNotifications启动通知")
456 error_response = json.dumps({ 503 error_response = json.dumps({
457 "jsonrpc": "2.0", 504 "jsonrpc": "2.0",
458 "result": None, 505 "result": None,
...@@ -461,6 +508,7 @@ class BLEClient: ...@@ -461,6 +508,7 @@ class BLEClient:
461 await log_message("下发", error_response) 508 await log_message("下发", error_response)
462 if not websocket.closed: 509 if not websocket.closed:
463 await websocket.send(error_response) 510 await websocket.send(error_response)
511 pass
464 else: 512 else:
465 error_response = json.dumps({ 513 error_response = json.dumps({
466 "jsonrpc": "2.0", 514 "jsonrpc": "2.0",
...@@ -483,6 +531,7 @@ class BLEClient: ...@@ -483,6 +531,7 @@ class BLEClient:
483 await websocket.send(response) 531 await websocket.send(response)
484 532
485 except json.JSONDecodeError as e: 533 except json.JSONDecodeError as e:
534 await log_exception_async(e, "JSON解析")
486 error_msg = json.dumps({ 535 error_msg = json.dumps({
487 "jsonrpc": "2.0", 536 "jsonrpc": "2.0",
488 "result": None, 537 "result": None,
...@@ -492,13 +541,12 @@ class BLEClient: ...@@ -492,13 +541,12 @@ class BLEClient:
492 try: 541 try:
493 if not websocket.closed: 542 if not websocket.closed:
494 await websocket.send(error_msg) 543 await websocket.send(error_msg)
495 except Exception: 544 except Exception as e2:
545 await log_exception_async(e2, "JSON解析后发送响应")
546 pass
496 pass 547 pass
497 except Exception as e: 548 except Exception as e:
498 # 记录完整错误堆栈 549 await log_exception_async(e, "处理请求")
499 error_trace = traceback.format_exc()
500 print(f"处理请求时出错: {error_trace}")
501
502 error_msg = json.dumps({ 550 error_msg = json.dumps({
503 "jsonrpc": "2.0", 551 "jsonrpc": "2.0",
504 "result": None, 552 "result": None,
...@@ -508,11 +556,14 @@ class BLEClient: ...@@ -508,11 +556,14 @@ class BLEClient:
508 try: 556 try:
509 if not websocket.closed: 557 if not websocket.closed:
510 await websocket.send(error_msg) 558 await websocket.send(error_msg)
511 except Exception: 559 except Exception as e2:
560 await log_exception_async(e2, "处理请求后发送响应")
561 pass
512 pass 562 pass
513 563
514 except websockets.exceptions.ConnectionClosed: 564 except websockets.exceptions.ConnectionClosed as e:
515 print("WebSocket连接关闭") 565 await log_exception_async(e, "WebSocket连接关闭")
566 pass
516 finally: 567 finally:
517 # 清理BLE连接和通知 568 # 清理BLE连接和通知
518 self._shutdown = True 569 self._shutdown = True
...@@ -523,12 +574,14 @@ class BLEClient: ...@@ -523,12 +574,14 @@ class BLEClient:
523 try: 574 try:
524 await self.client.stop_notify(characteristic_id) 575 await self.client.stop_notify(characteristic_id)
525 except Exception as e: 576 except Exception as e:
526 print(f"停止通知失败 {characteristic_id}: {e}") 577 await log_exception_async(e, f"停止通知{characteristic_id}")
578 pass
527 579
528 # 断开连接 580 # 断开连接
529 await self.client.disconnect() 581 await self.client.disconnect()
530 except Exception as e: 582 except Exception as e:
531 print(f"断开BLE连接失败: {e}") 583 await log_exception_async(e, "断开BLE连接")
584 pass
532 finally: 585 finally:
533 self.client = None 586 self.client = None
534 self.target_device = None 587 self.target_device = None
...@@ -570,18 +623,22 @@ class BLEClient: ...@@ -570,18 +623,22 @@ class BLEClient:
570 try: 623 try:
571 await log_message("下发", response) 624 await log_message("下发", response)
572 except Exception as e: 625 except Exception as e:
573 print(f"日志写入失败: {e}") 626 await log_exception_async(e, "notification_handler日志写入")
627 pass
574 628
575 # 发送响应 629 # 发送响应
576 try: 630 try:
577 await websocket.send(response) 631 await websocket.send(response)
578 except websockets.exceptions.ConnectionClosed: 632 except websockets.exceptions.ConnectionClosed as e:
579 print("WebSocket连接已关闭,停止发送通知") 633 await log_exception_async(e, "notification_handler发送通知连接关闭")
580 self._shutdown = True 634 self._shutdown = True
635 pass
581 except Exception as e: 636 except Exception as e:
582 print(f"发送通知失败: {e}") 637 await log_exception_async(e, "notification_handler发送通知")
638 pass
583 except Exception as e: 639 except Exception as e:
584 print(f"通知处理器出错: {e}") 640 await log_exception_async(e, "notification_handler")
641 pass
585 return callback 642 return callback
586 643
587 async def check_port_and_start_server(port=20111, host='localhost'): 644 async def check_port_and_start_server(port=20111, host='localhost'):
...@@ -613,7 +670,8 @@ async def check_port_and_start_server(port=20111, host='localhost'): ...@@ -613,7 +670,8 @@ async def check_port_and_start_server(port=20111, host='localhost'):
613 else: 670 else:
614 print("自检测试失败: 服务可能存在问题") 671 print("自检测试失败: 服务可能存在问题")
615 except Exception as e: 672 except Exception as e:
616 print(f"自检测试异常: {str(e)}") 673 await log_exception_async(e, "自检测试")
674 pass
617 675
618 return server 676 return server
619 677
...@@ -628,12 +686,14 @@ async def main(): ...@@ -628,12 +686,14 @@ async def main():
628 if _log_queue is not None: 686 if _log_queue is not None:
629 try: 687 try:
630 await _log_queue.put(None) 688 await _log_queue.put(None)
631 except Exception: 689 except Exception as e:
690 await log_exception_async(e, "main清理日志队列")
632 pass 691 pass
633 if _log_task is not None: 692 if _log_task is not None:
634 try: 693 try:
635 await _log_task 694 await _log_task
636 except Exception: 695 except Exception as e:
696 await log_exception_async(e, "main等待日志任务")
637 pass 697 pass
638 698
639 if __name__ == "__main__": 699 if __name__ == "__main__":
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!