refactor(client): 抽统一日志函数 logLine + 去掉重复时间戳
ci-pangolin / Lint — shellcheck (push) Has been cancelled
ci-pangolin / OpenAPI Sync Check (push) Has been cancelled
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (push) Has been cancelled
ci-pangolin / Flutter — analyze + test (push) Has been cancelled

- 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 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-06-18 22:17:09 +08:00
parent 3a20a40101
commit b9e5dbec9b
4 changed files with 33 additions and 16 deletions
+13 -13
View File
@@ -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<void> 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;
+2 -2
View File
@@ -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);
}
+15
View File
@@ -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');
+3 -1
View File
@@ -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,