1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
package ingest
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"sync"
"time"
)
type replayTraceEvent struct {
Timestamp string `json:"timestamp"`
Kind string `json:"kind"`
RequestURL string `json:"request_url,omitempty"`
After uint64 `json:"after,omitempty"`
Count uint64 `json:"count,omitempty"`
Attempt int `json:"attempt,omitempty"`
StatusCode int `json:"status_code,omitempty"`
Retryable bool `json:"retryable,omitempty"`
RetryAfterMS int64 `json:"retry_after_ms,omitempty"`
ParsedLines int `json:"parsed_lines,omitempty"`
ParsedRecords int `json:"parsed_records,omitempty"`
SkippedLines int `json:"skipped_lines,omitempty"`
TruncatedTail bool `json:"truncated_tail,omitempty"`
FirstCreatedAt string `json:"first_created_at,omitempty"`
LastCreatedAt string `json:"last_created_at,omitempty"`
Sequence uint64 `json:"sequence,omitempty"`
Reason string `json:"reason,omitempty"`
Message string `json:"message,omitempty"`
DID string `json:"did,omitempty"`
Prev string `json:"prev,omitempty"`
Tip string `json:"tip,omitempty"`
CID string `json:"cid,omitempty"`
CreatedAt string `json:"created_at,omitempty"`
Error string `json:"error,omitempty"`
Details any `json:"details,omitempty"`
}
type replayTracer struct {
mu sync.Mutex
f *os.File
enc *json.Encoder
}
func openReplayTracer(dataDir string) (*replayTracer, error) {
path := filepath.Join(dataDir, "trace.jsonl")
file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o644)
if err != nil {
return nil, fmt.Errorf("open replay trace file: %w", err)
}
return &replayTracer{
f: file,
enc: json.NewEncoder(file),
}, nil
}
func (t *replayTracer) Write(ev replayTraceEvent) {
if t == nil {
return
}
t.mu.Lock()
defer t.mu.Unlock()
ev.Timestamp = time.Now().UTC().Format(time.RFC3339Nano)
_ = t.enc.Encode(ev)
}
func (t *replayTracer) Close() error {
if t == nil || t.f == nil {
return nil
}
return t.f.Close()
}
|