src/cmd/trace/v2/gen.go | 35 +++++++++++++++++++++++++++++++++++ src/cmd/trace/v2/goroutinegen.go | 5 ++++- src/cmd/trace/v2/procgen.go | 5 ++++- src/cmd/trace/v2/threadgen.go | 5 ++++- diff --git a/src/cmd/trace/v2/gen.go b/src/cmd/trace/v2/gen.go index ad1599db92ddae098db7577822ca3bc298be2aa2..f6a4bb643b2c1aa7a744c091e6b064a65579d1ee 100644 --- a/src/cmd/trace/v2/gen.go +++ b/src/cmd/trace/v2/gen.go @@ -31,6 +31,9 @@ // Proc parts. ProcRange(ctx *traceContext, ev *tracev2.Event) ProcTransition(ctx *traceContext, ev *tracev2.Event) + // User annotations. + Log(ctx *traceContext, ev *tracev2.Event) + // Finish indicates the end of the trace and finalizes generation. Finish(ctx *traceContext) } @@ -69,6 +72,8 @@ g.ProcTransition(ctx, ev) case tracev2.ResourceGoroutine: g.GoroutineTransition(ctx, ev) } + case tracev2.EventLog: + g.Log(ctx, ev) } } for i, task := range opts.tasks { @@ -357,3 +362,33 @@ startStack tracev2.Stack endStack tracev2.Stack arg any } + +type logEventGenerator[R resource] struct { + // getResource is a function to extract a resource ID from a Log event. + getResource func(*tracev2.Event) R +} + +// Log implements a log event handler. It expects ev to be one such event. +func (g *logEventGenerator[R]) Log(ctx *traceContext, ev *tracev2.Event) { + id := g.getResource(ev) + if id == R(noResource) { + // We have nowhere to put this in the UI. + return + } + + // Construct the name to present. + log := ev.Log() + name := log.Message + if log.Category != "" { + name = "[" + log.Category + "] " + name + } + + // Emit an instant event. + ctx.Instant(traceviewer.InstantEvent{ + Name: name, + Ts: ctx.elapsed(ev.Time()), + Category: "user event", + Resource: uint64(id), + Stack: ctx.Stack(viewerFrames(ev.Stack())), + }) +} diff --git a/src/cmd/trace/v2/goroutinegen.go b/src/cmd/trace/v2/goroutinegen.go index eb1aea9bfa5ec62eeeea662b55ad2ae91f64c622..c76bd8487ae64f3fbde0e87446fcf93ca2cfee59 100644 --- a/src/cmd/trace/v2/goroutinegen.go +++ b/src/cmd/trace/v2/goroutinegen.go @@ -14,6 +14,7 @@ type goroutineGenerator struct { globalRangeGenerator globalMetricGenerator stackSampleGenerator[tracev2.GoID] + logEventGenerator[tracev2.GoID] gStates map[tracev2.GoID]*gState[tracev2.GoID] focus tracev2.GoID @@ -22,9 +23,11 @@ } func newGoroutineGenerator(ctx *traceContext, focus tracev2.GoID, filter map[tracev2.GoID]struct{}) *goroutineGenerator { gg := new(goroutineGenerator) - gg.stackSampleGenerator.getResource = func(ev *tracev2.Event) tracev2.GoID { + rg := func(ev *tracev2.Event) tracev2.GoID { return ev.Goroutine() } + gg.stackSampleGenerator.getResource = rg + gg.logEventGenerator.getResource = rg gg.gStates = make(map[tracev2.GoID]*gState[tracev2.GoID]) gg.focus = focus gg.filter = filter diff --git a/src/cmd/trace/v2/procgen.go b/src/cmd/trace/v2/procgen.go index 30ed568dadd0f9e3a694dd29fbe73c39b75e31d7..41e379527f1eaa8cc688f9c6af9e8550797bd6aa 100644 --- a/src/cmd/trace/v2/procgen.go +++ b/src/cmd/trace/v2/procgen.go @@ -18,6 +18,7 @@ globalRangeGenerator globalMetricGenerator procRangeGenerator stackSampleGenerator[tracev2.ProcID] + logEventGenerator[tracev2.ProcID] gStates map[tracev2.GoID]*gState[tracev2.ProcID] inSyscall map[tracev2.ProcID]*gState[tracev2.ProcID] @@ -26,9 +27,11 @@ } func newProcGenerator() *procGenerator { pg := new(procGenerator) - pg.stackSampleGenerator.getResource = func(ev *tracev2.Event) tracev2.ProcID { + rg := func(ev *tracev2.Event) tracev2.ProcID { return ev.Proc() } + pg.stackSampleGenerator.getResource = rg + pg.logEventGenerator.getResource = rg pg.gStates = make(map[tracev2.GoID]*gState[tracev2.ProcID]) pg.inSyscall = make(map[tracev2.ProcID]*gState[tracev2.ProcID]) return pg diff --git a/src/cmd/trace/v2/threadgen.go b/src/cmd/trace/v2/threadgen.go index c2d20719266f3667d9798a9c4d441bc93669d0b2..e1cae2b2cf93bf9d447b760a7dc17cdb333d07d5 100644 --- a/src/cmd/trace/v2/threadgen.go +++ b/src/cmd/trace/v2/threadgen.go @@ -17,6 +17,7 @@ type threadGenerator struct { globalRangeGenerator globalMetricGenerator stackSampleGenerator[tracev2.ThreadID] + logEventGenerator[tracev2.ThreadID] gStates map[tracev2.GoID]*gState[tracev2.ThreadID] threads map[tracev2.ThreadID]struct{} @@ -24,9 +25,11 @@ } func newThreadGenerator() *threadGenerator { tg := new(threadGenerator) - tg.stackSampleGenerator.getResource = func(ev *tracev2.Event) tracev2.ThreadID { + rg := func(ev *tracev2.Event) tracev2.ThreadID { return ev.Thread() } + tg.stackSampleGenerator.getResource = rg + tg.logEventGenerator.getResource = rg tg.gStates = make(map[tracev2.GoID]*gState[tracev2.ThreadID]) tg.threads = make(map[tracev2.ThreadID]struct{}) return tg