Как получить логрус для печати стека из пкг / ошибок - PullRequest
0 голосов
/ 25 января 2019

Я использую github.com/sirupsen/logrus и github.com/pkg/errors.Когда я передаю ошибку, упакованную или созданную из pkg / errors, все, что я вижу в выходе из системы, - это сообщение об ошибке.Я хочу увидеть трассировку стека.

Из этой проблемы https://github.com/sirupsen/logrus/issues/506, Я делаю вывод, что у logrus есть какой-то собственный метод для работы с pkg / errors.

Как я могу это сделать

Ответы [ 2 ]

0 голосов
/ 27 января 2019

Комментарий к вашей проблеме с Logrus неверен (и, кстати, кажется, что он поступил от кого-то, не имеющего отношения к 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.

OfКонечно, оба эти параметра заставляют вас использовать формат, определенный 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
        }
}

Вместо того, чтобы печатать каждый кадр, вы можете привести его в любой формат, который вам нравится.

0 голосов
/ 25 января 2019

Логический вывод неверен.Логрус на самом деле не знает, как справиться с ошибкой. Обновление Представитель команды Logrus сказал, что это НЕ поддерживаемая функция, https://github.com/sirupsen/logrus/issues/895#issuecomment-457656556.

Ответ Java-ish Для универсальной работы с ошибкойТаким образом, для обработчиков я составил новую версию Entry, которая принадлежит Logrus.Как показано в примере, создайте новую запись с какими-либо общими полями, которые вы хотите (ниже примера - регистратор, установленный в обработчике, который отслеживает идентификатор вызывающего абонента. Пропускайте PgkError через ваши слои, когда вы работаете с записью. Когда вам нужнорегистрируйте конкретные ошибки, например переменные вызова, в которых произошла ошибка, начните с PkgError.WithError (...), затем добавьте свои данные.

Это отправная точка. Если вы хотите использовать это в общем, реализуйте всеинтерфейс Entity на PkgErrorEntry. Продолжайте делегировать внутреннюю запись, но верните новый 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")
}

A Gopher-ishway См. https://www.reddit.com/r/golang/comments/ajby88/how_to_get_stack_traces_in_logrus/ для получения более подробной информации.

Бен Джонсон написал о том, как сделать ошибки частью вашего домена. Сокращенная версия заключается в том, что вы должны поместить атрибуты трассировщика вПользовательская ошибка. Когда код находится под вашим контролем или когда происходит ошибка из сторонней библиотеки, код immediaЕсли вы решите проблему с ошибкой, в пользовательскую ошибку должно быть включено уникальное значение.Это значение будет напечатано как часть реализации пользовательской ошибки Error() string.

Когда разработчики получат файл журнала, они смогут найти базу кода для этого уникального значения.Бен говорит: «Наконец, мы должны быть в состоянии предоставить всю эту информацию, а также трассировку логического стека нашему оператору, чтобы они могли отлаживать проблемы. Go уже предоставляет простой метод error.Error () для вывода информации об ошибках, чтобы мы могли использоватьthat. "

Вот пример Бена

// 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-способным кодом, заключается в том, что значение легко отклоняется от исходного контекста.Например, скажем, имя функции было изменено с attachRole на что-то другое, и функция стала длиннее.Возможно, что значение операции может отличаться от имени функции.В любом случае это, по-видимому, удовлетворяет общую потребность в поиске проблемы, в то же время обрабатывая ошибки, с которыми сталкиваются граждане первого сорта.Оставайтесь в курсе.https://go.googlesource.com/proposal/+/refs/changes/97/159497/3/design/XXXXX-error-values.md

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...