Open9

bombsimon/logrusr に warn, debug log を出力させたい

Shunsuke SuzukiShunsuke Suzuki
package main

import (
	"github.com/bombsimon/logrusr/v4"
	"github.com/go-logr/logr"
	"github.com/sirupsen/logrus"
)

func main() {
	logrusLog := logrus.New()
	log := logrusr.New(logrusLog)
	if err := run(log); err != nil {
		log.V(1).Error(err, "fail")
	}
}

func run(log logr.Logger) error {
	log = log.WithName("MyName").WithValues("user", "you")
	for level := 0; level <= 10; level++ {
		log.V(level).Info("log", "level", level)
	}
	return nil
}
$ go run main.go
INFO[0000] log                                           fields.level=0 logger=MyName user=you

info log しか出力しない

Shunsuke SuzukiShunsuke Suzuki

logpr#Logger.Info
logrusr#Sink.Enabled
logrus#Logger.IsLevelEnabled

# logpr#Logger.Info
if l.sink.Enabled(l.level) {
# logrusr#Sink.Enabled
return l.logger.Logger.IsLevelEnabled(logrus.Level(level + logrusDiffToInfo))
# logrus#Logger.IsLevelEnabled 
return logger.level() >= level

logpr#Logger の level + 4 (logrusDiffToInfo) が logrus#Logger の level より小さければ log を出力

logpr#Logger.V
引数が 0 より小さい場合は 0 扱い
Logger.level を引数分増やす

logrusr.New
logr.New で logr.Logger を生成
デフォルトでは logr.Logger.level は 0

logrus#New
logrus.Logger.Level はデフォルトで InfoLevel (4)

つまりデフォルトでは log は出力されるが、 V(N) で N が 1 以上の場合、 logpr#Logger の level が大きくなるので出力されない


V(N) で N が 1 以上の場合 log が出力されない原因はわかった。
デフォルトで info log を出力する理由と warn, debug log を出力する方法を調べる

Shunsuke SuzukiShunsuke Suzuki
# logpr#Logger.Info
l.sink.Info(l.level, msg, keysAndValues...)
# logrus#logrusr#Info
Log(logrus.Level(level+logrusDiffToInfo), msg) # logrus.Logger#Log

logpr#Logger.Info は logpr#Logger.level + 4 の level の log を logrus で出力している
つまり level はデフォルトで 4 = InfoLevel で常に 4 以上

https://pkg.go.dev/github.com/sirupsen/logrus#Level

Debug, Trace は出力できるが、 Warn や Fatal は出力できないように見える。
logr は Warn の存在を否定しているからだろうか?

https://github.com/go-logr/logr?tab=readme-ov-file#why-not-named-levels-like-infowarningerror

Verbosity-levels on info logs. This gives developers a chance to indicate arbitrary grades of importance for info logs, without assigning names with semantic meaning such as "warning", "trace", and "debug." Superficially this may feel very similar, but the primary difference is the lack of semantics. Because verbosity is a numerical value, it's safe to assume that an app running with higher verbosity means more (and less important) logs will be generated.

Shunsuke SuzukiShunsuke Suzuki

logrus-error

https://github.com/suzuki-shunsuke/logrus-error

func WithFields(err error, fields logrus.Fields) error
func WithError(entry *logrus.Entry, err error) *logrus.Entry

slog-error

https://github.com/suzuki-shunsuke/slog-error

func With(err error, args ...any) error
func WithError(logger *slog.Logger, err error) *slog.Logger

logrus

func WithError(err error) *Entry
func WithField(key string, value interface{}) *Entry
func WithFields(fields Fields) *Entry
func (entry *Entry) Debug(args ...interface{})
const (
	// PanicLevel level, highest level of severity. Logs and then calls panic with the
	// message passed to Debug, Info, ...
	PanicLevel Level = iota
	// FatalLevel level. Logs and then calls `logger.Exit(1)`. It will exit even if the
	// logging level is set to Panic.
	FatalLevel
	// ErrorLevel level. Logs. Used for errors that should definitely be noted.
	// Commonly used for hooks to send errors to an error tracking service.
	ErrorLevel
	// WarnLevel level. Non-critical entries that deserve eyes.
	WarnLevel
	// InfoLevel level. General operational entries about what's going on inside the
	// application.
	InfoLevel
	// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
	DebugLevel
	// TraceLevel level. Designates finer-grained informational events than the Debug.
	TraceLevel
)

slog

func With(args ...any) *Logger
func (l *Logger) Error(msg string, args ...any)
const (
	LevelDebug Level = -4
	LevelInfo  Level = 0
	LevelWarn  Level = 4
	LevelError Level = 8
)
Shunsuke SuzukiShunsuke Suzuki

logrus-util

func New(program, version string) *logrus.Entry
func Set(logE *logrus.Entry, level, color string) error
  • log level
  • log color

level

logrus.ParseLevel(level)
logE.Logger.Level

color

logE.Logger.SetFormatter(&logrus.TextFormatter{
			ForceColors: true,
		})
		logE.Logger.SetFormatter(&logrus.TextFormatter{
			DisableColors: true,
		})
Shunsuke SuzukiShunsuke Suzuki

統一的な API

func With(err error, args ...any) error
func WithError(logger *Logger, err error) *Logger
EnableColor()
DisableColor()
SetLogLevel(level LogLevel)
func (l *Logger) With(args ...any) *Logger
func (l *Logger) WithError(error) *Logger
func (l *Logger) Error(msg string)
Shunsuke SuzukiShunsuke Suzuki

https://github.com/samber/slog-logrus

logrus を使って slog.Handler を実装している。

urfave-cli-v3-util 内部では slog を使い、 logrus を使いたい場合は slog-logrus を使って内部で logrus を使うようにすると、 slog, logrus 両方サポートできるのでは。