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():
log_message_sync(direction, message)
except asyncio.CancelledError:
break
except Exception:
except Exception as e:
await log_exception_async(e, "日志写入循环")
await asyncio.sleep(0.05)
async def log_message(direction, message):
......@@ -85,6 +86,34 @@ async def log_message(direction, message):
if _log_dropped_count % 100 == 1:
print(f"警告: 日志队列已满,已丢弃 {_log_dropped_count} 条日志")
async def log_exception_async(exc, context=""):
"""异步记录异常到日志"""
try:
exc_type = type(exc).__name__
exc_msg = str(exc)
exc_traceback = traceback.format_exc()
error_msg = f"异常[{context}]: {exc_type}: {exc_msg}\n堆栈:\n{exc_traceback}"
await log_message("异常", error_msg)
except Exception:
pass # 记录异常失败时pass,避免循环异常
def log_exception_sync_to_async(exc, context=""):
"""同步函数中将异常放入异步日志队列"""
try:
exc_type = type(exc).__name__
exc_msg = str(exc)
exc_traceback = traceback.format_exc()
error_msg = f"异常[{context}]: {exc_type}: {exc_msg}\n堆栈:\n{exc_traceback}"
global _log_queue, _log_task
if _log_queue is not None:
try:
_log_queue.put_nowait(("异常", error_msg))
except asyncio.QueueFull:
pass # 队列满时pass
except Exception:
pass # 记录异常失败时pass
def is_port_in_use(port, host='localhost'):
"""检查端口是否被占用"""
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
......@@ -110,11 +139,13 @@ async def self_test(websocket):
response = await asyncio.wait_for(websocket.recv(), timeout=5.0)
await log_message("自测响应", response)
return True
except asyncio.TimeoutError:
await log_message("自测", "自测超时,未收到响应")
except asyncio.TimeoutError as e:
await log_exception_async(e, "自测超时")
pass
return False
except Exception as e:
await log_message("自测", f"自测异常: {str(e)}")
await log_exception_async(e, "自测")
pass
return False
class BLEClient:
......@@ -140,8 +171,9 @@ class BLEClient:
loop = asyncio.get_event_loop()
if loop.is_running():
loop.create_task(self.close_websocket())
except Exception:
except Exception as e:
# 如果没有事件循环,直接设置为None(延迟清理)
log_exception_sync_to_async(e, "on_disconnect获取事件循环")
pass
async def close_websocket(self):
......@@ -153,7 +185,8 @@ class BLEClient:
await self.websocket.close(code=1000, reason="BLE connection closed")
print("WebSocket连接已关闭")
except Exception as e:
print(f"关闭WebSocket时出错: {e}")
await log_exception_async(e, "关闭WebSocket")
pass
finally:
self.websocket = None
self._shutdown = True
......@@ -189,7 +222,8 @@ class BLEClient:
if self._scanner is not None:
# 在事件循环中停止扫描,避免阻塞回调
asyncio.create_task(self._stop_scan_early())
except Exception:
except Exception as e:
log_exception_sync_to_async(e, "detection_callback停止扫描")
pass
return self.target_device
......@@ -197,7 +231,8 @@ class BLEClient:
try:
if self._scanner is not None:
await self._scanner.stop()
except Exception:
except Exception as e:
await log_exception_async(e, "_stop_scan_early")
pass
async def handle_client(self, websocket, path):
......@@ -248,7 +283,8 @@ class BLEClient:
finally:
try:
await self._scanner.stop()
except Exception:
except Exception as e:
await log_exception_async(e, "扫描停止")
pass
self._scanner = None
......@@ -291,7 +327,8 @@ class BLEClient:
if self.client and self.client.is_connected:
try:
await self.client.disconnect()
except Exception:
except Exception as e:
await log_exception_async(e, "connect断开旧连接")
pass
try:
......@@ -318,6 +355,7 @@ class BLEClient:
if not websocket.closed:
await websocket.send(error_response)
except Exception as e:
await log_exception_async(e, "connect连接BLE")
error_response = json.dumps({
"jsonrpc": "2.0",
"result": None,
......@@ -328,6 +366,7 @@ class BLEClient:
await websocket.send(error_response)
if self.client:
self.client = None
pass
elif method == "write":
service_id = params.get("serviceId")
......@@ -354,6 +393,7 @@ class BLEClient:
if not websocket.closed:
await websocket.send(response)
except Exception as e:
await log_exception_async(e, "write写入特征值")
error_response = json.dumps({
"jsonrpc": "2.0",
"result": None,
......@@ -362,6 +402,7 @@ class BLEClient:
await log_message("下发", error_response)
if not websocket.closed:
await websocket.send(error_response)
pass
else:
error_response = json.dumps({
"jsonrpc": "2.0",
......@@ -397,7 +438,8 @@ class BLEClient:
# 检查WebSocket状态后再发送
if not websocket.closed:
await websocket.send(response)
except asyncio.TimeoutError:
except asyncio.TimeoutError as e:
await log_exception_async(e, "read读取超时")
error_response = json.dumps({
"jsonrpc": "2.0",
"result": None,
......@@ -406,7 +448,9 @@ class BLEClient:
await log_message("下发", error_response)
if not websocket.closed:
await websocket.send(error_response)
pass
except Exception as e:
await log_exception_async(e, "read读取特征值")
error_response = json.dumps({
"jsonrpc": "2.0",
"result": None,
......@@ -416,6 +460,7 @@ class BLEClient:
# 检查WebSocket状态后再发送
if not websocket.closed:
await websocket.send(error_response)
pass
else:
error_response = json.dumps({
"jsonrpc": "2.0",
......@@ -436,7 +481,8 @@ class BLEClient:
if characteristic_id in self._notification_callbacks:
try:
await self.client.stop_notify(characteristic_id)
except Exception:
except Exception as e:
await log_exception_async(e, "startNotifications停止旧通知")
pass
# 创建新的通知处理器
......@@ -453,6 +499,7 @@ class BLEClient:
if not websocket.closed:
await websocket.send(response)
except Exception as e:
await log_exception_async(e, "startNotifications启动通知")
error_response = json.dumps({
"jsonrpc": "2.0",
"result": None,
......@@ -461,6 +508,7 @@ class BLEClient:
await log_message("下发", error_response)
if not websocket.closed:
await websocket.send(error_response)
pass
else:
error_response = json.dumps({
"jsonrpc": "2.0",
......@@ -483,6 +531,7 @@ class BLEClient:
await websocket.send(response)
except json.JSONDecodeError as e:
await log_exception_async(e, "JSON解析")
error_msg = json.dumps({
"jsonrpc": "2.0",
"result": None,
......@@ -492,13 +541,12 @@ class BLEClient:
try:
if not websocket.closed:
await websocket.send(error_msg)
except Exception:
except Exception as e2:
await log_exception_async(e2, "JSON解析后发送响应")
pass
pass
except Exception as e:
# 记录完整错误堆栈
error_trace = traceback.format_exc()
print(f"处理请求时出错: {error_trace}")
await log_exception_async(e, "处理请求")
error_msg = json.dumps({
"jsonrpc": "2.0",
"result": None,
......@@ -508,11 +556,14 @@ class BLEClient:
try:
if not websocket.closed:
await websocket.send(error_msg)
except Exception:
except Exception as e2:
await log_exception_async(e2, "处理请求后发送响应")
pass
pass
except websockets.exceptions.ConnectionClosed:
print("WebSocket连接关闭")
except websockets.exceptions.ConnectionClosed as e:
await log_exception_async(e, "WebSocket连接关闭")
pass
finally:
# 清理BLE连接和通知
self._shutdown = True
......@@ -523,12 +574,14 @@ class BLEClient:
try:
await self.client.stop_notify(characteristic_id)
except Exception as e:
print(f"停止通知失败 {characteristic_id}: {e}")
await log_exception_async(e, f"停止通知{characteristic_id}")
pass
# 断开连接
await self.client.disconnect()
except Exception as e:
print(f"断开BLE连接失败: {e}")
await log_exception_async(e, "断开BLE连接")
pass
finally:
self.client = None
self.target_device = None
......@@ -570,18 +623,22 @@ class BLEClient:
try:
await log_message("下发", response)
except Exception as e:
print(f"日志写入失败: {e}")
await log_exception_async(e, "notification_handler日志写入")
pass
# 发送响应
try:
await websocket.send(response)
except websockets.exceptions.ConnectionClosed:
print("WebSocket连接已关闭,停止发送通知")
except websockets.exceptions.ConnectionClosed as e:
await log_exception_async(e, "notification_handler发送通知连接关闭")
self._shutdown = True
pass
except Exception as e:
print(f"发送通知失败: {e}")
await log_exception_async(e, "notification_handler发送通知")
pass
except Exception as e:
print(f"通知处理器出错: {e}")
await log_exception_async(e, "notification_handler")
pass
return callback
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'):
else:
print("自检测试失败: 服务可能存在问题")
except Exception as e:
print(f"自检测试异常: {str(e)}")
await log_exception_async(e, "自检测试")
pass
return server
......@@ -628,12 +686,14 @@ async def main():
if _log_queue is not None:
try:
await _log_queue.put(None)
except Exception:
except Exception as e:
await log_exception_async(e, "main清理日志队列")
pass
if _log_task is not None:
try:
await _log_task
except Exception:
except Exception as e:
await log_exception_async(e, "main等待日志任务")
pass
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!