From b9e5dbec9b72917ef8101ff2ecb3677170a6c730 Mon Sep 17 00:00:00 2001 From: wangjia <809946525@qq.com> Date: Thu, 18 Jun 2026 22:17:09 +0800 Subject: [PATCH] =?UTF-8?q?refactor(client):=20=E6=8A=BD=E7=BB=9F=E4=B8=80?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E5=87=BD=E6=95=B0=20logLine=20+=20=E5=8E=BB?= =?UTF-8?q?=E6=8E=89=E9=87=8D=E5=A4=8D=E6=97=B6=E9=97=B4=E6=88=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - log_time.dart → log.dart:提供 logLine(tag, msg),格式 `[时:分:秒.毫秒] [tag] msg`, DesktopKernel / DesktopVpnBridge 散落的 print+拼接全部收敛到此。 - 下发配置 log.timestamp=false:sing-box 不再自带时间戳,避免一行打印两个时间 (之前 `[22:10:35.213] [stderr] +0800 2026-06-18 22:10:35 ...` 重复)。 Co-Authored-By: Claude Opus 4.8 --- client/lib/bridge/desktop_vpn_bridge.dart | 26 +++++++++++------------ client/lib/bridge/kernel_process.dart | 4 ++-- client/lib/bridge/log.dart | 15 +++++++++++++ server/internal/httpapi/clientconfig.go | 4 +++- 4 files changed, 33 insertions(+), 16 deletions(-) create mode 100644 client/lib/bridge/log.dart diff --git a/client/lib/bridge/desktop_vpn_bridge.dart b/client/lib/bridge/desktop_vpn_bridge.dart index cf17ac8..7656ace 100644 --- a/client/lib/bridge/desktop_vpn_bridge.dart +++ b/client/lib/bridge/desktop_vpn_bridge.dart @@ -25,7 +25,7 @@ import 'dart:convert'; import 'dart:io'; import 'kernel_process.dart'; -import 'log_time.dart'; +import 'log.dart'; import 'vpn_bridge.dart'; /// 桌面端 VPN 桥接实现(macOS / Linux / Windows PoC)。 @@ -101,9 +101,9 @@ class DesktopVpnBridge implements VpnBridge { // 3. 写 config 到应用支持目录(0600 权限) final configPath = await writeConfig(enrichedJson); - print('${logTime()}[DesktopVpnBridge] config written: $configPath'); - print('${logTime()}[DesktopVpnBridge] clash_api port=$port secret_len=${secret.length}'); - print('${logTime()}[DesktopVpnBridge] killSwitch=$_killSwitchEnabled'); + logLine('DesktopVpnBridge', 'config written: $configPath'); + logLine('DesktopVpnBridge', 'clash_api port=$port secret_len=${secret.length}'); + logLine('DesktopVpnBridge', 'killSwitch=$_killSwitchEnabled'); // 4. 启动内核子进程(blocking until Clash API ready or error) await _kernel.spawn(configPath); @@ -142,7 +142,7 @@ class DesktopVpnBridge implements VpnBridge { try { await _kernel.clashApiClient.selectProxy('proxy', tag); } catch (e) { - print('${logTime()}[DesktopVpnBridge] selectOutbound(tag=$tag) error: $e'); + logLine('DesktopVpnBridge', 'selectOutbound(tag=$tag) error: $e'); rethrow; } } @@ -178,11 +178,11 @@ class DesktopVpnBridge implements VpnBridge { Future setKillSwitch({required bool on}) async { if (_killSwitchEnabled == on) return; _killSwitchEnabled = on; - print('${logTime()}[DesktopVpnBridge] setKillSwitch=$on'); + logLine('DesktopVpnBridge', 'setKillSwitch=$on'); // 若内核正在运行,用新设置重载(会有约 1~2s 重连) if (_kernel.isRunning && _lastUserConfigJson != null) { - print('${logTime()}[DesktopVpnBridge] reloading kernel for killSwitch change'); + logLine('DesktopVpnBridge', 'reloading kernel for killSwitch change'); // 暂停自动重连,避免 kill 触发重连定时器 final wasAutoReconnect = _shouldAutoReconnect; _shouldAutoReconnect = false; @@ -230,18 +230,18 @@ class DesktopVpnBridge implements VpnBridge { _reconnectAttempt.clamp(0, _kRetryDelaysSec.length - 1)]; _reconnectAttempt++; - print( - '${logTime()}[DesktopVpnBridge] auto-reconnect in ${delaySec}s (attempt $_reconnectAttempt)'); + logLine('DesktopVpnBridge', + 'auto-reconnect in ${delaySec}s (attempt $_reconnectAttempt)'); _reconnectTimer = Timer(Duration(seconds: delaySec), () async { if (!_shouldAutoReconnect || _lastUserConfigJson == null) return; try { - print('${logTime()}[DesktopVpnBridge] auto-reconnect: attempting start...'); + logLine('DesktopVpnBridge', 'auto-reconnect: attempting start...'); await start(_lastUserConfigJson!); _reconnectAttempt = 0; // 成功后重置退避计数 - print('${logTime()}[DesktopVpnBridge] auto-reconnect: success'); + logLine('DesktopVpnBridge', 'auto-reconnect: success'); } catch (e) { - print('${logTime()}[DesktopVpnBridge] auto-reconnect: start failed: $e'); + logLine('DesktopVpnBridge', 'auto-reconnect: start failed: $e'); // start() 失败(内核未能启动)→ 手动调度下一次重试 if (_shouldAutoReconnect) _scheduleReconnect(); } @@ -342,7 +342,7 @@ class DesktopVpnBridge implements VpnBridge { try { await Process.run('chmod', ['600', file.path]); } catch (_) { - print('${logTime()}[DesktopVpnBridge] warning: chmod 600 failed for ${file.path}'); + logLine('DesktopVpnBridge', 'warning: chmod 600 failed for ${file.path}'); } } return file.path; diff --git a/client/lib/bridge/kernel_process.dart b/client/lib/bridge/kernel_process.dart index 85b1203..b341214 100644 --- a/client/lib/bridge/kernel_process.dart +++ b/client/lib/bridge/kernel_process.dart @@ -30,7 +30,7 @@ import 'dart:math' as math; import 'package:http/http.dart' as http; -import 'log_time.dart'; +import 'log.dart'; import 'vpn_bridge.dart'; // ══════════════════════════════════════════════════════════════════ @@ -482,7 +482,7 @@ class DesktopKernelProcess implements KernelProcess { } void _log(String msg) { - print('${logTime()}[DesktopKernel] $msg'); + logLine('DesktopKernel', msg); if (!_logCtrl.isClosed) _logCtrl.add(msg); } diff --git a/client/lib/bridge/log.dart b/client/lib/bridge/log.dart new file mode 100644 index 0000000..bb835ca --- /dev/null +++ b/client/lib/bridge/log.dart @@ -0,0 +1,15 @@ +// log.dart — 桌面端统一日志出口。 +// 格式: `[时:分:秒.毫秒] [tag] msg`,全部走 logLine(),便于排查时序。 +// 注:sing-box 自身时间戳已在下发配置里关闭(log.timestamp=false), +// 避免与这里的前缀重复打印两个时间。 + +// ignore_for_file: avoid_print + +String _ts() { + final n = DateTime.now(); + String p(int v, [int w = 2]) => v.toString().padLeft(w, '0'); + return '${p(n.hour)}:${p(n.minute)}:${p(n.second)}.${p(n.millisecond, 3)}'; +} + +/// 打印一行带时间戳与标签的桌面端日志。 +void logLine(String tag, String msg) => print('[${_ts()}] [$tag] $msg'); diff --git a/server/internal/httpapi/clientconfig.go b/server/internal/httpapi/clientconfig.go index 8ccbfb4..97cdb06 100644 --- a/server/internal/httpapi/clientconfig.go +++ b/server/internal/httpapi/clientconfig.go @@ -143,7 +143,9 @@ func BuildClientConfig(node *nodes.NodeRow, dpUUID, deriveKey string) ([]byte, e } cfg := map[string]any{ - "log": map[string]any{"level": "warn", "timestamp": true}, + // timestamp=false:客户端日志出口(logLine)已统一加时间戳, + // 关掉 sing-box 自带时间戳避免一行打印两个时间。 + "log": map[string]any{"level": "warn", "timestamp": false}, "inbounds": []any{tunIn}, "outbounds": append(proxyOutbounds, autoBest,