Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Specify log level by parameter #1084

Closed
adrianlungu opened this issue Apr 21, 2022 · 6 comments · Fixed by #1118
Closed

Specify log level by parameter #1084

adrianlungu opened this issue Apr 21, 2022 · 6 comments · Fixed by #1118

Comments

@adrianlungu
Copy link

Hello!

Would it be possible to have something like the following added to the logger ?

func (log *Logger) Log(level zapcore.Level, msg string, fields ...Field) {
	if ce := log.check(level, msg); ce != nil {
		ce.Write(fields...)
	}
}

this would allow anyone to also make dynamic calls i.e. log.Log(ErrorLevel, "message", fields...).

Thanks!

@mway
Copy link
Member

mway commented Apr 21, 2022

Hey @adrianlungu, thanks for the suggestion! Could you give some more detail about the use case you're trying to solve for?

@adrianlungu
Copy link
Author

adrianlungu commented Apr 21, 2022

Hey @mway ,

We use zap in a router middleware and currently compute a zapcore.Level based on the statusCode, i.e.

func DefaultLogLevel(status int) zapcore.Level {
	switch {
	case status >= 500:
		return zapcore.ErrorLevel
	case status >= 400:
		return zapcore.WarnLevel
	default:
		return zapcore.InfoLevel
	}
}

This allows us to use different levels based on the status code without having to switch between different logger functions or loggers.

Here is an example of where we use this:
airtame/echozap@02b10b9

@prashantv
Copy link
Collaborator

It is possible to use logger.Check today which would be similar:

logger.Check(level, "message").Write(fields...)

The CheckedEntry.Write will no-op on a nil entry (e.g., if that level shouldn't be logged):
https://github.com/uber-go/zap/blob/v1.21.0/zapcore/entry.go#L202

For performance reasons, it's recommended to check the returned entry before writing (avoids passing the varargs fields unnecessarily):

if ce := logger.Check(level, "message"); ce != nil {
  ce.Write(fields...)
}

That said, i think adding Log could be helpful for discovery and readability:

logger.Log(level, "message", fields...)

@adrianlungu
Copy link
Author

adrianlungu commented Apr 21, 2022

@prashantv yes, that is what we currently use, i.e.

func logWithLevel(logger *zap.Logger, level zapcore.Level, msg string, fields ...zapcore.Field) {
	if ce := logger.Check(level, msg); ce != nil {
		ce.Write(fields...)
	}
}

@adrianlungu
Copy link
Author

Having

logger.Log(level, "message", fields...)

Also means that functions such as

func (log *Logger) Info(msg string, fields ...Field) {
	if ce := log.check(InfoLevel, msg); ce != nil {
		ce.Write(fields...)
	}
}

could be written as

func (log *Logger) Info(msg string, fields ...Field) {
	log.Log(InfoLevel, msg, fields)
}

although I wouldn't say it's a change that brings that much benefit

@mway
Copy link
Member

mway commented Apr 21, 2022

The calls would likely be inlined, so that would just result in code deduplication which is always nice.

Edit: Worth noting that if we were to reuse this internally, we would need to be careful not to break the caller skip for stack traces. (Even with mid-stack inlining, all inline points are treated as logical stack frames and are still reported by the runtime.)

abhinav pushed a commit that referenced this issue Jun 22, 2022
Adds a Logger.Log method which logs a message and fields at the
provided level.

    log.Log(zap.InfoLevel, msg, fields...)
    // is the same as
    log.Info(msg, fields...)

Resolve #1084
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging a pull request may close this issue.

4 participants