Package slogx is a collection of extensions to Go’s structured logging package, slog.
The slogx package provides the following features:
ContextHandlerallows you to addslogattributes (slog.Attrinstances) to acontext.Context. These attributes are added to log records when the*Contextfunction variants (InfoContext,ErrorContext, etc) on the logger are used.LoggerBuilderprovides a simple way to buildslog.Loggerinstances.LevelManagerprovides a way to manageslog.LevelVarinstances from environment variables or provided LevelFunc (useful with config modules like koanf, viper, etc.).- Multiple loggers can be created with different log levels and formats. See internal/examples for more examples.
go get -u github.com/Evernorth/slogx-go
The following example demonstrates how to create a logger and log a message.
package main
import (
"github.com/Evernorth/slogx-go/slogx"
"log/slog"
"os"
)
// This gets us a slog.Logger with context support that logs in JSON format to stdout.
var (
logger, _ = slogx.NewLoggerBuilder().
WithWriter(os.Stdout).
WithFormat(slogx.FormatJSON).
WithLevel(slog.LevelInfo).
Build()
)
func main() {
logger.Info("Hello, World!")
}{"time":"2024-10-21T12:03:41.103566-04:00","level":"INFO","msg":"Hello, World!"}
The following example demonstrates how to create a logger using a string based log level.
package main
import (
"github.com/Evernorth/slogx-go/slogx"
"log/slog"
"os"
)
// This gets us a slog.Logger with context support that logs in JSON format to stdout.
var (
logLevel := os.Getenv("LOG_LEVEL")
logger, _ = slogx.NewLoggerBuilder().
WithWriter(os.Stdout).
WithFormat(slogx.FormatJSON).
WithLevelString(logLevel).
Build()
)
func main() {
logger.Info("Hello, World!")
}This will produce the same behavior as the above example, but provides a convenient alternative if you want to staticly set your log level from a string. If the string is not a valid slog log level (debug, info, warn or error, case-insensitive, it will default to info)
The following example shows how to configure the timestamp format for your logger. You must use a valid format provided by the time standard library's constants.
package main
import (
"os"
"time"
"github.com/Evernorth/slogx-go/slogx"
)
func main() {
logger, _ := slogx.NewLoggerBuilder().
WithWriter(os.Stdout).
WithFormat(slogx.FormatJSON).
WithLevelString("debug").
WithTimestampFormat(time.TimeOnly).
Build()
logger.Debug("A")
logger.Info("B")
logger.Warn("C")
logger.Error("D")
}{"time":"00:24:48","level":"DEBUG","msg":"A"}
{"time":"00:24:48","level":"INFO","msg":"B"}
{"time":"00:24:48","level":"WARN","msg":"C"}
{"time":"00:24:48","level":"ERROR","msg":"D"}
The following examples demonstrate how to create a logger with a log level that can be changed at runtime.
package main
import (
"github.com/Evernorth/slogx-go/slogx"
"log/slog"
"os"
)
// Environment variables
// These can be set to change the log level at runtime.
// The log level can be set to one of the following values: DEBUG, INFO, WARN, ERROR, FATAL, PANIC
const (
logger1LevelEnvVar = "LOGGER1_LOG_LEVEL"
logger2LevelEnvVar = "LOGGER2_LOG_LEVEL"
)
// Loggers
// This gets us a slog.Logger with context support that logs in JSON format to stdout.
var (
logger1, levelVar1 = slogx.NewLoggerBuilder().
WithWriter(os.Stdout).
WithFormat(slogx.FormatJSON).
WithLevel(slog.LevelInfo).
Build()
logger2, levelVar2 = slogx.NewLoggerBuilder().
WithWriter(os.Stdout).
WithFormat(slogx.FormatJSON).
WithLevel(slog.LevelDebug).
Build()
)
// manageLevelFromEnv Manage the log level from an environment variable with LevelManager.ManageLevelFromEnv.
func manageLevelFromEnv(logLevel string, levelVar *slog.LevelVar) {
// Log the log level
slog.Default().Info("", slog.String(logLevel, os.Getenv(logLevel)))
// Set the log level.
err := slogx.GetLevelManager().ManageLevelFromEnv(levelVar, logLevel)
if err != nil {
panic(err)
}
}
// setup Set the default level manager
func setup() {
// Enroll the levelVars with the LevelManager
manageLevelFromEnv(logger1LevelEnvVar, levelVar1)
manageLevelFromEnv(logger2LevelEnvVar, levelVar2)
// Tell the LevelManager to update the levels
slogx.GetLevelManager().UpdateLevels()
// Log that the logger has been initialized
slog.Info("Logger initialized", slog.String(logger1LevelEnvVar, levelVar1.Level().String()))
slog.Info("Logger initialized", slog.String(logger2LevelEnvVar, levelVar2.Level().String()))
}
// main This function demonstrates how to use the slogx package to create a logger to manage log levels.
// It also demonstrates how to manage the log level from an environment variable.
// It also demonstrates how to use multiple loggers with log levels.
// The logger is configured to log in JSON format to stdout with a default log level of INFO.
func main() {
setup()
// Log some test messages
// This message will not be logged because the log level is INFO.
// This can be changed by setting the environment variable LOGGER1_LOG_LEVEL to DEBUG
logger1.Debug("logger1 debug message.")
logger1.Info("logger1 info message.")
logger1.Warn("logger1 warn message.")
logger1.Error("logger1 error message.")
// Log some test messages using the 2nd logger
// This message will be logged because the log level is DEBUG.
// This can be changed by setting the environment variable LOGGER2_LOG_LEVEL to INFO
logger2.Debug("logger2 debug message.")
logger2.Info("logger2 info message.")
logger2.Warn("logger2 warn message.")
logger2.Error("logger2 error message.")
}Although very similar to the above, this example demonstrates how a LevelFunc can be used to customize the source of log level values.
package main
import (
"github.com/Evernorth/slogx-go/slogx"
"github.com/knadh/koanf/v2"
"log/slog"
"os"
)
// Property keys
// These can be set to change the log level at runtime.
// The log level can be set to one of the following values: DEBUG, INFO, WARN, ERROR, FATAL, PANIC
const (
logger1LevelKey = "logger1.log.level"
logger2LevelKey = "logger2.log.level"
)
// Loggers
// This gets us a slog.Logger with context support that logs in JSON format to stdout.
var (
logger1, levelVar1 = slogx.NewLoggerBuilder().
WithWriter(os.Stdout).
WithFormat(slogx.FormatJSON).
WithLevel(slog.LevelInfo).
Build()
logger2, levelVar2 = slogx.NewLoggerBuilder().
WithWriter(os.Stdout).
WithFormat(slogx.FormatJSON).
WithLevel(slog.LevelDebug).
Build()
// create a new koanf instance to provide the configuration
k = koanf.New(".")
)
// manageLevelFromFunc Manage the log level from a function with LevelManager.ManageLevelFromFunc.
func manageLevelFromFunc(logLevel string, levelVar *slog.LevelVar) {
// Log the log level
slog.Default().Info("", slog.String(logLevel, k.String(logLevel)))
// Set the log level, using Koanf as the LevelFunc for obtaining updated log levels.
err := slogx.GetLevelManager().ManageLevelFromFunc(levelVar, logLevel, k.String)
if err != nil {
panic(err)
}
}
// setup Set the default level manager
func setup() {
// Load Koanf config from the Providers of choice (environment, file, etc.).
loadConfig(k)
// Enroll the level keys with the LevelManager
manageLevelFromFunc(logger1LevelKey, levelVar1)
manageLevelFromFunc(logger2LevelKey, levelVar2)
// Tell the LevelManager to update the levels
slogx.GetLevelManager().UpdateLevels()
// Log that the logger has been initialized
slog.Info("Logger initialized", slog.String(logger1LevelKey, levelVar1.Level().String()))
slog.Info("Logger initialized", slog.String(logger2LevelKey, levelVar2.Level().String()))
}
// main This function demonstrates how to use the slogx package to create a logger to manage log levels.
// It also demonstrates how to manage the log level from a configuration module (Koanf, other).
// It also demonstrates how to use multiple loggers with log levels.
// The logger is configured to log in JSON format to stdout with a default log level of INFO.
func main() {
setup()
// Log some test messages
// This message will not be logged because the log level is INFO.
// This can be changed by setting the environment variable LOGGER1_LOG_LEVEL to DEBUG
logger1.Debug("logger1 debug message.")
logger1.Info("logger1 info message.")
logger1.Warn("logger1 warn message.")
logger1.Error("logger1 error message.")
// Log some test messages using the 2nd logger
// This message will be logged because the log level is DEBUG.
// This can be changed by setting the environment variable LOGGER2_LOG_LEVEL to INFO
logger2.Debug("logger2 debug message.")
logger2.Info("logger2 info message.")
logger2.Warn("logger2 warn message.")
logger2.Error("logger2 error message.")
}2024/10/21 12:05:40 INFO Logger initialized LOGGER1_LOG_LEVEL=INFO
2024/10/21 12:05:40 INFO Logger initialized LOGGER2_LOG_LEVEL=DEBUG
{"time":"2024-10-21T12:05:40.937543-04:00","level":"INFO","msg":"logger1 info message."}
{"time":"2024-10-21T12:05:40.937545-04:00","level":"WARN","msg":"logger1 warn message."}
{"time":"2024-10-21T12:05:40.937547-04:00","level":"ERROR","msg":"logger1 error message."}
{"time":"2024-10-21T12:05:40.937548-04:00","level":"DEBUG","msg":"logger2 debug message."}
{"time":"2024-10-21T12:05:40.93755-04:00","level":"INFO","msg":"logger2 info message."}
{"time":"2024-10-21T12:05:40.937551-04:00","level":"ERROR","msg":"logger2 error message."}
Create a context-aware slog.Logger, then use the logger making sure to use a Context variant function.
package main
import (
"context"
"github.com/Evernorth/slogx-go/slogx"
"log/slog"
"os"
)
// This gets us a slog.Logger with context support that logs in JSON format to stdout.
var (
logger, _ = slogx.NewLoggerBuilder().
WithWriter(os.Stdout).
WithFormat(slogx.FormatJSON).
WithLevel(slog.LevelInfo).
WithContextHandler().
Build()
)
// main This example demonstrates how to create a logger with context support that logs in JSON format to stdout.
// It also demonstrates how to log with context and attributes.
// The logger is configured to log in JSON format to stdout with a default log level of INFO.
func main() {
ctx := context.Background()
logger.InfoContext(ctx, "Hello, World! Logging with Context.")
// Create a context with some attributes
ctx = slogx.ContextWithAttrs(ctx, slog.String("test1", "val1"),
slog.String("test2", "val2"))
logger.InfoContext(ctx, "Context and some attributes")
// Create a context with some more attributes
ctx = slogx.ContextWithAttrs(ctx, slog.String("test3", "val3"))
logger.InfoContext(ctx, "Context and some more attributes")
// Create a context with updated attributes
ctx = slogx.ContextWithAttrs(ctx, slog.String("test1", "new-val1"))
logger.InfoContext(ctx, "Context and update attributes")
}{"time":"2024-10-21T12:09:44.301872-04:00","level":"INFO","msg":"Hello, World! Logging with Context."}
{"time":"2024-10-21T12:09:44.302091-04:00","level":"INFO","msg":"Context and some attributes","test1":"val1","test2":"val2"}
{"time":"2024-10-21T12:09:44.302095-04:00","level":"INFO","msg":"Context and some more attributes","test1":"val1","test2":"val2","test3":"val3"}
{"time":"2024-10-21T12:09:44.302098-04:00","level":"INFO","msg":"Context and update attributes","test1":"new-val1","test2":"val2","test3":"val3"}
See the go.mod file.
If you have questions, concerns, bug reports, etc. See CONTRIBUTING.
slogx is open source software released under the Apache 2.0 license.
- Steve Sefton, Evernorth
- Shellee Stewart, Evernorth
- Neil Powell, Evernorth