goparsify/debugon.go

145 lines
3.1 KiB
Go
Raw Normal View History

2017-08-07 12:07:29 +02:00
// +build debug
package goparsify
import (
2017-08-10 13:04:14 +02:00
"bytes"
"flag"
2017-08-07 12:07:29 +02:00
"fmt"
2017-08-10 13:04:14 +02:00
"io"
"os"
2017-08-07 12:07:29 +02:00
"sort"
2017-08-10 13:04:14 +02:00
"strconv"
2017-08-07 12:07:29 +02:00
"strings"
"time"
2017-08-10 13:04:14 +02:00
"github.com/vektah/goparsify/debug"
2017-08-07 12:07:29 +02:00
)
2017-08-10 13:04:14 +02:00
var log io.Writer = nil
2017-08-09 13:18:14 +02:00
var parsers []*debugParser
2017-08-10 13:04:14 +02:00
var pendingOpenLog = ""
var activeParsers []*debugParser
var longestLocation = 0
2017-08-07 12:07:29 +02:00
2017-08-09 13:18:14 +02:00
type debugParser struct {
2017-08-10 13:04:14 +02:00
Match string
Var string
Location string
Next Parser
Time time.Duration
Calls int
}
func (dp *debugParser) Name() string {
2017-08-10 13:58:14 +02:00
if len(activeParsers) > 1 && activeParsers[len(activeParsers)-2].Var == dp.Var {
2017-08-10 13:04:14 +02:00
return dp.Match
}
return dp.Var
}
func (dp *debugParser) logf(ps *State, result *Result, format string, args ...interface{}) string {
buf := &bytes.Buffer{}
buf.WriteString(fmt.Sprintf("%"+strconv.Itoa(longestLocation)+"s | ", dp.Location))
buf.WriteString(fmt.Sprintf("%-15s", ps.Preview(15)))
buf.WriteString(" | ")
output := ""
if ps.Errored() {
output = "fail"
} else if result != nil {
output = result.Token
}
buf.WriteString(fmt.Sprintf("%-10s | ", output))
buf.WriteString(strings.Repeat(" ", len(activeParsers)-1))
buf.WriteString(fmt.Sprintf(format, args...))
buf.WriteRune('\n')
return buf.String()
}
func (dp *debugParser) logStart(ps *State) {
if log != nil {
if pendingOpenLog != "" {
fmt.Fprint(log, pendingOpenLog)
pendingOpenLog = ""
}
pendingOpenLog = dp.logf(ps, nil, dp.Name())
}
}
func (dp *debugParser) logEnd(ps *State, result *Result) {
if log != nil {
if pendingOpenLog != "" {
fmt.Fprintf(log, dp.logf(ps, result, dp.Name()))
pendingOpenLog = ""
}
}
2017-08-07 12:07:29 +02:00
}
2017-08-09 13:18:14 +02:00
func (dp *debugParser) Parse(ps *State) Result {
2017-08-10 13:04:14 +02:00
activeParsers = append(activeParsers, dp)
2017-08-07 12:07:29 +02:00
start := time.Now()
2017-08-10 13:04:14 +02:00
dp.logStart(ps)
2017-08-07 12:07:29 +02:00
ret := dp.Next(ps)
2017-08-10 13:04:14 +02:00
dp.logEnd(ps, &ret)
2017-08-07 12:07:29 +02:00
dp.Time = dp.Time + time.Since(start)
dp.Calls++
2017-08-10 13:04:14 +02:00
activeParsers = activeParsers[0 : len(activeParsers)-1]
2017-08-07 12:07:29 +02:00
return ret
}
2017-08-10 13:04:14 +02:00
func init() {
logs := flag.Bool("parselogs", false, "print detailed parsing logs")
flag.Parse()
2017-08-07 12:07:29 +02:00
2017-08-10 13:04:14 +02:00
if *logs {
EnableLogging(os.Stdout)
2017-08-07 12:07:29 +02:00
}
}
2017-08-09 13:18:14 +02:00
// NewParser should be called around the creation of every Parser.
// It does nothing normally and should incur no runtime overhead, but when building with -tags debug
2017-08-10 13:04:14 +02:00
// it will instrument every parser to collect valuable timing and debug information.
func NewParser(name string, p Parser) Parser {
description, location := debug.GetDefinition()
2017-08-07 12:07:29 +02:00
2017-08-09 13:18:14 +02:00
dp := &debugParser{
2017-08-10 13:04:14 +02:00
Match: name,
Var: description,
Location: location,
Next: p,
}
if len(dp.Location) > longestLocation {
longestLocation = len(dp.Location)
2017-08-07 12:07:29 +02:00
}
parsers = append(parsers, dp)
return dp.Parse
}
2017-08-10 13:04:14 +02:00
// EnableLogging will write logs to the given writer as the next parse happens
func EnableLogging(w io.Writer) {
log = w
}
// DisableLogging will stop writing logs
func DisableLogging() {
log = nil
}
2017-08-09 13:18:14 +02:00
// DumpDebugStats will print out the curring timings for each parser if built with -tags debug
2017-08-07 12:07:29 +02:00
func DumpDebugStats() {
sort.Slice(parsers, func(i, j int) bool {
return parsers[i].Time >= parsers[j].Time
})
fmt.Println("Parser stats:")
for _, parser := range parsers {
2017-08-10 13:04:14 +02:00
fmt.Printf("%20s\t%10s\t%10d\tcalls\t%s\n", parser.Name(), parser.Time.String(), parser.Calls, parser.Location)
2017-08-07 12:07:29 +02:00
}
}