init
This commit is contained in:
111
bbs-go/server/cmd/test/main.go
Normal file
111
bbs-go/server/cmd/test/main.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func main() {
|
||||
handler := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{
|
||||
ReplaceAttr: replaceAttr,
|
||||
AddSource: true,
|
||||
})
|
||||
|
||||
slog.SetDefault(slog.New(handler))
|
||||
|
||||
if err := f(); err != nil {
|
||||
slog.Info("something went wrong", slog.Any("err", err))
|
||||
}
|
||||
}
|
||||
|
||||
func f() error {
|
||||
return g()
|
||||
}
|
||||
|
||||
func g() error {
|
||||
return errors.New("test error")
|
||||
}
|
||||
|
||||
func replaceAttr(groups []string, a slog.Attr) slog.Attr {
|
||||
switch a.Value.Kind() {
|
||||
// other cases
|
||||
|
||||
case slog.KindAny:
|
||||
switch v := a.Value.Any().(type) {
|
||||
case error:
|
||||
a.Value = fmtErr(v)
|
||||
}
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
// fmtErr returns a slog.GroupValue with keys "msg" and "trace". If the error
|
||||
// does not implement interface { StackTrace() errors.StackTrace }, the "trace"
|
||||
// key is omitted.
|
||||
func fmtErr(err error) slog.Value {
|
||||
var groupValues []slog.Attr
|
||||
|
||||
groupValues = append(groupValues, slog.String("msg", err.Error()))
|
||||
|
||||
type StackTracer interface {
|
||||
StackTrace() errors.StackTrace
|
||||
}
|
||||
|
||||
// Find the trace to the location of the first errors.New,
|
||||
// errors.Wrap, or errors.WithStack call.
|
||||
var st StackTracer
|
||||
for err := err; err != nil; err = errors.Unwrap(err) {
|
||||
if x, ok := err.(StackTracer); ok {
|
||||
st = x
|
||||
}
|
||||
}
|
||||
|
||||
if st != nil {
|
||||
groupValues = append(groupValues,
|
||||
slog.Any("trace", traceLines(st.StackTrace())),
|
||||
)
|
||||
}
|
||||
|
||||
return slog.GroupValue(groupValues...)
|
||||
}
|
||||
|
||||
func traceLines(frames errors.StackTrace) []string {
|
||||
traceLines := make([]string, len(frames))
|
||||
|
||||
// Iterate in reverse to skip uninteresting, consecutive runtime frames at
|
||||
// the bottom of the trace.
|
||||
var skipped int
|
||||
skipping := true
|
||||
for i := len(frames) - 1; i >= 0; i-- {
|
||||
// Adapted from errors.Frame.MarshalText(), but avoiding repeated
|
||||
// calls to FuncForPC and FileLine.
|
||||
pc := uintptr(frames[i]) - 1
|
||||
fn := runtime.FuncForPC(pc)
|
||||
if fn == nil {
|
||||
traceLines[i] = "unknown"
|
||||
skipping = false
|
||||
continue
|
||||
}
|
||||
|
||||
name := fn.Name()
|
||||
|
||||
if skipping && strings.HasPrefix(name, "runtime.") {
|
||||
skipped++
|
||||
continue
|
||||
} else {
|
||||
skipping = false
|
||||
}
|
||||
|
||||
filename, lineNr := fn.FileLine(pc)
|
||||
|
||||
traceLines[i] = fmt.Sprintf("%s %s:%d", name, filename, lineNr)
|
||||
}
|
||||
|
||||
return traceLines[:len(traceLines)-skipped]
|
||||
}
|
||||
Reference in New Issue
Block a user