// Copyright 2023 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package raw import ( "encoding/binary" "fmt" "io" "internal/trace/v2/event" "internal/trace/v2/version" ) // Writer emits the wire format of a trace. // // It may not produce a byte-for-byte compatible trace from what is // produced by the runtime, because it may be missing extra padding // in the LEB128 encoding that the runtime adds but isn't necessary // when you know the data up-front. type Writer struct { w io.Writer buf []byte v version.Version specs []event.Spec } // NewWriter creates a new byte format writer. func NewWriter(w io.Writer, v version.Version) (*Writer, error) { _, err := version.WriteHeader(w, v) return &Writer{w: w, v: v, specs: v.Specs()}, err } // WriteEvent writes a single event to the trace wire format stream. func (w *Writer) WriteEvent(e Event) error { // Check version. if e.Version != w.v { return fmt.Errorf("mismatched version between writer (go 1.%d) and event (go 1.%d)", w.v, e.Version) } // Write event header byte. w.buf = append(w.buf, uint8(e.Ev)) // Write out all arguments. spec := w.specs[e.Ev] for _, arg := range e.Args[:len(spec.Args)] { w.buf = binary.AppendUvarint(w.buf, arg) } if spec.IsStack { frameArgs := e.Args[len(spec.Args):] for i := 0; i < len(frameArgs); i++ { w.buf = binary.AppendUvarint(w.buf, frameArgs[i]) } } // Write out the length of the data. if spec.HasData { w.buf = binary.AppendUvarint(w.buf, uint64(len(e.Data))) } // Write out varint events. _, err := w.w.Write(w.buf) w.buf = w.buf[:0] if err != nil { return err } // Write out data. if spec.HasData { _, err := w.w.Write(e.Data) return err } return nil }