亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何讓 logrus 打印 pkg/errors 堆棧

如何讓 logrus 打印 pkg/errors 堆棧

Go
喵喵時光機 2023-06-01 18:19:46
我正在使用 github.com/sirupsen/logrus 和 github.com/pkg/errors。當我提交一個從 pkg/errors 包裝或創建的錯誤時,我在注銷中看到的只是錯誤消息。我想查看堆棧跟蹤。我推斷 logrus 有一些處理 pkg/errors 的本機方法。我怎樣才能做到這一點?
查看完整描述

3 回答

?
繁華開滿天機

TA貢獻1816條經驗 獲得超4個贊

(順便說一句,似乎來自與 Logrus 沒有任何關系且對 Logrus 沒有做出任何貢獻的人,因此實際上不是來自“Logrus 團隊”)。


如記錄的那樣pkg/errors,很容易在錯誤中提取堆棧跟蹤:


type stackTracer interface {

? ? ? ? StackTrace() errors.StackTrace

}

這意味著使用 logrus 記錄堆棧跟蹤的最簡單方法就是:


if stackErr, ok := err.(stackTracer); ok {

? ? log.WithField("stacktrace", fmt.Sprintf("%+v", stackErr.StackTrace()))

}

從今天開始,當我的一個拉取請求與 合并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\n", f, f) // Or your own formatting

? ? ? ? }

}

您可以將其強制轉換為您喜歡的任何格式,而不是打印每一幀。


查看完整回答
反對 回復 2023-06-01
?
DIEA

TA貢獻1820條經驗 獲得超2個贊

推論是錯誤的。Logrus 實際上并不知道如何處理錯誤。?

類似 Java 的響應?為了以這種方式普遍使用錯誤處理程序,我編寫了一個新版本的 Entry,它來自 Logrus。如示例所示,使用您想要的任何常用字段創建一個新條目(示例下方是在處理程序中設置的記錄器,用于跟蹤調用者 ID。在處理條目時通過層傳遞 PgkError。當您需要時記錄特定的錯誤,比如遇到錯誤的調用變量,從 PkgError.WithError(...) 開始,然后添加您的詳細信息。

這是一個起點。如果您想普遍使用它,請在 PkgErrorEntry 上實現所有 Entity 接口。繼續委托給內部入口,但返回一個新的 PkgErrorEntry。這樣的更改將使 true 的值代替 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寫過關于讓錯誤成為你領域的一部分。一個簡化版本是您應該將跟蹤器屬性放在自定義錯誤上。當直接受您控制的代碼出錯或發生來自第 3 方庫的錯誤時,立即處理錯誤的代碼應將唯一值放入自定義錯誤中。該值將作為自定義錯誤Error() string實現的一部分打印。


當開發人員獲得日志文件時,他們將能夠 grep 代碼庫以獲取該唯一值。Ben 說:“最后,我們需要能夠向我們的操作員提供所有這些信息以及邏輯堆棧跟蹤,以便他們可以調試問題。Go 已經提供了一個簡單的方法 error.Error() 來打印錯誤信息,因此我們可以利用那?!?/p>


這是本的例子


// 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 響應。


查看完整回答
反對 回復 2023-06-01
?
忽然笑

TA貢獻1806條經驗 獲得超5個贊

使用自定義鉤子提取堆棧跟蹤


import (

    "fmt"

    "github.com/pkg/errors"

    "github.com/sirupsen/logrus"

)


type StacktraceHook struct {

}


func (h *StacktraceHook) Levels() []logrus.Level {

    return logrus.AllLevels

}


func (h *StacktraceHook) Fire(e *logrus.Entry) error {

    if v, found := e.Data[logrus.ErrorKey]; found {

        if err, iserr := v.(error); iserr {

            type stackTracer interface {

                StackTrace() errors.StackTrace

            }

            if st, isst := err.(stackTracer); isst {

                stack := fmt.Sprintf("%+v", st.StackTrace())

                e.Data["stacktrace"] = stack

            }

        }

    }

    return nil

}


func main() {

    logrus.SetFormatter(&logrus.TextFormatter{DisableQuote: true})

    logrus.AddHook(&StacktraceHook{})


    logrus.WithError(errors.New("Foo")).Error("Wrong")

}

輸出


time=2009-11-10T23:00:00Z level=error msg=Wrong error=Foo stacktrace=

main.main

    /tmp/sandbox1710078453/prog.go:36

runtime.main

    /usr/local/go-faketime/src/runtime/proc.go:250

runtime.goexit

    /usr/local/go-faketime/src/runtime/asm_amd64.s:1594


查看完整回答
反對 回復 2023-06-01
  • 3 回答
  • 0 關注
  • 540 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號