|
@@ -21,6 +21,9 @@ TCP_WIN_RE = re.compile(
|
|
|
UDP_WIN_RE = re.compile(
|
|
UDP_WIN_RE = re.compile(
|
|
|
r"udp flow=(?P<flow>\d+) winner=(?P<winner>\S+) target=(?P<host>[^:]+):(?P<port>\d+)"
|
|
r"udp flow=(?P<flow>\d+) winner=(?P<winner>\S+) target=(?P<host>[^:]+):(?P<port>\d+)"
|
|
|
)
|
|
)
|
|
|
|
|
+SOCKS_UDP_SUMMARY_RE = re.compile(
|
|
|
|
|
+ r"udp summary .*?winner_detail=(?P<winner_detail>.*?) (?:target_detail=(?P<target_detail>.*?) )?packets_sent="
|
|
|
|
|
+)
|
|
|
|
|
|
|
|
|
|
|
|
|
def normalize_winner(name: str) -> str:
|
|
def normalize_winner(name: str) -> str:
|
|
@@ -59,6 +62,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
|
|
|
|
|
summary = sub.add_parser("summary", help="汇总透明模式日志里的胜率")
|
|
summary = sub.add_parser("summary", help="汇总透明模式日志里的胜率")
|
|
|
summary.add_argument("--log-file", default="/var/log/mynetspeeder-edge.log")
|
|
summary.add_argument("--log-file", default="/var/log/mynetspeeder-edge.log")
|
|
|
|
|
+ summary.add_argument("--socks-log-file", default="/var/log/mynetspeeder-socks.log")
|
|
|
summary.add_argument("--top", type=int, default=10)
|
|
summary.add_argument("--top", type=int, default=10)
|
|
|
summary.add_argument("--json", action="store_true")
|
|
summary.add_argument("--json", action="store_true")
|
|
|
summary.set_defaults(handler=handle_summary)
|
|
summary.set_defaults(handler=handle_summary)
|
|
@@ -98,6 +102,7 @@ def handle_summary(args: argparse.Namespace) -> int:
|
|
|
log_path = Path(args.log_file)
|
|
log_path = Path(args.log_file)
|
|
|
if not log_path.exists():
|
|
if not log_path.exists():
|
|
|
raise SystemExit(f"log file not found: {log_path}")
|
|
raise SystemExit(f"log file not found: {log_path}")
|
|
|
|
|
+ socks_log_path = Path(args.socks_log_file)
|
|
|
|
|
|
|
|
tcp_total = 0
|
|
tcp_total = 0
|
|
|
tcp_direct = 0
|
|
tcp_direct = 0
|
|
@@ -141,6 +146,48 @@ def handle_summary(args: argparse.Namespace) -> int:
|
|
|
else:
|
|
else:
|
|
|
udp_relay += 1
|
|
udp_relay += 1
|
|
|
|
|
|
|
|
|
|
+ socks_udp_wins: dict[int, tuple[str, str | None]] = {}
|
|
|
|
|
+ if socks_log_path.exists():
|
|
|
|
|
+ for line in socks_log_path.read_text(errors="replace").splitlines():
|
|
|
|
|
+ summary_match = SOCKS_UDP_SUMMARY_RE.search(line)
|
|
|
|
|
+ if not summary_match:
|
|
|
|
|
+ continue
|
|
|
|
|
+ winners_raw = summary_match.group("winner_detail").strip()
|
|
|
|
|
+ targets_raw = (summary_match.group("target_detail") or "").strip()
|
|
|
|
|
+ if winners_raw == "none":
|
|
|
|
|
+ continue
|
|
|
|
|
+ target_map: dict[int, str] = {}
|
|
|
|
|
+ if targets_raw and targets_raw != "none":
|
|
|
|
|
+ for item in targets_raw.split(", "):
|
|
|
|
|
+ parts = item.split(":")
|
|
|
|
|
+ if len(parts) < 3:
|
|
|
|
|
+ continue
|
|
|
|
|
+ try:
|
|
|
|
|
+ flow_id = int(parts[0])
|
|
|
|
|
+ except ValueError:
|
|
|
|
|
+ continue
|
|
|
|
|
+ target_map[flow_id] = f"{':'.join(parts[1:-1])}:{parts[-1]}"
|
|
|
|
|
+ for item in winners_raw.split(", "):
|
|
|
|
|
+ flow_parts = item.split(":", 1)
|
|
|
|
|
+ if len(flow_parts) != 2:
|
|
|
|
|
+ continue
|
|
|
|
|
+ try:
|
|
|
|
|
+ flow_id = int(flow_parts[0])
|
|
|
|
|
+ except ValueError:
|
|
|
|
|
+ continue
|
|
|
|
|
+ winner = normalize_winner(flow_parts[1])
|
|
|
|
|
+ socks_udp_wins[flow_id] = (winner, target_map.get(flow_id))
|
|
|
|
|
+
|
|
|
|
|
+ for winner, target in socks_udp_wins.values():
|
|
|
|
|
+ udp_total += 1
|
|
|
|
|
+ udp_winners[winner] += 1
|
|
|
|
|
+ if winner == "direct":
|
|
|
|
|
+ udp_direct += 1
|
|
|
|
|
+ else:
|
|
|
|
|
+ udp_relay += 1
|
|
|
|
|
+ if target:
|
|
|
|
|
+ udp_targets[target][winner] += 1
|
|
|
|
|
+
|
|
|
tcp_ordered_targets = sorted(
|
|
tcp_ordered_targets = sorted(
|
|
|
tcp_targets.items(),
|
|
tcp_targets.items(),
|
|
|
key=lambda item: sum(item[1].values()),
|
|
key=lambda item: sum(item[1].values()),
|
|
@@ -187,6 +234,8 @@ def handle_summary(args: argparse.Namespace) -> int:
|
|
|
return 0
|
|
return 0
|
|
|
|
|
|
|
|
print(f"log: {log_path}")
|
|
print(f"log: {log_path}")
|
|
|
|
|
+ if socks_log_path.exists():
|
|
|
|
|
+ print(f"socks_log: {socks_log_path}")
|
|
|
for protocol in ("tcp", "udp"):
|
|
for protocol in ("tcp", "udp"):
|
|
|
section = result[protocol]
|
|
section = result[protocol]
|
|
|
print(f"{protocol}: total={section['total']} direct={section['direct']} relay={section['relay']}")
|
|
print(f"{protocol}: total={section['total']} direct={section['direct']} relay={section['relay']}")
|