zerolog icon indicating copy to clipboard operation
zerolog copied to clipboard

ConsoleWriter fails when used with other writers

Open GaikwadPratik opened this issue 4 years ago • 3 comments
trafficstars

I'm currently trying to use consolewriter along with filewriter and journalwriter.

Below is my configuration code

// ConfigLogger contains Configuration for logging
type ConfigLogger struct {
	// Enable console logging
	ConsoleLoggingEnabled bool

	// EncodeLogsAsJson makes the log framework log JSON
	EncodeLogsAsJson bool
	// FileLoggingEnabled makes the framework log to a file
	// the fields below can be skipped if this value is false!
	FileLoggingEnabled bool
	// JournalLoggingEnabled makes the framework log to systemd-journald
	JournalLoggingEnabled bool
	// Directory to log to to when filelogging is enabled
	Directory string
	// Filename is the name of the logfile which will be placed inside the directory
	Filename string
	// MaxSize the max size in MB of the logfile before it's rolled
	MaxSize int
	// MaxBackups the max number of rolled files to keep
	MaxBackups int
	// MaxAge the max age in days to keep a logfile
	MaxAge int
}

func newRollingFile(config ConfigLogger) io.Writer {
	if err := os.MkdirAll(config.Directory, 0744); err != nil {
		log.Error().Err(err).Str("path", config.Directory).Msg("can't create log directory")
		return nil
	}

	return &lumberjack.Logger{
		Filename:   path.Join(config.Directory, config.Filename),
		MaxBackups: config.MaxBackups, // files
		MaxSize:    config.MaxSize,    // megabytes
		MaxAge:     config.MaxAge,     // days
	}
}

//ConfigureLogger updates opeion on logger
func ConfigureLogger(config ConfigLogger) zerolog.Logger {
	var writers []io.Writer
	zerolog.SetGlobalLevel(zerolog.DebugLevel)

	if config.ConsoleLoggingEnabled {
		writers = append(writers, zerolog.ConsoleWriter{Out: os.Stdout, NoColor: false})
	}
	if config.FileLoggingEnabled {
		writers = append(writers, newRollingFile(config))
	}
	if config.JournalLoggingEnabled {
		writers = append(writers, journald.NewJournalDWriter())
	}
	mw := io.MultiWriter(writers...)
	zerolog.MessageFieldName = "msg"
	hostname, err := os.Hostname()
	if err != nil {
		panic("Unable to get hostname of the system")
	}
	logger := zerolog.
		New(mw).
		With().
		Int("pid", os.Getpid()).
		Int("v", 0).
		Str("hostname", hostname).
		Str("name", "hio:vm:manager").
		Caller().
		Timestamp().
		Logger().
		Hook(BunyanHook{})

	logger.Info().
		Bool("fileLogging", config.FileLoggingEnabled).
		Bool("jsonLogOutput", config.EncodeLogsAsJson).
		Str("logDirectory", config.Directory).
		Str("fileName", config.Filename).
		Int("maxSizeMB", config.MaxSize).
		Int("maxBackups", config.MaxBackups).
		Int("maxAgeInDays", config.MaxAge).
		Msg("logging configured")

	return logger
}

Invocation is done

conf := utilities.ConfigLogger{
		ConsoleLoggingEnabled: true,
		EncodeLogsAsJson:      true,
		FileLoggingEnabled:    true,
		JournalLoggingEnabled: true,
		Directory:             "/var/log/",
		Filename:              filename,
		MaxSize:               100,
		MaxBackups:            2,
		MaxAge:                7,
	}
	log.Logger = utilities.ConfigureLogger(conf)

But when I run application, I get

panic: runtime error: slice bounds out of range [:3] with length 2

goroutine 1 [running]:
github.com/rs/zerolog.consoleDefaultFormatLevel.func1(0x9edb40, 0xc0000998d0, 0xa84176, 0x5)
	/workspace/pkg/mod/github.com/rs/[email protected]/console.go:357 +0x49e
github.com/rs/zerolog.ConsoleWriter.writePart(0xb2c360, 0xc0000bc008, 0x0, 0x0, 0x0, 0xc0000dc400, 0x4, 0x4, 0x0, 0x0, ...)
	/workspace/pkg/mod/github.com/rs/[email protected]/console.go:256 +0x156
