logger/slog: add stacktrace support
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
parent
897be419b4
commit
4c7e1607d4
@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
@ -14,6 +15,8 @@ import (
|
|||||||
"go.unistack.org/micro/v3/tracer"
|
"go.unistack.org/micro/v3/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var reTrace = regexp.MustCompile(`.*/slog/logger\.go.*\n`)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
DefaultSourceKey string = slog.SourceKey
|
DefaultSourceKey string = slog.SourceKey
|
||||||
DefaultTimeKey string = slog.TimeKey
|
DefaultTimeKey string = slog.TimeKey
|
||||||
@ -290,6 +293,15 @@ func (s *slogLogger) Error(ctx context.Context, attrs ...interface{}) {
|
|||||||
runtime.Callers(s.opts.CallerSkipCount, pcs[:]) // skip [Callers, Infof]
|
runtime.Callers(s.opts.CallerSkipCount, pcs[:]) // skip [Callers, Infof]
|
||||||
r := slog.NewRecord(time.Now(), slog.LevelError, fmt.Sprintf("%s", attrs[0]), pcs[0])
|
r := slog.NewRecord(time.Now(), slog.LevelError, fmt.Sprintf("%s", attrs[0]), pcs[0])
|
||||||
// r.Add(attrs[1:]...)
|
// r.Add(attrs[1:]...)
|
||||||
|
if s.opts.Stacktrace {
|
||||||
|
stackInfo := make([]byte, 1024*1024)
|
||||||
|
if stackSize := runtime.Stack(stackInfo, false); stackSize > 0 {
|
||||||
|
traceLines := reTrace.Split(string(stackInfo[:stackSize]), -1)
|
||||||
|
if len(traceLines) != 0 {
|
||||||
|
r.AddAttrs(slog.String("stacktrace", traceLines[len(traceLines)-1]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
r.Attrs(func(a slog.Attr) bool {
|
r.Attrs(func(a slog.Attr) bool {
|
||||||
if a.Key == "error" {
|
if a.Key == "error" {
|
||||||
if span, ok := tracer.SpanFromContext(ctx); ok {
|
if span, ok := tracer.SpanFromContext(ctx); ok {
|
||||||
@ -310,6 +322,15 @@ func (s *slogLogger) Errorf(ctx context.Context, msg string, attrs ...interface{
|
|||||||
runtime.Callers(s.opts.CallerSkipCount, pcs[:]) // skip [Callers, Infof]
|
runtime.Callers(s.opts.CallerSkipCount, pcs[:]) // skip [Callers, Infof]
|
||||||
r := slog.NewRecord(time.Now(), slog.LevelError, fmt.Sprintf(msg, attrs...), pcs[0])
|
r := slog.NewRecord(time.Now(), slog.LevelError, fmt.Sprintf(msg, attrs...), pcs[0])
|
||||||
// r.Add(attrs...)
|
// r.Add(attrs...)
|
||||||
|
if s.opts.Stacktrace {
|
||||||
|
stackInfo := make([]byte, 1024*1024)
|
||||||
|
if stackSize := runtime.Stack(stackInfo, false); stackSize > 0 {
|
||||||
|
traceLines := reTrace.Split(string(stackInfo[:stackSize]), -1)
|
||||||
|
if len(traceLines) != 0 {
|
||||||
|
r.AddAttrs(slog.String("stacktrace", traceLines[len(traceLines)-1]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
r.Attrs(func(a slog.Attr) bool {
|
r.Attrs(func(a slog.Attr) bool {
|
||||||
if a.Key == "error" {
|
if a.Key == "error" {
|
||||||
if span, ok := tracer.SpanFromContext(ctx); ok {
|
if span, ok := tracer.SpanFromContext(ctx); ok {
|
||||||
|
@ -9,6 +9,20 @@ import (
|
|||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v3/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestError(t *testing.T) {
|
||||||
|
ctx := context.TODO()
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
l := NewLogger(logger.WithLevel(logger.ErrorLevel), logger.WithOutput(buf), logger.WithStacktrace(true))
|
||||||
|
if err := l.Init(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Error(ctx, "message")
|
||||||
|
if !bytes.Contains(buf.Bytes(), []byte(`"stacktrace":"`)) {
|
||||||
|
t.Fatalf("logger stacktrace not works, buf contains: %s", buf.Bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestContext(t *testing.T) {
|
func TestContext(t *testing.T) {
|
||||||
ctx := context.TODO()
|
ctx := context.TODO()
|
||||||
buf := bytes.NewBuffer(nil)
|
buf := bytes.NewBuffer(nil)
|
||||||
|
Loading…
Reference in New Issue
Block a user