如何让logrus打印堆栈的pkg /错误
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何让logrus打印堆栈的pkg /错误相关的知识,希望对你有一定的参考价值。
我正在使用github.com/sirupsen/logrus和github.com/pkg/errors。当我处理由pkg / errors包装或创建的错误时,我在注销中看到的只是错误消息。我想看看堆栈跟踪。
从这个问题,https://github.com/sirupsen/logrus/issues/506,我推断logrus有一些本地方法来处理pkg / errors。
我怎样才能做到这一点?
推断是错误的。 Logrus实际上并不知道如何处理错误。更新Logrus团队的官员说,这不是一个支持的功能,https://github.com/sirupsen/logrus/issues/895#issuecomment-457656556。
Java-ish响应为了以这种方式普遍使用错误处理程序,我编写了一个新版本的Entry,它来自Logrus。如示例所示,创建一个包含所需常用字段的新条目(在示例下方是跟踪调用者ID的处理程序中设置的记录器。在处理条目时将PgkError传递到各个层。当您需要时记录特定错误,如遇到错误的调用变量,从PkgError.WithError(...)开始,然后添加您的详细信息。
这是一个起点。如果您想一般使用它,请在PkgErrorEntry上实现所有Entity接口。继续委托内部条目,但返回一个新的PkgErrorEntry。这样的改变将使得替换Entry的值真正下降。
package main
import (
"fmt"
"github.com/sirupsen/logrus"
"strings"
unwrappedErrors "errors"
"github.com/pkg/errors"
)
// PkgErrorEntry enables stack frame extraction directly into the log fields.
type PkgErrorEntry struct {
*logrus.Entry
// Depth defines how much of the stacktrace you want.
Depth int
}
// This is dirty pkg/errors.
type stackTracer interface {
StackTrace() errors.StackTrace
}
func (e *PkgErrorEntry) WithError(err error) *logrus.Entry {
out := e.Entry
common := func(pError stackTracer) {
st := pError.StackTrace()
depth := 3
if e.Depth != 0 {
depth = e.Depth
}
valued := fmt.Sprintf("%+v", st[0:depth])
valued = strings.Replace(valued, " ", "", -1)
stack := strings.Split(valued, "
")
out = out.WithField("stack", stack[2:])
}
if err2, ok := err.(stackTracer); ok {
common(err2)
}
if err2, ok := errors.Cause(err).(stackTracer); ok {
common(err2)
}
return out.WithError(err)
}
func someWhereElse() error {
return unwrappedErrors.New("Ouch")
}
func level1() error {
return level2()
}
func level2() error {
return errors.WithStack(unwrappedErrors.New("All wrapped up"))
}
func main() {
baseLog := logrus.New()
baseLog.SetFormatter(&logrus.JSONFormatter{})
errorHandling := PkgErrorEntry{Entry: baseLog.WithField("callerid", "1000")}
errorHandling.Info("Hello")
err := errors.New("Hi")
errorHandling.WithError(err).Error("That should have a stack.")
err = someWhereElse()
errorHandling.WithError(err).Info("Less painful error")
err = level1()
errorHandling.WithError(err).Warn("Should have multiple layers of stack")
}
Gopher-ish方式有关详细信息,请参阅https://www.reddit.com/r/golang/comments/ajby88/how_to_get_stack_traces_in_logrus/。
Ben Johnson wrote关于将错误归咎于您的域名。缩写版本是您应该将跟踪器属性放在自定义错误上。当代码直接出现在您的控制错误下或第三方库发生错误时,立即处理错误的代码应该在自定义错误中添加唯一值。此值将作为自定义错误的Error() string
实现的一部分打印。
当开发人员获得日志文件时,他们将能够为该唯一值grep代码库。 Ben说:“最后,我们需要能够向操作员提供所有这些信息和逻辑堆栈跟踪,以便他们可以调试问题.Go已经提供了一个简单的方法,error.Error(),以便打印错误信息,以便我们可以利用那。”
这是本的例子
// attachRole inserts a role record for a user in the database
func (s *UserService) attachRole(ctx context.Context, id int, role string) error {
const op = "attachRole"
if _, err := s.db.Exec(`INSERT roles...`); err != nil {
return &myapp.Error{Op: op, Err: err}
}
return nil
}
我对grep-able代码的一个问题是,值很容易偏离原始上下文。例如,假设函数的名称已从attachRole更改为其他内容,并且函数更长。 op值可能与函数名称不同。无论如何,这似乎满足了追踪问题的一般需要,同时将错误视为一等公民。
Go2可能会在此处引入更多Java-ish响应。敬请关注。 https://go.googlesource.com/proposal/+/refs/changes/97/159497/3/design/XXXXX-error-values.md
关于你的Logrus问题的评论是不正确的(顺便说一下,似乎来自与Logrus没有任何关系的人,以及谁没有对Logrus做出任何贡献,所以实际上并没有来自“Logrus团队”)。
在pkg/errors
错误as documented中很容易提取堆栈跟踪:
type stackTracer interface {
StackTrace() errors.StackTrace
}
这意味着使用logrus记录堆栈跟踪的最简单方法就是:
if stackErr, ok := err.(stackTracer); ok {
log.WithField("stacktrace", fmt.Sprintf("%+v", stackErr.StackTrace()))
}
截至今天,当my a pull request of mine was merged with pkg/errors
,现在更容易,如果您正在使用JSON日志记录:
if stackErr, ok := err.(stackTracer); ok {
log.WithField("stacktrace", stackErr.StackTrace())
}
这将生成类似于“%+ v”的日志格式,但没有换行符或选项卡,每个字符串有一个日志条目,以便轻松编组成JSON数组。
当然,这两个选项都迫使您使用pkg/errors
定义的格式,这并不总是理想的。因此,您可以遍历堆栈跟踪,并生成自己的格式,可能会生成一个易于编组为JSON的格式。
if err, ok := err.(stackTracer); ok {
for _, f := range err.StackTrace() {
fmt.Printf("%+s:%d
", f, f) // Or your own formatting
}
}
您可以将其强制转换为您喜欢的任何格式,而不是打印每个帧。
以上是关于如何让logrus打印堆栈的pkg /错误的主要内容,如果未能解决你的问题,请参考以下文章