commit d370bc33fa26d4807fdf46b184fa828d19d32c8d
parent 35e397917bdb4f431812d56eac3a9f8696a22f42
Author: lash <dev@holbrook.no>
Date: Tue, 18 Apr 2023 09:48:20 +0100
Implement context logging
Diffstat:
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 {