package trace import ( "encoding/json" "fmt" "io" "sync" ) // Writer persists a completed span. Implementations must be safe for concurrent // use, as WriteSpan may be called from several goroutines. A Writer such as // *JSONRecorder provides structured local logging for the M9 panel. type Writer interface { // WriteSpan persists a single completed span and returns any encoding or // write error. WriteSpan(rec SpanRecord) error } // JSONRecorder writes each completed span as one line of JSON (JSONL) to an // underlying io.Writer. It is safe for concurrent use. type JSONRecorder struct { mu sync.Mutex enc *json.Encoder } // NewJSONRecorder builds a JSONRecorder that appends one JSON object per span to // out. func NewJSONRecorder(out io.Writer) *JSONRecorder { return &JSONRecorder{enc: json.NewEncoder(out)} } // WriteSpan encodes rec as JSON followed by a newline. Concurrent calls are // serialized so a single span object is never interleaved with another. func (r *JSONRecorder) WriteSpan(rec SpanRecord) error { r.mu.Lock() defer r.mu.Unlock() if err := r.enc.Encode(rec); err != nil { return fmt.Errorf("trace: encode span %q: %w", rec.ID, err) } return nil }