Documentation
¶
Overview ¶
Package tracer records finished tool invocations as JSON Lines.
Tracer is the seam, shaped like a logger: Log, Warn, Error and Fatal each record an Entry at their level. FileTracer appends a record to a log file and echoes it to a writer, and Nop records nothing. A tracer never fails the caller: a record that cannot be written is reported on the warning writer only.
Index ¶
Examples ¶
Constants ¶
const ( LevelInfo = "info" LevelWarn = "warn" LevelError = "error" LevelFatal = "fatal" )
Level of a record.
const ( StdinTerminal = "terminal" StdinPipe = "pipe" )
Values for Config.Stdin.
const FileName = ".gotools_trace.log"
FileName is the conventional trace log, in the project root.
Variables ¶
This section is empty.
Functions ¶
func ReproCommand ¶
ReproCommand is the copy-pasteable invocation for a trace record.
func ShellQuote ¶
ShellQuote renders arg so a shell reads it back as one word.
Types ¶
type Config ¶
type Config struct {
Path string // the log file; records are appended to it
Echo io.Writer // each record line is also written here; nil for none
Warn io.Writer // where a failure to trace is reported; nil for none
Program string // the command name used in the repro command
Stdin string // StdinTerminal or StdinPipe
Env Env
Now func() time.Time // the clock; time.Now when nil
}
Config is what a FileTracer stamps on every record.
type Entry ¶
type Entry struct {
Tool string
Binary string // the binary a tool resolved to
Args []string // the arguments the tool was run with
Code *int // the tool's exit code; set for a finished invocation
Message string // what happened, for warnings, errors and fatal stops
}
Entry is what a caller reports. The tracer adds the timestamp and the configuration the process runs under.
type Env ¶
type Env struct {
Strategy string `json:"GOTOOLS_STRATEGY"`
Dir string `json:"GOTOOLS_DIR"`
GoVersion string `json:"GOTOOLS_GO_VERSION"`
ModulePrefix string `json:"GOTOOLS_MODULE_PREFIX"`
Verbose string `json:"GOTOOLS_VERBOSE"`
Trace string `json:"GOTOOLS_TRACE"`
}
Env is the resolved configuration a record was produced under.
type FileTracer ¶
type FileTracer struct {
// contains filtered or unexported fields
}
FileTracer is the Tracer that appends JSON Lines to a file.
Example ¶
A FileTracer stamps every record with the configuration it runs under and echoes the line it appends.
package main
import (
"os"
"path/filepath"
"time"
"github.com/piusalfred/gotools/internal/tracer"
)
func main() {
dir, _ := os.MkdirTemp("", "tracer-example")
defer os.RemoveAll(dir)
tr := tracer.NewFile(tracer.Config{
Path: filepath.Join(dir, tracer.FileName),
Echo: os.Stdout,
Program: "gotools",
Stdin: tracer.StdinPipe,
Env: tracer.Env{Strategy: "split", Dir: "tools"},
Now: func() time.Time { return time.Date(2026, 1, 2, 3, 4, 5, 0, time.UTC) },
})
tr.Log(tracer.Entry{Tool: "fmt", Binary: "gofumpt", Args: []string{"-w", "."}, Code: new(0)})
}
Output: {"ts":"2026-01-02T03:04:05Z","level":"info","tool":"fmt","binary":"gofumpt","cmd":"gotools exec fmt -w .","strategy":"split","stdin":"pipe","exit_code":0,"args":["-w","."],"env":{"GOTOOLS_STRATEGY":"split","GOTOOLS_DIR":"tools","GOTOOLS_GO_VERSION":"","GOTOOLS_MODULE_PREFIX":"","GOTOOLS_VERBOSE":"","GOTOOLS_TRACE":""}}
func NewFile ¶
func NewFile(cfg Config) *FileTracer
NewFile returns a FileTracer for cfg. It touches nothing until a record is written.
type Record ¶
type Record struct {
TS string `json:"ts"`
Level string `json:"level"`
Tool string `json:"tool"`
Binary string `json:"binary,omitzero"`
Cmd string `json:"cmd,omitzero"`
Error string `json:"error,omitzero"` // Entry.Message
Strategy string `json:"strategy"`
Stdin string `json:"stdin"`
ExitCode *int `json:"exit_code,omitzero"`
Args []string `json:"args,omitzero"`
Env Env `json:"env"`
}
Record is one line of the trace log. It is built from fields, never by string assembly, so every value is escaped by the encoder.
type Tracer ¶
Tracer records what a command did, one level per method like a logger. Fatal records that gotools stopped; it does not exit.
Example ¶
Callers hold the interface and swap the implementation.
package main
import (
"fmt"
"os"
"github.com/piusalfred/gotools/internal/tracer"
)
func main() {
var tr tracer.Tracer = tracer.Nop{}
if os.Getenv("GOTOOLS_EXAMPLE_TRACE") != "" {
tr = tracer.NewFile(tracer.Config{Path: tracer.FileName, Echo: os.Stderr})
}
tr.Log(tracer.Entry{Tool: "fmt", Binary: "gofumpt", Args: []string{"-w", "."}, Code: new(0)})
fmt.Println("done")
}
Output: done