Введение
предыдущий постПредставляет библиотеку ведения журналов в стандартной библиотеке Go.log
. Наконец, мы также упомянули, чтоlog
Библиотека предоставляет только три набора интерфейсов, и функция слишком проста.
Сегодня давайте представим «звездную библиотеку» в лог-библиотеке —logrus
. На момент написания этой статьи (2020.02.07),logrusКоличество звезд на GitHub достигло 13,8 тыс.logrus
полностью соответствует стандартуlog
Библиотека также поддерживает два формата вывода журнала: текст и JSON. Многие известные проекты с открытым исходным кодом используют эту библиотеку, например, знаменитый докер.
быстрый в использовании
Сначала необходимо установить сторонние библиотеки:
$ go get github.com/sirupsen/logrus
После использования:
package main
import (
"github.com/sirupsen/logrus"
)
func main() {
logrus.SetLevel(logrus.TraceLevel)
logrus.Trace("trace msg")
logrus.Debug("debug msg")
logrus.Info("info msg")
logrus.Warn("warn msg")
logrus.Error("error msg")
logrus.Fatal("fatal msg")
logrus.Panic("panic msg")
}
logrus
очень прост в использовании, со стандартной библиотекойlog
похожий.logrus
Поддерживается больше уровней ведения журнала:
-
Panic
: войти, тоpanic
. -
Fatal
: Неустранимая ошибка, при возникновении ошибки программа не может работать нормально. После вывода журнала программа завершает работу; -
Error
: Журнал ошибок, нужно проверить причину; -
Warn
: Предупреждающее сообщение, напоминающее программистам об осторожности; -
Info
: Журналы ключевых операций, основных процессов; -
Debug
: вывод отладочной информации в общие программы; -
Trace
: очень подробная информация, обычно не используемая;
Уровень лога увеличивается последовательно сверху вниз,Trace
максимум,Panic
минимум.logrus
Существует уровень журнала, выше которого журналы не выводятся.
Уровень по умолчаниюInfoLevel
. Итак, чтобы увидетьTrace
иDebug
войти, мыmain
Первая строка функции устанавливает уровень журнала наTraceLevel
.
Запускаем программу, выводим:
$ go run main.go
time="2020-02-07T21:22:42+08:00" level=trace msg="trace msg"
time="2020-02-07T21:22:42+08:00" level=debug msg="debug msg"
time="2020-02-07T21:22:42+08:00" level=info msg="info msg"
time="2020-02-07T21:22:42+08:00" level=info msg="warn msg"
time="2020-02-07T21:22:42+08:00" level=error msg="error msg"
time="2020-02-07T21:22:42+08:00" level=fatal msg="fatal msg"
exit status 1
так какlogrus.Fatal
приведет к выходу программы, следующиеlogrus.Panic
не будет реализовано.
Кроме того, в выводе мы наблюдаем три ключевых фрагмента информации:time
,level
иmsg
:
-
time
: время вывода журнала; -
level
: уровень журнала; -
msg
: информация журнала.
сделанный на заказ
имя выходного файла
перечислитьlogrus.SetReportCaller(true)
Установите для добавления информации об имени файла и методе в выходной журнал:
package main
import (
"github.com/sirupsen/logrus"
)
func main() {
logrus.SetReportCaller(true)
logrus.Info("info msg")
}
Вывод имеет еще два поляfile
для звонкаlogrus
имя файла соответствующего метода,method
Для имени метода:
$ go run main.go
time="2020-02-07T21:46:03+08:00" level=info msg="info msg" func=main.main file="D:/code/golang/src/github.com/darjun/go-daily-lib/logrus/caller/main.go:10"
добавить поле
Иногда необходимо добавить в вывод какие-то поля, что можно сделать, вызвавlogrus.WithField
иlogrus.WithFields
выполнить.logrus.WithFields
принять одинlogrus.Fields
параметр типа, базовый слой которого фактическиmap[string]interface{}
:
// github.com/sirupsen/logrus/logrus.go
type Fields map[string]interface{}
Следующая программа добавляет два поля к выходным даннымname
иage
:
package main
import (
"github.com/sirupsen/logrus"
)
func main() {
logrus.WithFields(logrus.Fields{
"name": "dj",
"age": 18,
}).Info("info msg")
}
Если во все журналы в функции необходимо добавить некоторые поля, вы можете использоватьWithFields
Возвращаемое значение. Например, в обработчик веб-запроса необходимо добавить логuser_id
иip
Поле:
package main
import (
"github.com/sirupsen/logrus"
)
func main() {
requestLogger := logrus.WithFields(logrus.Fields{
"user_id": 10010,
"ip": "192.168.32.15",
})
requestLogger.Info("info msg")
requestLogger.Error("error msg")
}
По факту,WithFields
вернутьlogrus.Entry
значение типа, оно будетlogrus.Logger
и установитьlogrus.Fields
Сохрани это.
перечислитьEntry
Когда связанный метод выводит журнал, сохраненныйlogrus.Fields
также будет выводиться соответственно.
перенаправить вывод
По умолчанию журналы выводятся вio.Stderr
. можно назватьlogrus.SetOutput
проходить вio.Writer
параметр. Последующие вызовы соответствующих журналов методов будут записываться вio.Writer
середина.
Теперь, как и в предыдущей статье, мы можем представитьlogПора что-то делать. проходить вio.MultiWriter
,
Также записывайте логи вbytes.Buffer
, стандартный вывод и файлы:
package main
import (
"bytes"
"io"
"log"
"os"
"github.com/sirupsen/logrus"
)
func main() {
writer1 := &bytes.Buffer{}
writer2 := os.Stdout
writer3, err := os.OpenFile("log.txt", os.O_WRONLY|os.O_CREATE, 0755)
if err != nil {
log.Fatalf("create file log.txt failed: %v", err)
}
logrus.SetOutput(io.MultiWriter(writer1, writer2, writer3))
logrus.Info("info msg")
}
настроить
На самом деле, учитывая простоту использования, библиотека обычно создает объект со значениями по умолчанию, и самые внешние методы пакета обычно работают с этим объектом по умолчанию.
Мы рассмотрели это в нескольких предыдущих статьях:
-
Флаг ежедневной библиотеки Go:
flag
в стандартной библиотекеCommandLine
объект; -
Перейти ежедневный журнал библиотеки:
log
в стандартной библиотекеstd
объект.
Этот метод используется при разработке многих библиотек,logrus
тоже так:
// github.com/sirupsen/logrus/exported.go
var (
std = New()
)
func StandardLogger() *Logger {
return std
}
func SetOutput(out io.Writer) {
std.SetOutput(out)
}
func SetFormatter(formatter Formatter) {
std.SetFormatter(formatter)
}
func SetReportCaller(include bool) {
std.SetReportCaller(include)
}
func SetLevel(level Level) {
std.SetLevel(level)
}
Во-первых, определитеLogger
объектstd
,SetOutput/SetFormatter/SetReportCaller/SetLevel
Эти методы называютсяstd
Соответствующий метод объекта!
Мы, конечно, также можем создать свой собственныйLogger
Объект, использование и прямой вызовlogrus
Метод аналогичен:
package main
import "github.com/sirupsen/logrus"
func main() {
log := logrus.New()
log.SetLevel(logrus.InfoLevel)
log.SetFormatter(&logrus.JSONFormatter{})
log.Info("info msg")
}
формат журнала
logrus
Поддерживаются два формата журнала, текстовый и JSON, по умолчанию используется текстовый формат. в состоянии пройтиlogrus.SetFormatter
Установите формат журнала:
package main
import (
"github.com/sirupsen/logrus"
)
func main() {
logrus.SetLevel(logrus.TraceLevel)
logrus.SetFormatter(&logrus.JSONFormatter{})
logrus.Trace("trace msg")
logrus.Debug("debug msg")
logrus.Info("info msg")
logrus.Warn("warn msg")
logrus.Error("error msg")
logrus.Fatal("fatal msg")
logrus.Panic("panic msg")
}
Программа выводит логи в формате JSON:
$ go run main.go
{"level":"trace","msg":"trace msg","time":"2020-02-07T21:40:04+08:00"}
{"level":"debug","msg":"debug msg","time":"2020-02-07T21:40:04+08:00"}
{"level":"info","msg":"info msg","time":"2020-02-07T21:40:04+08:00"}
{"level":"info","msg":"warn msg","time":"2020-02-07T21:40:04+08:00"}
{"level":"error","msg":"error msg","time":"2020-02-07T21:40:04+08:00"}
{"level":"fatal","msg":"fatal msg","time":"2020-02-07T21:40:04+08:00"}
exit status 1
сторонний формат
кроме встроенногоTextFormatter
иJSONFormatter
, и многие сторонние форматы поддерживаются. Здесь мы вводимnested-logrus-formatter.
Сначала установите:
$ go get github.com/antonfisher/nested-logrus-formatter
После использования:
package main
import (
nested "github.com/antonfisher/nested-logrus-formatter"
"github.com/sirupsen/logrus"
)
func main() {
logrus.SetFormatter(&nested.Formatter{
HideKeys: true,
FieldsOrder: []string{"component", "category"},
})
logrus.Info("info msg")
}
Вывод программы:
Feb 8 15:22:59.077 [INFO] info msg
nested
Формат предоставляет несколько полей для настройки поведения:
// github.com/antonfisher/nested-logrus-formatter/formatter.go
type Formatter struct {
FieldsOrder []string
TimestampFormat string
HideKeys bool
NoColors bool
NoFieldsColors bool
ShowFullLevel bool
TrimMessages bool
}
- дефолт,
logrus
Поле в выходном журналеkey=value
такая форма. использоватьnested
формат, мы можем установитьHideKeys
заtrue
скрыть ключ, вывести только значение; - дефолт,
logrus
это алфавитное поле вывода ключей, которое может быть установленоFieldsOrder
Определите порядок выходных полей; - установив
TimestampFormat
Установите формат даты.
package main
import (
"time"
nested "github.com/antonfisher/nested-logrus-formatter"
"github.com/sirupsen/logrus"
)
func main() {
logrus.SetFormatter(&nested.Formatter{
// HideKeys: true,
TimestampFormat: time.RFC3339,
FieldsOrder: []string{"name", "age"},
})
logrus.WithFields(logrus.Fields{
"name": "dj",
"age": 18,
}).Info("info msg")
}
Если ключи не скрыты, программа выводит:
$ 2020-02-08T15:40:07+08:00 [INFO] [name:dj] [age:18] info msg
Скрытые ключи, вывод программы:
$ 2020-02-08T15:41:58+08:00 [INFO] [dj] [18] info msg
Обратите внимание, что мы устанавливаем формат времени наtime.RFC3339
,Сейчас2006-01-02T15:04:05Z07:00
эта форма.
путем реализации интерфейсаlogrus.Formatter
Вы можете реализовать свой собственный формат.
// github.com/sirupsen/logrus/formatter.go
type Formatter interface {
Format(*Entry) ([]byte, error)
}
установить крючок
так же может бытьlogrus
Установите хук, конкретный метод хука будет выполняться перед каждым выводом журнала. Таким образом, мы можем добавить поля вывода для вывода журналов в разные места назначения в зависимости от уровня.logrus
также имеет встроенныйsyslog
хук, который выводит логи наsyslog
середина. Здесь мы реализуем хук, чтобы добавить хук в выходной журнал.app=awesome-web
поле.
Хуки должны быть реализованыlogrus.Hook
интерфейс:
// github.com/sirupsen/logrus/hooks.go
type Hook interface {
Levels() []Level
Fire(*Entry) error
}
Levels()
Метод возвращает интересующий уровень журнала, хук не будет срабатывать при выводе других журналов.Fire
Метод ловушки вызывается перед выводом журнала.
package main
import (
"github.com/sirupsen/logrus"
)
type AppHook struct {
AppName string
}
func (h *AppHook) Levels() []logrus.Level {
return logrus.AllLevels
}
func (h *AppHook) Fire(entry *logrus.Entry) error {
entry.Data["app"] = h.AppName
return nil
}
func main() {
h := &AppHook{AppName: "awesome-web"}
logrus.AddHook(h)
logrus.Info("info msg")
}
просто нужноFire
При реализации метода дляentry.Data
Добавление полей выводится в лог.
Вывод программы:
$ time="2020-02-08T15:51:52+08:00" level=info msg="info msg" app=awesome-web
logrus
Есть много сторонних хуков, мы можем использовать некоторые хуки для отправки логов в хранилище, например, redis/mongodb:
- mgorus: отправить логи в mongodb;
- logrus-redis-hook: отправить логи в Redis;
- logrus-amqp: отправлять журналы в ActiveMQ.
Здесь мы демонстрируем Redis и заинтересованы в проверке остальных самостоятельно. Установить первымlogrus-redis-hook
:
$ go get github.com/rogierlommers/logrus-redis-hook
Затем напишите программу:
package main
import (
"io/ioutil"
logredis "github.com/rogierlommers/logrus-redis-hook"
"github.com/sirupsen/logrus"
)
func init() {
hookConfig := logredis.HookConfig{
Host: "localhost",
Key: "mykey",
Format: "v0",
App: "aweosome",
Hostname: "localhost",
TTL: 3600,
}
hook, err := logredis.NewHook(hookConfig)
if err == nil {
logrus.AddHook(hook)
} else {
logrus.Errorf("logredis error: %q", err)
}
}
func main() {
logrus.Info("just some info logging...")
logrus.WithFields(logrus.Fields{
"animal": "walrus",
"foo": "bar",
"this": "that",
}).Info("additional fields are being logged as well")
logrus.SetOutput(ioutil.Discard)
logrus.Info("This will only be sent to Redis")
}
Для корректной работы программы нам также необходимо установитьredis
.
Прямое использование на окнахchocoУстановите редис:
PS C:\Users\Administrator> choco install redis-64
Chocolatey v0.10.15
Installing the following packages:
redis-64
By installing you accept licenses for the packages.
Progress: Downloading redis-64 3.0.503... 100%
redis-64 v3.0.503 [Approved]
redis-64 package files install completed. Performing other installation steps.
ShimGen has successfully created a shim for redis-benchmark.exe
ShimGen has successfully created a shim for redis-check-aof.exe
ShimGen has successfully created a shim for redis-check-dump.exe
ShimGen has successfully created a shim for redis-cli.exe
ShimGen has successfully created a shim for redis-server.exe
The install of redis-64 was successful.
Software install location not explicitly set, could be in package or
default install location if installer.
Chocolatey installed 1/1 packages.
See the log for details (C:\ProgramData\chocolatey\logs\chocolatey.log).
прямой вводredis-server
, запустите сервер:
После запуска программы используемredis-cli
Проверять:
Мы виделиmykey
Являетсяlist
, каждый раз, когда приходит лог,list
Добавить элемент позже.
Суммировать
В этой статье описываетсяlogrus
базовое использование.logrus
Расширяемость отлично подходит для внедрения сторонних форматов и улучшений Hook. Также популярен в сообществе.
Ссылаться на
я
Добро пожаловать, чтобы обратить внимание на мою общедоступную учетную запись WeChat [GoUpUp], учитесь вместе и добивайтесь прогресса вместе ~
Эта статья опубликована в блогеOpenWriteвыпуск!