github.com/rs/zerolog.ConsoleWriter.Write(0xb2c360, 0xc0000bc008, 0x0, 0x0, 0x0, 0xc0000dc400, 0x4, 0x4, 0x0, 0x0, ...)
	/workspace/pkg/mod/github.com/rs/[email protected]/console.go:111 +0x285
io.(*multiWriter).Write(0xc0000b02a0, 0xc0001b8c00, 0x175, 0x1f4, 0x158, 0x1f4, 0x19)
	/usr/local/go/src/io/multi.go:60 +0x87
github.com/rs/zerolog.levelWriterAdapter.WriteLevel(...)
	/workspace/pkg/mod/github.com/rs/[email protected]/writer.go:20
github.com/rs/zerolog.(*Event).write(0xc0000be660, 0x160, 0x1f4)
	/workspace/pkg/mod/github.com/rs/[email protected]/event.go:78 +0x125
github.com/rs/zerolog.(*Event).msg(0xc0000be660, 0xa8a50a, 0x12)
	/workspace/pkg/mod/github.com/rs/[email protected]/event.go:142 +0x21b
github.com/rs/zerolog.(*Event).Msg(...)
	/workspace/pkg/mod/github.com/rs/[email protected]/event.go:108
hive-vm-manager/utilities.Configure(0x1010101, 0xa85922, 0x9, 0xa93be7, 0x23, 0x64, 0x2, 0x7, 0x0, 0x0, ...)
	/workspaces/hive-vm-manager/utilities/logger.go:92 +0x9c5
hive-vm-manager/hio-vm-manager-cmd/cmd.InitLoggerConfig(0xa93be7, 0x23)
	/workspaces/hive-vm-manager/hio-vm-manager-cmd/cmd/common.go:21 +0xc6
hive-vm-manager/hio-vm-manager-cmd/cmd.init.0()
	/workspaces/hive-vm-manager/hio-vm-manager-cmd/cmd/correctoldmetadata.go:62 +0x77

What am I missing? I tried setting NoColor option to both true and false. Since the LogLevel is set using SetGlobalLogLevel func call, do I need to anything specific for consolewriter?

GaikwadPratik avatar Aug 05 '21 22:08 GaikwadPratik

@rs ,

Any thoughts/suggestions? If this is not the right place to ask questions, can you please let me know what platform is used for queries?

GaikwadPratik avatar Aug 07 '21 20:08 GaikwadPratik

@GaikwadPratik , Have you tried zerolog.MultiLevelWriter instead of io.MultiWriter?

https://github.com/rs/zerolog#multiple-log-output

thaney071 avatar Nov 03 '21 02:11 thaney071

@thaney071 ,

Thank you for suggestion. I tried that. No it didn't work. It failed with same error as soon as enabled ConsoleLogging. Any other suggestion?

GaikwadPratik avatar Nov 03 '21 15:11 GaikwadPratik

In my case, the problem was that I was passing a field named "level". Renaming it solved the issue.

kamushadenes avatar Feb 12 '23 12:02 kamushadenes

@kamushadenes,

I think that is also case with me. bunyan hook needs level and that's when ConsoleWriter breaks down.

Because in case of bunyan, the hook is as follows:

type BunyanHook struct{}

func (b BunyanHook) Run(e *zerolog.Event, level zerolog.Level, msg string) {
	blevel := 10
	switch level {
	case zerolog.FatalLevel:
		blevel = 60
	case zerolog.ErrorLevel:
		blevel = 50
	case zerolog.WarnLevel:
		blevel = 40
	case zerolog.InfoLevel:
		blevel = 30
	case zerolog.DebugLevel:
		blevel = 20
	case zerolog.TraceLevel:
	default:
		blevel = 10
	}
	e.Int("level", blevel)
}

and then as indicated in original post, it is added to logger as

                .....
		Logger().
		Hook(BunyanHook{})

Also bunyan expects level to be an int whereas zerolog.console expects it as string with at min 3 characters.

GaikwadPratik avatar Mar 16 '23 03:03 GaikwadPratik

The only option I could find was to write my own Formatter for console writer and use colorize functionality from zero log. I wish that would've been public. but alas, not everything is easy, yet

GaikwadPratik avatar Mar 16 '23 03:03 GaikwadPratik