tegola icon indicating copy to clipboard operation
tegola copied to clipboard

Use slog as default and only logger

Open iwpnd opened this issue 10 months ago • 4 comments

Heya,

as discussed in #1032 and slack I would like to tackle the refactor from text based standard logger and zap structured logger to a single logger around golangs slog with the goal to simplify logging in Tegola, and moving logging closer to the standard libraries.

Status quo

  • The old implementation uses global variables (e.g., logger, level, IsError, etc.) and manual flag management for log level checks
  • even though we log structured logs, we do not use structured logging, we put a message in a structured log, that's it.

This approach was necessary 5 years ago, but fell out of time.

Migration stages

Stage 1

  • drop zap and std logger in favour of slog
  • add a tracelog to every Error log for easier debugging. We achieve this with a custom log handler that adds a stacktrace field and populates it. The custom handler will be passed to slog.SetDefault() and will become the global logger.
  • use slog in log.Info,log.Infof (...) to keep compatibility and reduce the changes in stage 1 to a minimum
  • follow slogs approach of Info, Debug, Warn and Error to keep things simple
  • Drop Fatal(f). Fatal(f) is really only an Error(f) with an os.Exit(1). The os.Exit(1) should be explicit, not implicitly hidden in a fatal log.
  • Drop Trace, it's not being used anyways
  • logs will go to os.Stderr instead of os.Stdout, use one output for simplicity.

Stage 2

  • drop log.Debug, log.Infof and the likes
  • modules will either import and use slog.Default(), that at this point is out custom logger,
  • or they receive the logger via dependency injection.
  • Module-specific loggers can be derived by adding context using With or WithGroup.

Can we agree on this? :)

iwpnd avatar Mar 16 '25 16:03 iwpnd

I'm 100% for this! Thank you!

gdey avatar Mar 17 '25 02:03 gdey

@iwpnd I also support this! And thank you for putting momentum behind this update.

even though we log structured logs, we do not use structured logging, we put a message in a structured log, that's it.

I agree with this point. One problem I find when implementing structured logging is that the "keys" are littered throughout the codebase in random places. An idea as we go through this transition:

  • Let's add a logging.go file to each package that implements structured logging.
  • In the logging.go file we define const for each log "key". For example:
package foo

const (
  logKeyRequestID = "request_id"
  logKeyRequestMapName = "map_name"
)

This would help drive consistency in the package as well as give us a single file to start investigating the package's logging structure. We could also expand what's in the logging.go file, but a minimum I think it would be good to define the log keys.

ARolek avatar Mar 18 '25 02:03 ARolek

That would also allow us to have a single logger per package, instead of a global logger. That logger could have predefined default fields such as {“provider”:”“mvt_postgis“}.

iwpnd avatar Mar 18 '25 07:03 iwpnd

@iwpnd yes, excellent point. We could use this same file to define our default grouping for the package.

ARolek avatar Mar 18 '25 16:03 ARolek