1package main23import (4 "log/slog"5 "runtime/debug"6 "time"78 "src.rest/cat/012/internal/config"9 "src.rest/cat/012/internal/sheet"10 "src.rest/cat/012/internal/telemetry"11)1213// telemetryConfig is where telemetry goes: the log file, level and OTLP14// endpoint from the config (whose flags and variables win over the15// file), and the rest of OTLP's settings from the OTEL_* variables.16// Telemetry stays off when neither a log file nor an endpoint is set.17func telemetryConfig(c *config.Config) telemetry.Config {18 tc := telemetry.ConfigFromEnv()19 tc.LogPath = c.String("log-file")20 tc.OTLP.Endpoint = c.String("otlp-endpoint")21 tc.Level.UnmarshalText([]byte(c.String("log-level")))22 return tc23}2425// startTelemetry opens the log and reports every recalculation and pivot26// refresh to it, as spans nested in their workbook's trace.27func startTelemetry(c telemetry.Config) (func() error, error) {28 if info, ok := debug.ReadBuildInfo(); ok {29 c.Version = info.Main.Version30 for _, s := range info.Settings {31 if s.Key == "vcs.revision" {32 c.Version = s.Value33 }34 }35 }36 stop, err := telemetry.Setup(c)37 if err != nil || !telemetry.Enabled() {38 return stop, err39 }40 sheet.OnBegin = func(trace any, op string) {41 if t, ok := trace.(*telemetry.Trace); ok {42 t.Begin(op)43 }44 }45 sheet.OnRecalc = func(trace any, i sheet.RecalcInfo) {46 telemetry.Set("cells", int64(i.Cells))47 endSpan(trace, "recalc", i.Duration,48 slog.Bool("full", i.Full), slog.Int("evaluated", i.Evaluated), slog.Int("cells", i.Cells),49 slog.Int("volatile", i.Volatile), slog.Bool("circular", i.Circular))50 }51 sheet.OnPivot = func(trace any, i sheet.PivotInfo) {52 endSpan(trace, "pivot", i.Duration,53 slog.Int("records", i.Records), slog.Int("groups", i.Groups), slog.Int("cells", i.Cells), slog.Bool("failed", i.Failed))54 }55 sheet.OnLive = func(trace any, i sheet.LiveInfo) {56 endSpan(trace, "live", i.Duration, slog.Int("rows", i.Rows), slog.Int("cells", i.Cells), slog.Bool("reset", i.Reset))57 }58 return stop, nil59}6061// endSpan ends the span sheet.OnBegin began in the workbook's trace, or62// logs the operation as a root span of its own when the workbook has no63// trace (one read before the UI took it, say).64func endSpan(trace any, name string, d time.Duration, attrs ...slog.Attr) {65 if t, ok := trace.(*telemetry.Trace); ok && t.End(attrs...) {66 return67 }68 telemetry.Event(name, d, attrs...)69}