aboutsummaryrefslogtreecommitdiff
path: root/internal/ingest/trace.go
blob: 36f785bbbf4b698ed9e5078e05a4a4298cb7d19a (plain) (blame)
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()
}