cat / 012
clone

a spreadsheet for the terminal: lotus 1-2-3 looks, google sheets keys and formulas, one go binary

cat/module-path
012 / internal / telemetry / telemetry_test.go
telemetry_test.go 4.1K
1package telemetry23import (4 "bytes"5 "encoding/json"6 "errors"7 "io"8 "log/slog"9 "strings"10 "testing"11 "time"12)1314// record turns telemetry on into a buffer for the test.15func record(t testing.TB, level slog.Level) *bytes.Buffer {16 var buf bytes.Buffer17 start(&buf, nil, Config{Level: level})18 t.Cleanup(func() { Close() })19 return &buf20}2122func events(t *testing.T, buf *bytes.Buffer) []map[string]any {23 t.Helper()24 var out []map[string]any25 for _, line := range strings.Split(strings.TrimSpace(buf.String()), "\n") {26 if line == "" {27 continue28 }29 var ev map[string]any30 if err := json.Unmarshal([]byte(line), &ev); err != nil {31 t.Fatalf("%q: %v", line, err)32 }33 out = append(out, ev)34 }35 return out36}3738func TestOffRecordsNothing(t *testing.T) {39 if Enabled() {40 t.Fatal("on without Setup")41 }42 s := Start("recalc")43 s.End(slog.Int("cells", 1))44 Event("x", time.Second)45 Frame(time.Millisecond, time.Millisecond)46 Set("cells", 3)47 if s.name != "" || s.n != 0 {48 t.Errorf("span while off = %+v", s)49 }50 stop, err := Setup(Config{})51 if err != nil || Enabled() {52 t.Fatalf("Setup without a path: %v, enabled %v", err, Enabled())53 }54 stop()55}5657func TestSpansAreJSONEvents(t *testing.T) {58 buf := record(t, slog.LevelInfo)59 s := Start("import", slog.String("format", "CSV"))60 s.End(slog.Int("rows", 42))61 Start("open").Fail(errors.New("bad file"))62 Debug("frame", time.Millisecond) // below the level63 evs := events(t, buf)64 if len(evs) != 2 {65 t.Fatalf("%d events: %s", len(evs), buf)66 }67 imp := evs[0]68 if imp["event"] != "import" || imp["format"] != "CSV" || imp["rows"] != 42.0 || imp["service"] != "012" || imp["level"] != "INFO" {69 t.Errorf("import event %v", imp)70 }71 if _, ok := imp["dur_ms"].(float64); !ok {72 t.Errorf("no duration in %v", imp)73 }74 if evs[1]["level"] != "WARN" || evs[1]["error"] != "bad file" {75 t.Errorf("failure event %v", evs[1])76 }77}7879func TestFramesAreSummarized(t *testing.T) {80 buf := record(t, slog.LevelInfo)81 Set("cells", 1234)82 for i := range 10 {83 Frame(time.Duration(i+1)*time.Millisecond, 0)84 }85 Frame(time.Millisecond, 20*time.Millisecond)86 if buf.Len() > 0 {87 t.Fatalf("summary before the window closed: %s", buf)88 }89 frames.mu.Lock()90 frames.since = time.Now().Add(-2 * window)91 frames.mu.Unlock()92 Frame(time.Millisecond, 0)93 evs := events(t, buf)94 if len(evs) != 1 {95 t.Fatalf("%d events: %s", len(evs), buf)96 }97 ev := evs[0]98 want := map[string]float64{"frames": 12, "render_max_ms": 10, "keys": 1, "key_p95_ms": 20, "cells": 1234}99 for k, v := range want {100 if ev[k] != v {101 t.Errorf("%s = %v, want %v", k, ev[k], v)102 }103 }104 if h, _ := ev["heap_bytes"].(float64); h <= 0 {105 t.Errorf("heap_bytes = %v", ev["heap_bytes"])106 }107}108109func TestPercentile(t *testing.T) {110 ds := []time.Duration{5, 1, 4, 2, 3}111 tests := []struct {112 p int113 want time.Duration114 }{{0, 1}, {50, 3}, {95, 5}, {100, 5}}115 for _, tt := range tests {116 if got := percentile(ds, tt.p); got != tt.want {117 t.Errorf("p%d = %v, want %v", tt.p, got, tt.want)118 }119 }120 if percentile(nil, 50) != 0 {121 t.Error("empty percentile")122 }123}124125// Call sites must not allocate while telemetry is off, OTLP compiled in126// or not.127func TestOffAllocatesNothing(t *testing.T) {128 n := testing.AllocsPerRun(100, func() {129 s := Start("recalc", slog.Int("n", 1))130 s.End(slog.Int("cells", 2))131 Event("recalc", time.Millisecond, slog.Int("cells", 2))132 Frame(time.Millisecond, 0)133 })134 if n != 0 {135 t.Errorf("%v allocations per call while off", n)136 }137}138139// The cost at a call site while telemetry is off: what every keystroke140// pays for having it compiled in.141func BenchmarkSpanOff(b *testing.B) {142 for b.Loop() {143 s := Start("recalc", slog.Int("n", 1))144 s.End(slog.Int("cells", 2))145 }146}147148func BenchmarkFrameOff(b *testing.B) {149 for b.Loop() {150 Frame(time.Millisecond, 0)151 }152}153154// The cost while on, writing JSON (to io.Discard).155func BenchmarkSpanOn(b *testing.B) {156 start(io.Discard, nil, Config{})157 defer Close()158 for b.Loop() {159 s := Start("recalc", slog.Int("n", 1))160 s.End(slog.Int("cells", 2))161 }162}163164func BenchmarkFrameOn(b *testing.B) {165 start(io.Discard, nil, Config{})166 defer Close()167 for b.Loop() {168 Frame(time.Millisecond, 0)169 }170}