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

feat(zerolog): Add default log level helpers #26

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

javorszky
Copy link
Contributor

@javorszky javorszky commented Feb 22, 2023

Closes #25

I've tried a number of different approaches, but I think every single approach is just too much work and too much indirection for them to exist in a separate module.

It does not cut down on the amount of code, it makes the initialization of services more complex, the developers need to keep in mind and remember the environment variable names and how they work, how the kit is configured. All in all I don't think it's of sufficient benefit that it should be abstracted away.

Problem definition

Per the conversation on threads, the wish is to have a unified way of setting the logger to a specific level based on an environment variable.

As context:

  • each service already has their own configuration structs and configuration resolution that they need for startup
  • each service already has the loggers being instantiated in the services themselves mostly because the loggers need to have metadata, or key-value pairs attached to them

An example to the latter as a minimum setup

func main() {
    zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
    l := zerolog.New(os.Stderr).With().
        Timestamp().
        Str("service", "builder").
        Str("version", "v1.1.1").
        Str("sha", "acab1312").
        Logger()

    // rest of the service
}

This code only runs once every time a service starts up. Of this the parts that aren't service specific are

  • it needs a timestamp
  • it should be of unix format
  • it should go to os.Stderr (maybe?)

Possible solutions?

As an experiment I extracted all that into a Baseline function. To use that here's what the service needs to do:

import "github.com/suborbital/go-kit/loglevel"

func main() {
    l := loglevel.Baseline("BUILDER_")

    l = l.With().
        Str("service", "builder").
        Str("version", "v1.1.1").
        Str("sha", "acab1312").
        Logger()

    // rest of the service
}

It does not cut down on lines of code, it hides implementation which makes figuring out what's happening harder than necessary to do. On the other hand it adds another dependency that we need, and it does not remove dependencies that we already have.

You also don't really know what comes out of Baseline, and it takes a lot more hops to figure out what the log level depends on, what its current value is. It's opaque.

The PR also includes a bunch of other experiments, but in all cases the settings achieved in zerolog can be done in fewer lines with greater accuracy and precision directly than hiding it behind a kit function / module.

Personally I advocate for dealing with setting log levels in the services directly by using their already existing config structs and dedicating 3 lines in the setup code in all 4 places this is currently needed.

Marked the PR as draft because I do not have the intention of merging it in with current context. I am open to be persuaded if the problem definition warrants abstraction. I don't think the current one does.

@cohix
Copy link

cohix commented Feb 23, 2023

I was hoping for something along the lines of this:

logLevel := gokit.LogLevelFromEnv("PREFIX_")

zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
    l := zerolog.New(os.Stderr).With().
        Timestamp().
        Str("service", "builder").
        Str("version", "v1.1.1").
        Str("sha", "acab1312").
        Logger().Level(logLevel)

So that on any service we maintain, I can set PREFIX_LOG_LEVEL={something} and know that for every logger and local-logger, it will adhere to that minimum log level. This is something we use all the time in debugging to make one service or another louder or quieter.

All this helper needs to do is allow me to avoid copying the envconfig/lookupper/whatever code among services and have a common behaviour among all our software.

@javorszky
Copy link
Contributor Author

All this helper needs to do is allow me to avoid copying the envconfig/lookupper/whatever code among services and have a common behaviour among all our software.

The services already have envconfig/lookuper/whatever code inside when they do their own config's parsing. The PREFIX_LOG_LEVEL={something} can be part of the service configs with a default, and we can use that with zerolog.SetGlobalLogLevel(valueOfConfig).

I still think involving gokit for this is unnecessary. I can do it, it's not a hill I'm willing to die on, but I also want to stress that using the config of the service and calling zerolog's global log level directly is less effort than having a separate package in gokit, doing config parsing again, and calling zerolog's global log level behind the curtains.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add helper to restric the log levels based on env variable
2 participants