-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdump.go
More file actions
83 lines (74 loc) · 1.85 KB
/
Copy pathdump.go
File metadata and controls
83 lines (74 loc) · 1.85 KB
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
80
81
82
83
package main
import (
"fmt"
"os"
"path/filepath"
"sync"
"time"
)
const defaultDumpMaxBytes = 10 << 20 // 10 MiB
func dumpPath() string { return filepath.Join(configDir(), "dump.log") }
// dumper appends chat traffic to one capped file; no rotation, stops at the cap — delete to reset.
type dumper struct {
mu sync.Mutex
f *os.File
max int64
n int64
}
// newDumper opens the dump file when enabled; returns nil (a valid no-op receiver) when off or unopenable.
func newDumper(cfg Config) *dumper {
if !cfg.Dump && os.Getenv("QP_DUMP") == "" {
return nil
}
if os.MkdirAll(configDir(), 0o700) != nil {
return nil
}
f, err := os.OpenFile(dumpPath(), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o600)
if err != nil {
return nil
}
_ = f.Chmod(0o600) // O_CREATE perm is umask-masked and skipped for an existing file; enforce it
max := int64(cfg.DumpMaxBytes)
if max <= 0 {
max = defaultDumpMaxBytes
}
d := &dumper{f: f, max: max}
if info, err := f.Stat(); err == nil {
d.n = info.Size() // pre-existing bytes count toward the cap
}
return d
}
// section writes a labeled header then the payload; both count against the cap.
func (d *dumper) section(tag string, b []byte) {
if d == nil {
return
}
d.header(tag)
_, _ = d.Write(b)
}
func (d *dumper) header(tag string) {
_, _ = d.Write([]byte(fmt.Sprintf("\n===== %s %s =====\n", tag, time.Now().Format(time.RFC3339))))
}
// Write: capped serialized append (io.Writer, for teeing); reports full write always — best-effort, never errors a tee.
func (d *dumper) Write(b []byte) (int, error) {
if d == nil {
return len(b), nil
}
d.mu.Lock()
defer d.mu.Unlock()
if room := d.max - d.n; room > 0 {
w := b
if int64(len(w)) > room {
w = w[:room]
}
nn, _ := d.f.Write(w)
d.n += int64(nn)
}
return len(b), nil
}
func (d *dumper) close() {
if d == nil {
return
}
_ = d.f.Close()
}