go-vise

Constrained Size Output Virtual Machine
Info | Log | Files | Refs | README | LICENSE

commit d370bc33fa26d4807fdf46b184fa828d19d32c8d
parent 35e397917bdb4f431812d56eac3a9f8696a22f42
Author: lash <dev@holbrook.no>
Date:   Tue, 18 Apr 2023 09:48:20 +0100

Implement context logging

Diffstat:
Mengine/engine.go | 8++++----
Mengine/loop.go | 2+-
Mlogging/logging.go | 8+++++++-
Mlogging/vanilla.go | 84+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Mvm/runner.go | 36++++++++++++++++++------------------
5 files changed, 82 insertions(+), 56 deletions(-)

diff --git a/engine/engine.go b/engine/engine.go @@ -54,7 +54,7 @@ func NewEngine(cfg Config, st *state.State, rs resource.Resource, ca cache.Memor // It loads and executes code for the start node. func(en *Engine) Init(ctx context.Context) (bool, error) { if en.initd { - Logg.Debugf("already initialized") + Logg.DebugCtxf(ctx, "already initialized") return true, nil } sym := en.root @@ -67,13 +67,13 @@ func(en *Engine) Init(ctx context.Context) (bool, error) { return false, err } b := vm.NewLine(nil, vm.MOVE, []string{sym}, nil, nil) - Logg.Debugf("start new init VM run", "code", b) + Logg.DebugCtxf(ctx, "start new init VM run", "code", b) b, err = en.vm.Run(b, ctx) if err != nil { return false, err } - Logg.Debugf("end new init VM run", "code", b) + Logg.DebugCtxf(ctx, "end new init VM run", "code", b) en.st.SetCode(b) err = en.st.SetInput(inSave) if err != nil { @@ -110,7 +110,7 @@ func (en *Engine) Exec(input []byte, ctx context.Context) (bool, error) { return false, err } - Logg.Infof("new VM execution with input", "input", string(input)) + Logg.InfoCtxf(ctx, "new VM execution with input", "input", string(input)) code, err := en.st.GetCode() if err != nil { return false, err diff --git a/engine/loop.go b/engine/loop.go @@ -30,7 +30,7 @@ func Loop(en *Engine, reader io.Reader, writer io.Writer, ctx context.Context) e for running { in, err := bufReader.ReadString('\n') if err == io.EOF { - Logg.Debugf("EOF found, that's all folks") + Logg.DebugCtxf(ctx, "EOF found, that's all folks") return nil } if err != nil { diff --git a/logging/logging.go b/logging/logging.go @@ -29,6 +29,12 @@ var ( LogWriter = os.Stderr ) + +func AsString(level int) string { + return levelStr[level] +} + + type Logger interface { Writef(w io.Writer, level int, msg string, args ...any) WriteCtxf(ctx context.Context, w io.Writer, level int, msg string, args ...any) @@ -44,5 +50,5 @@ type Logger interface { WarnCtxf(ctx context.Context, msg string, args ...any) Errorf(msg string, args ...any) ErrorCtxf(ctx context.Context, msg string, args ...any) - AsString(level int) string } + diff --git a/logging/vanilla.go b/logging/vanilla.go @@ -8,11 +8,13 @@ import ( "runtime" ) +// Vanilla is a basic single-line structured output logger for terminal output. type Vanilla struct { domain string levelFilter int } +// NewVanilla creates a new Vanilla logger. func NewVanilla() Vanilla { return Vanilla{ domain: "main", @@ -20,124 +22,116 @@ func NewVanilla() Vanilla { } } +// WithDomain sets the logging domain. It is prepended to the caller file/line information. func(v Vanilla) WithDomain(domain string) Vanilla { v.domain = domain return v } +// WithLevel overrides the globally set loglevel for the logger instance. func(v Vanilla) WithLevel(level int) Vanilla { v.levelFilter = level return v } +// Printf logs to the global writer. func(v Vanilla) Printf(level int, msg string, args ...any) { v.Writef(LogWriter, level, msg, args...) } +// compile log line from inputs and send to given writer. func(v Vanilla) writef(w io.Writer, file string, line int, level int, msg string, args ...any) { if level > v.levelFilter { return } argsStr := argsToString(args) if len(msg) > 0 { - fmt.Fprintf(w, "[%s] %s:%s:%v %s\t%s\n", v.AsString(level), v.domain, file, line, msg, argsStr) + fmt.Fprintf(w, "[%s] %s:%s:%v %s\t%s\n", AsString(level), v.domain, file, line, msg, argsStr) } else { - fmt.Fprintf(w, "[%s] %s:%s:%v %s\n", v.AsString(level), v.domain, file, line, argsStr) + fmt.Fprintf(w, "[%s] %s:%s:%v %s\n", AsString(level), v.domain, file, line, argsStr) } } +// Writef logs to the given writer. func(v Vanilla) Writef(w io.Writer, level int, msg string, args ...any) { file, line := getCaller(2) v.writef(w, file, line, level, msg, args) } -func argsToString(args []any) string { - var s string - c := len(args) - var i int - for i = 0; i < c; i += 2 { - if len(s) > 0 { - s += ", " - } - - if i + 1 < c { - var argByte []byte - var ok bool - argByte, ok = args[i+1].([]byte) - if ok { - s += fmt.Sprintf("%s=%x", args[i], argByte) - } else { - s += fmt.Sprintf("%s=%v", args[i], args[i+1]) - } - } else { - s += fmt.Sprintf("%s=??", args[i]) - } - } - return s -} - +// WriteCtxf logs with context to the given writer. func(v Vanilla) WriteCtxf(ctx context.Context, w io.Writer, level int, msg string, args ...any) { - v.Writef(w, level, msg, args...) + file, line := getCaller(2) + v.writef(w, file, line, level, msg, args...) } +// get caller information and pass on to writef func(v Vanilla) printf(level int, msg string, args ...any) { file, line := getCaller(3) v.writef(LogWriter, file, line, level, msg, args...) } +// get caller information and pass on to writef func(v Vanilla) printCtxf(ctx context.Context, level int, msg string, args ...any) { file, line := getCaller(3) v.writef(LogWriter, file, line, level, msg, args...) } +// PrintCtxf logs with context to the global writer. func(v Vanilla) PrintCtxf(ctx context.Context, level int, msg string, args ...any) { v.printf(level, msg, args...) } -func(v Vanilla) AsString(level int) string { - return levelStr[level] -} - +// Tracef logs a line with level TRACE to the global writer. func(v Vanilla) Tracef(msg string, args ...any) { v.printf(LVL_TRACE, msg, args...) } +// Tracef logs a line with level DEBUG to the global writer. func(v Vanilla) Debugf(msg string, args ...any) { v.printf(LVL_DEBUG, msg, args...) } +// Tracef logs a line with level INFO to the global writer. func(v Vanilla) Infof(msg string, args ...any) { v.printf(LVL_INFO, msg, args...) } +// Tracef logs a line with level WARN to the global writer. func(v Vanilla) Warnf(msg string, args ...any) { v.printf(LVL_WARN, msg, args...) } +// Tracef logs a line with level ERROR to the global writer. func(v Vanilla) Errorf(msg string, args ...any) { v.printf(LVL_ERROR, msg, args...) } +// Tracef logs a line with context with level TRACE to the global writer. func(v Vanilla) TraceCtxf(ctx context.Context, msg string, args ...any) { v.printCtxf(ctx, LVL_TRACE, msg, args...) } +// Tracef logs a line with context with level DEBUG to the global writer. func(v Vanilla) DebugCtxf(ctx context.Context, msg string, args ...any) { v.printCtxf(ctx, LVL_DEBUG, msg, args...) } +// Tracef logs a line with context with level INFO to the global writer. func(v Vanilla) InfoCtxf(ctx context.Context, msg string, args ...any) { v.printCtxf(ctx, LVL_INFO, msg, args...) } +// Tracef logs a line with context with level WARN to the global writer. func(v Vanilla) WarnCtxf(ctx context.Context, msg string, args ...any) { v.printCtxf(ctx, LVL_WARN, msg, args...) } +// Tracef logs a line with context with level ERROR to the global writer. func(v Vanilla) ErrorCtxf(ctx context.Context, msg string, args ...any) { v.printCtxf(ctx, LVL_ERROR, msg, args...) } +// return file basename and line for caller information. func getCaller(depth int) (string, int) { var file string var line int @@ -145,3 +139,29 @@ func getCaller(depth int) (string, int) { baseFile := path.Base(file) return baseFile, line } + +// string representation of the given structured log args. +func argsToString(args []any) string { + var s string + c := len(args) + var i int + for i = 0; i < c; i += 2 { + if len(s) > 0 { + s += ", " + } + + if i + 1 < c { + var argByte []byte + var ok bool + argByte, ok = args[i+1].([]byte) + if ok { + s += fmt.Sprintf("%s=%x", args[i], argByte) + } else { + s += fmt.Sprintf("%s=%v", args[i], args[i+1]) + } + } else { + s += fmt.Sprintf("%s=??", args[i]) + } + } + return s +} diff --git a/vm/runner.go b/vm/runner.go @@ -58,7 +58,7 @@ func(vm *Vm) Run(b []byte, ctx context.Context) ([]byte, error) { } if r { //log.Printf("terminate set! bailing!") - Logg.Infof("terminate set! bailing") + Logg.InfoCtxf(ctx, "terminate set! bailing") return []byte{}, nil } //vm.st.ResetBaseFlags() @@ -87,8 +87,8 @@ func(vm *Vm) Run(b []byte, ctx context.Context) ([]byte, error) { return b, err } b = bb - Logg.Debugf("execute code", "opcode", op, "op", OpcodeString[op], "code", b) - Logg.Debugf("", "state", vm.st) + Logg.DebugCtxf(ctx, "execute code", "opcode", op, "op", OpcodeString[op], "code", b) + Logg.DebugCtxf(ctx, "", "state", vm.st) switch op { case CATCH: b, err = vm.RunCatch(b, ctx) @@ -150,7 +150,7 @@ func(vm *Vm) RunDeadCheck(b []byte, ctx context.Context) ([]byte, error) { panic(err) } if r { - Logg.Debugf("Not processing input. Setting terminate") + Logg.DebugCtxf(ctx, "Not processing input. Setting terminate") _, err := vm.st.SetFlag(state.FLAG_TERMINATE) if err != nil { panic(err) @@ -162,12 +162,12 @@ func(vm *Vm) RunDeadCheck(b []byte, ctx context.Context) ([]byte, error) { panic(err) } if r { - Logg.Tracef("Terminate found!!") + Logg.TraceCtxf(ctx, "Terminate found!!") return b, nil } - Logg.Tracef("no code remaining but not terminating") + Logg.TraceCtxf(ctx, "no code remaining but not terminating") location, _ := vm.st.Where() if location == "" { return b, fmt.Errorf("dead runner with no current location") @@ -196,7 +196,7 @@ func(vm *Vm) RunCatch(b []byte, ctx context.Context) ([]byte, error) { if perr != nil { panic(perr) } - Logg.Tracef("terminate set") + Logg.TraceCtxf(ctx, "terminate set") return b, err } if r { @@ -207,7 +207,7 @@ func(vm *Vm) RunCatch(b []byte, ctx context.Context) ([]byte, error) { if err != nil { return b, err } - Logg.Infof("catch!", "flag", sig, "sym", sym, "target", actualSym) + Logg.InfoCtxf(ctx, "catch!", "flag", sig, "sym", sym, "target", actualSym) sym = actualSym bh, err := vm.rs.GetCode(sym) if err != nil { @@ -229,7 +229,7 @@ func(vm *Vm) RunCroak(b []byte, ctx context.Context) ([]byte, error) { return b, err } if r { - Logg.Infof("croak at flag %v, purging and moving to top", "signal", sig) + Logg.InfoCtxf(ctx, "croak at flag %v, purging and moving to top", "signal", sig) vm.Reset() vm.pg.Reset() vm.ca.Reset() @@ -291,7 +291,7 @@ func(vm *Vm) RunMove(b []byte, ctx context.Context) ([]byte, error) { if err != nil { return b, err } - Logg.Debugf("loaded code", "sym", sym, "code", code) + Logg.DebugCtxf(ctx, "loaded code", "sym", sym, "code", code) b = append(b, code...) vm.Reset() return b, nil @@ -315,7 +315,7 @@ func(vm *Vm) RunInCmp(b []byte, ctx context.Context) ([]byte, error) { } if have { if reading { - Logg.Debugf("ignoring input - already have match", "input", sym) + Logg.DebugCtxf(ctx, "ignoring input - already have match", "input", sym) return b, nil } } else { @@ -328,15 +328,15 @@ func(vm *Vm) RunInCmp(b []byte, ctx context.Context) ([]byte, error) { if err != nil { return b, err } - Logg.Tracef("testing sym", "sym", sym, "input", input) + Logg.TraceCtxf(ctx, "testing sym", "sym", sym, "input", input) if !have && sym == "*" { - Logg.Debugf("input wildcard match", "input", input, "target", target) + Logg.DebugCtxf(ctx, "input wildcard match", "input", input, "target", target) } else { if sym != string(input) { return b, nil } - Logg.Infof("input match", "input", input, "target", target) + Logg.InfoCtxf(ctx, "input match", "input", input, "target", target) } _, err = vm.st.SetFlag(state.FLAG_INMATCH) if err != nil { @@ -368,7 +368,7 @@ func(vm *Vm) RunInCmp(b []byte, ctx context.Context) ([]byte, error) { if err != nil { return b, err } - Logg.Debugf("loaded additional code", "target", target, "code", code) + Logg.DebugCtxf(ctx, "loaded additional code", "target", target, "code", code) b = append(b, code...) return b, err } @@ -380,7 +380,7 @@ func(vm *Vm) RunHalt(b []byte, ctx context.Context) ([]byte, error) { if err != nil { return b, err } - Logg.Debugf("found HALT, stopping") + Logg.DebugCtxf(ctx, "found HALT, stopping") _, err = vm.st.SetFlag(state.FLAG_WAIT) if err != nil { @@ -391,7 +391,7 @@ func(vm *Vm) RunHalt(b []byte, ctx context.Context) ([]byte, error) { // RunMSize executes the MSIZE opcode func(vm *Vm) RunMSize(b []byte, ctx context.Context) ([]byte, error) { - Logg.Warnf("MSIZE not yet implemented") + Logg.WarnCtxf(ctx, "MSIZE not yet implemented") _, _, b, err := ParseMSize(b) return b, err } @@ -472,7 +472,7 @@ func(vm *Vm) refresh(key string, rs resource.Resource, ctx context.Context) (str input, _ := vm.st.GetInput() r, err := fn(key, input, ctx) if err != nil { - Logg.Tracef("loadfail", "err", err) + Logg.TraceCtxf(ctx, "loadfail", "err", err) var perr error _, perr = vm.st.SetFlag(state.FLAG_LOADFAIL) if perr != nil {