Логирование в файл в JSON формате на Golang

Задача из числа самых обычных - писать в файл сообщения в JSON-формате с определенным набором полей. Для решения воспользуемся библиотекой Logrus .

Самый простой способ использовать Logrus - просто экспортировать логгер на уровне пакета:

package main

import (
    log "github.com/sirupsen/logrus"
)

func main() {
    log.WithFields(log.Fields{
        "animal": "walrus",
    }).Info("A walrus appears")
}
$ go run main.go
INFO[0000] A walrus appears                              animal=walrus

Обратите внимание, что он полностью api-совместим с логгером из stdlib, поэтому вы можете везде заменить import log на log "github.com/sirupsen/logrus", и теперь у вас будет гибкость Logrus. Вы можете настроить все, что хотите:

package main

import (
    "os"
    log "github.com/sirupsen/logrus"
)

func init() {
    // Log as JSON instead of the default ASCII formatter.
    log.SetFormatter(&log.JSONFormatter{})

    // Output to stdout instead of the default stderr
    // Can be any io.Writer, see below for File example
    log.SetOutput(os.Stdout)

    // Only log the warning severity or above.
    log.SetLevel(log.WarnLevel)
}

func main() {
    log.WithFields(log.Fields{
        "animal": "walrus",
        "size":   10,
    }).Info("A group of walrus emerges from the ocean")

    log.WithFields(log.Fields{
        "omg":    true,
        "number": 122,
    }).Warn("The group's number increased tremendously!")

    log.WithFields(log.Fields{
        "omg":    true,
        "number": 100,
    }).Fatal("The ice breaks!")

    // A common pattern is to re-use fields between logging statements by re-using
    // the logrus.Entry returned from WithFields()
    contextLogger := log.WithFields(log.Fields{
        "common": "this is a common field",
        "other": "I also should be logged always",
    })

    contextLogger.Info("I'll be logged with common and other field")
    contextLogger.Info("Me too")
}
$ go run main.go
{"level":"warning","msg":"The group's number increased tremendously!","number":122,"omg":true,"time":"2020-12-04T23:17:26+03:00"}
{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true,"time":"2020-12-04T23:17:26+03:00"}
exit status 1

Для более продвинутого использования, такого как ведение журнала в нескольких местах из одного приложения, вы также можете создать экземпляр logrus Logger:

package main

import (
    "os"
    "github.com/sirupsen/logrus"
)

// Create a new instance of the logger. You can have any number of instances.
var log = logrus.New()

func main() {
    // The API for setting attributes is a little different than the package level
    // exported logger. See Godoc.
    log.Out = os.Stdout

    // Log as JSON instead of the default ASCII formatter.
    log.SetFormatter(&logrus.JSONFormatter{})

    // You could set this to any `io.Writer` such as a file
    file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
    if err == nil {
        log.Out = file
    } else {
        log.Warn("Failed to log to file, using default stderr")
    }

    log.WithFields(logrus.Fields{
        "animal": "walrus",
        "size":   10,
    }).Info("A group of walrus emerges from the ocean")
}
$ go run main.go
$ jq . logrus.log
{
  "animal": "walrus",
  "level": "info",
  "msg": "A group of walrus emerges from the ocean",
  "size": 10,
  "time": "2020-12-04T23:27:31+03:00"
}