package transport import ( "encoding/json" "fmt" "os" "path/filepath" "sync" ) // KCPPacketDebugRecord 是 KCP 底层 UDP packet kernel timestamp 的一条 JSONL 调试记录。 type KCPPacketDebugRecord struct { Event string `json:"event"` NodeRole string `json:"node_role,omitempty"` NodeID string `json:"node_id,omitempty"` LocalAddr string `json:"local_addr,omitempty"` RemoteAddr string `json:"remote_addr,omitempty"` PacketBytes int `json:"packet_bytes"` UDPTXID *uint32 `json:"udp_tx_id,omitempty"` KCPConv *uint32 `json:"kcp_conv,omitempty"` Segments []KCPPacketDebugSegment `json:"segments,omitempty"` TSUnixNano int64 `json:"ts_unix_nano"` } // KCPPacketDebugSegment 是一个 UDP datagram 中解析出的 KCP segment 头信息。 type KCPPacketDebugSegment struct { Cmd uint8 `json:"cmd"` SN uint32 `json:"sn"` UNA uint32 `json:"una"` Frg uint8 `json:"frg"` Wnd uint16 `json:"wnd"` Len uint32 `json:"len"` } // KCPPacketDebugLogger 接收 KCP packet 级调试记录。 type KCPPacketDebugLogger interface { LogKCPPacketDebugRecord(record KCPPacketDebugRecord) error } // JSONLKCPPacketDebugLogger 以 JSONL 形式追加写 KCP packet 调试日志。 type JSONLKCPPacketDebugLogger struct { mu sync.Mutex closeOnce sync.Once closeErr error file *os.File } // NewJSONLKCPPacketDebugLogger 创建一个线程安全的 KCP packet JSONL 日志器。 func NewJSONLKCPPacketDebugLogger(path string) (*JSONLKCPPacketDebugLogger, error) { dir := filepath.Dir(path) if err := os.MkdirAll(dir, 0o755); err != nil { return nil, fmt.Errorf("transport: create kcp packet debug log dir %s: %w", dir, err) } file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o644) if err != nil { return nil, fmt.Errorf("transport: open kcp packet debug log %s: %w", path, err) } return &JSONLKCPPacketDebugLogger{file: file}, nil } // LogKCPPacketDebugRecord 以单行 JSON 的形式追加一条 KCP packet 调试记录。 func (l *JSONLKCPPacketDebugLogger) LogKCPPacketDebugRecord(record KCPPacketDebugRecord) error { line, err := json.Marshal(record) if err != nil { return err } l.mu.Lock() defer l.mu.Unlock() if _, err := l.file.Write(append(line, '\n')); err != nil { return err } return nil } // Close 关闭底层文件;重复调用是安全的。 func (l *JSONLKCPPacketDebugLogger) Close() error { l.closeOnce.Do(func() { l.closeErr = l.file.Close() }) return l.closeErr }