我正在使用github.com/sirupsen/logrus和github.com/pkg/errors。当我处理由pkg / errors包装或创建的错误时,我在注销中看到的只是错误消息。我想查看堆栈跟踪。
从这个问题https://github.com/sirupsen/logrus/issues/506,我推断出logrus有一些本地方法可以处理pkg / errors。
我该怎么做?
答案 0 :(得分:0)
推论是错误的。 Logrus实际上并不知道如何处理该错误。 更新:Logrus小组的负责人说,这不是受支持的功能https://github.com/sirupsen/logrus/issues/895#issuecomment-457656556。
类似Java的响应 为了以这种方式通用地使用错误处理程序,我编写了一个新版本的Entry,它来自Logrus。如示例所示,使用所需的常用字段创建一个新Entry(示例下方是在处理程序中设置的记录器,该记录器跟踪呼叫者ID。在处理Entry时,将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, "\t", "", -1)
stack := strings.Split(valued, "\n")
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
}
我可以使用可重复代码的代码存在的一个问题是,该值很容易与原始上下文背离。例如,说函数的名称从attachRole更改为其他名称,并且函数变长了。 op值可能与函数名称不同。无论如何,这似乎可以满足追踪问题的一般需求,同时也可以处理头等公民的错误。
Go2可能会为此弯下腰,以获得更多类似于Java的响应。敬请关注。 https://go.googlesource.com/proposal/+/refs/changes/97/159497/3/design/XXXXX-error-values.md
答案 1 :(得分:0)
您对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()))
}
从今天开始,当您使用JSON日志记录时,my a pull request of mine was merged with pkg/errors
现在变得更加简单:
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\n", f, f) // Or your own formatting
}
}
您可以将其强制打印为所需的任何格式,而不是打印每个帧。