in internal/git/trace2/parser.go [115:209]
func (p *parser) parseEvent(event *jsonEvent) error {
if _, ok := ignoredEvents[event.Name]; ok {
return nil
}
if p.root != nil && p.currentNode == nil {
// The situation where there are more leaving events than starting ones. That makes
// the currentNode exits the root node of the tree while moving upward. For example:
// [start, region_start, region_start, region_leaving, region_leaving, region_leaving]
return fmt.Errorf("unmatched leaving event")
}
var trace *Trace
eventTime, err := p.parseEventTime(p.currentNode, event)
if err != nil {
return fmt.Errorf("parsing event time: %w", err)
}
if p.root == nil {
trace = &Trace{Thread: event.Thread, StartTime: eventTime, Name: "root"}
p.root = trace
p.currentNode = p.root
}
// Leaving events, don't create trace
switch event.Name {
case "atexit":
p.currentNode.FinishTime = eventTime
p.currentNode.SetMetadata("code", fmt.Sprintf("%d", event.Code))
return nil
case "child_exit":
p.currentNode.FinishTime = eventTime
p.currentNode.SetMetadata("code", fmt.Sprintf("%d", event.Code))
p.currentNode = p.currentNode.Parent
return nil
case "region_leave":
p.currentNode.FinishTime = eventTime
p.currentNode = p.currentNode.Parent
return nil
}
trace = &Trace{
ChildID: p.currentNode.ChildID,
Thread: event.Thread,
StartTime: eventTime,
FinishTime: eventTime,
Parent: p.currentNode,
Depth: p.currentNode.Depth + 1,
}
if event.Msg != "" {
trace.SetMetadata("msg", event.Msg)
}
p.currentNode.Children = append(p.currentNode.Children, trace)
switch event.Name {
case "version":
trace.setName([]string{event.Name, event.Category, event.Label})
trace.SetMetadata("exe", event.Exe)
trace.SetMetadata("evt", event.Evt)
case "def_repo":
trace.setName([]string{event.Name, event.Category, event.Label})
trace.SetMetadata("worktree", event.Worktree)
case "start":
trace.setName([]string{event.Name, event.Category, event.Label})
trace.SetMetadata("argv", strings.Join(event.Argv, " "))
case "child_start":
trace.setName([]string{event.Name, event.Category, event.Label})
trace.SetMetadata("argv", strings.Join(event.Argv, " "))
trace.ChildID = fmt.Sprintf("%d", event.ChildID)
p.currentNode = trace
case "region_enter":
trace.setName([]string{event.Category, event.Label})
p.currentNode = trace
case "data":
trace.setName([]string{event.Name, event.Category, event.Label, event.DataKey})
if event.DataValue != nil {
var data string
// When the event name is "data", we can unmarshal the data. This allows
// easy data access later
err := json.Unmarshal(*event.DataValue, &data)
if err != nil {
return fmt.Errorf("mismatched data value: %w", err)
}
trace.SetMetadata("data", data)
}
case "data_json":
trace.setName([]string{event.Name, event.Category, event.Label, event.DataKey})
if event.DataValue != nil {
trace.SetMetadata("data", string(*event.DataValue))
}
default:
trace.setName([]string{event.Name, event.Category, event.Label})
}
return nil
}