internal/etrace/protocol.go
Rama main · réplica de lectura del repositorio original.
package etrace
import (
"bufio"
"context"
"encoding/json"
"io"
"os"
"sync"
"time"
"github.com/cockroachdb/errors"
)
// See https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
// for documentation on the Perfetto JSON trace format.
func WithTracer(ctx context.Context, w io.Writer) (context.Context, *Tracer) {
tr := &Tracer{
start: time.Now(),
bw: bufio.NewWriter(w),
}
tr.bw.WriteString("[")
ctx = context.WithValue(ctx, tracerKey, tr)
return ctx, tr
}
func WithFileTracer(ctx context.Context, dst string) (context.Context, *Tracer, error) {
f, err := os.Create(dst)
if err != nil {
return nil, nil, errors.Wrap(err, "create file tracer")
}
tr := &Tracer{
start: time.Now(),
bw: bufio.NewWriter(f),
closer: f,
}
tr.bw.WriteString("[")
ctx = context.WithValue(ctx, tracerKey, tr)
return ctx, tr, nil
}
func fromCtx(ctx context.Context) *Tracer {
tr, _ := ctx.Value(tracerKey).(*Tracer)
return tr
}
type key string
const tracerKey key = "etrace.tracer"
type Tracer struct {
start time.Time
closer io.Closer
mu sync.Mutex
bw *bufio.Writer
}
func (tr *Tracer) Close() error {
if tr == nil {
return nil
}
tr.mu.Lock()
defer tr.mu.Unlock()
err := tr.bw.Flush()
// Close the file, if any.
if tr.closer != nil {
if err2 := tr.closer.Close(); err == nil {
err = err2
}
}
return err
}
func (tr *Tracer) Emit(typ eventType, name, category string, args map[string]any, gid int64, asyncID int64) {
if tr == nil {
return
}
ts := time.Since(tr.start).Microseconds()
data, err := json.Marshal(event{
Type: typ,
Name: name,
Category: category,
Args: args,
Timestamp: ts,
ProcessID: 1, // TODO
ThreadID: gid,
AsyncID: asyncID,
})
if err != nil {
panic(err)
}
tr.mu.Lock()
defer tr.mu.Unlock()
tr.bw.Write(data)
tr.bw.WriteByte(',')
}
type eventType string
const (
beginSync eventType = "B"
endSync eventType = "E"
beginAsync eventType = "b"
endAsync eventType = "e"
)
type event struct {
// Name is the user-specified name of the traced operation.
Name string `json:"name"`
// Category is the user-specified category of the traced operation.
// There should be a small number of categories.
Category string `json:"cat"`
// Type is the type of event.
Type eventType `json:"ph"`
// Timestamp is when the event occurred.
Timestamp int64 `json:"ts"`
// ProcessID is the id of the process generating the event.
ProcessID uint64 `json:"pid"`
// ThreadID is the id of the thread generating the event.
ThreadID int64 `json:"tid"`
// Args is the set of arguments for the event.
Args map[string]any `json:"args,omitempty"`
// AsyncID is the ID for asynchronous events.
AsyncID int64 `json:"id,omitempty"`
}