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)
}
case tracev2.ResourceGoroutine:
g.GoroutineTransition(ctx, ev)
}
+ case tracev2.EventLog:
+ g.Log(ctx, ev)
}
}
for i, task := range opts.tasks {
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())),
+ })
+}
globalRangeGenerator
globalMetricGenerator
stackSampleGenerator[tracev2.GoID]
+ logEventGenerator[tracev2.GoID]
gStates map[tracev2.GoID]*gState[tracev2.GoID]
focus tracev2.GoID
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
globalMetricGenerator
procRangeGenerator
stackSampleGenerator[tracev2.ProcID]
+ logEventGenerator[tracev2.ProcID]
gStates map[tracev2.GoID]*gState[tracev2.ProcID]
inSyscall map[tracev2.ProcID]*gState[tracev2.ProcID]
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
globalRangeGenerator
globalMetricGenerator
stackSampleGenerator[tracev2.ThreadID]
+ logEventGenerator[tracev2.ThreadID]
gStates map[tracev2.GoID]*gState[tracev2.ThreadID]
threads map[tracev2.ThreadID]struct{}
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