package transport import ( "encoding/json" "fmt" "os" "path/filepath" "sync" "omnisocketgo/cmd/internal/protocol" ) const ( txTimestampDebugRecordTypeSendChunk = "send_chunk" txTimestampDebugRecordTypeErrqueueEvent = "errqueue_event" ) // TXTimestampDebugRecord 是 TX errqueue 调试日志的一条 JSONL 记录。 type TXTimestampDebugRecord struct { RecordType string `json:"record_type"` NodeRole string `json:"node_role,omitempty"` NodeID string `json:"node_id,omitempty"` MessageType protocol.MessageType `json:"message_type"` MessageID uint64 `json:"message_id"` From string `json:"from"` To string `json:"to"` FileName string `json:"file_name,omitempty"` BodySize int `json:"body_size"` Phase string `json:"phase,omitempty"` SendCallIndex *int `json:"send_call_index,omitempty"` FrameOffsetStart *int `json:"frame_offset_start,omitempty"` FrameOffsetEnd *int `json:"frame_offset_end,omitempty"` BytesWritten *int `json:"bytes_written,omitempty"` ExpectedTXID *uint32 `json:"expected_tx_id,omitempty"` ReadIndex *int `json:"read_index,omitempty"` EventName string `json:"event_name,omitempty"` TSUnixNano *int64 `json:"ts_unix_nano,omitempty"` EEInfo *uint32 `json:"ee_info,omitempty"` EEData *uint32 `json:"ee_data,omitempty"` MatchedSendCallIndex *int `json:"matched_send_call_index,omitempty"` SelectedForLatency *bool `json:"selected_for_latency,omitempty"` } // TXTimestampDebugLogger 接收 TX errqueue 调试记录。 type TXTimestampDebugLogger interface { LogTXTimestampDebugRecord(record TXTimestampDebugRecord) error } // JSONLTXTimestampDebugLogger 以 JSONL 形式追加写 TX errqueue 调试日志。 type JSONLTXTimestampDebugLogger struct { mu sync.Mutex closeOnce sync.Once closeErr error file *os.File } // NewJSONLTXTimestampDebugLogger 创建一个线程安全的 TX errqueue JSONL 日志器。 func NewJSONLTXTimestampDebugLogger(path string) (*JSONLTXTimestampDebugLogger, error) { dir := filepath.Dir(path) if err := os.MkdirAll(dir, 0o755); err != nil { return nil, fmt.Errorf("transport: create tx timestamp 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 tx timestamp debug log %s: %w", path, err) } return &JSONLTXTimestampDebugLogger{file: file}, nil } // LogTXTimestampDebugRecord 以单行 JSON 的形式追加一条调试记录。 func (l *JSONLTXTimestampDebugLogger) LogTXTimestampDebugRecord(record TXTimestampDebugRecord) 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 *JSONLTXTimestampDebugLogger) Close() error { l.closeOnce.Do(func() { l.closeErr = l.file.Close() }) return l.closeErr }