异常处理,记录日志
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__": | ... | ... |
-
Please register or sign in to post a comment