Documentation ¶
Overview ¶
Package logging is an opinionated structured logging library based on log/slog.
This package also aliases most top-level functions in log/slog to reduce the need to manage the additional import.
Index ¶
- Constants
- func DefaultLogger() *slog.Logger
- func FormatNames() []string
- func FromContext(ctx context.Context) *slog.Logger
- func GRPCStreamingInterceptor(inLogger *slog.Logger, projectID string) grpc.StreamClientInterceptor
- func GRPCUnaryInterceptor(inLogger *slog.Logger, projectID string) grpc.UnaryServerInterceptor
- func HTTPInterceptor(inLogger *slog.Logger, projectID string) func(http.Handler) http.Handler
- func LevelNames() []string
- func LevelSlogValue(l slog.Level) slog.Value
- func LevelString(l slog.Level) string
- func LookupLevel(name string) (slog.Level, error)
- func New(w io.Writer, level slog.Level, format Format, debug bool) *slog.Logger
- func NewFromEnv(envPrefix string) *slog.Logger
- func SetLevel(logger *slog.Logger, level slog.Level) *slog.Logger
- func TestLogger(tb testing.TB) *slog.Logger
- func WithLogger(ctx context.Context, logger *slog.Logger) context.Context
- type Format
- type LevelHandler
- func (h *LevelHandler) Enabled(_ context.Context, level slog.Level) bool
- func (h *LevelHandler) Handle(ctx context.Context, r slog.Record) error
- func (h *LevelHandler) Handler() slog.Handler
- func (h *LevelHandler) SetLevel(level slog.Level)
- func (h *LevelHandler) WithAttrs(attrs []slog.Attr) slog.Handler
- func (h *LevelHandler) WithGroup(name string) slog.Handler
- type LevelableHandler
Examples ¶
Constants ¶
const ( FormatJSON = Format("JSON") FormatText = Format("TEXT") )
Variables ¶
This section is empty.
Functions ¶
func DefaultLogger ¶ added in v0.7.0
DefaultLogger creates a default logger.
Example ¶
package main import ( "log/slog" "github.com/abcxyz/pkg/logging" ) var logger *slog.Logger func main() { logger = logging.DefaultLogger() }
Output:
func FormatNames ¶ added in v0.7.0
func FormatNames() []string
FormatNames returns the list of all log format names.
func FromContext ¶
FromContext returns the logger stored in the context. If no such logger exists, a default logger is returned.
Example ¶
package main import ( "context" "log/slog" "os" "github.com/abcxyz/pkg/logging" ) var logger *slog.Logger func main() { ctx := context.Background() logger = logging.New(os.Stdout, slog.LevelDebug, logging.FormatText, true) ctx = logging.WithLogger(ctx, logger) logger = logging.FromContext(ctx) // same logger }
Output:
func GRPCStreamingInterceptor ¶ added in v0.1.2
func GRPCStreamingInterceptor(inLogger *slog.Logger, projectID string) grpc.StreamClientInterceptor
GRPCStreamingInterceptor returns client-side a gRPC streaming interceptor that populates a logger with trace data in the context.
func GRPCUnaryInterceptor ¶ added in v0.1.2
func GRPCUnaryInterceptor(inLogger *slog.Logger, projectID string) grpc.UnaryServerInterceptor
GRPCUnaryInterceptor returns a server-side gRPC unary interceptor that populates a logger with trace data in the context.
func HTTPInterceptor ¶ added in v0.1.2
HTTPInterceptor returns an HTTP middleware that populates a logger with trace data onto the incoming and outgoing http.Request context.
func LevelNames ¶ added in v0.7.0
func LevelNames() []string
LevelNames returns the list of all log level names.
func LevelSlogValue ¶ added in v0.7.0
LevelSlogValue returns the slog.Value representation of the level.
func LevelString ¶ added in v0.7.0
LevelString returns the string representation of the given level. Note this is different from calling String() on the Level, which uses the slog implementation.
func LookupLevel ¶ added in v0.7.0
LookupLevel attempts to get the level that corresponds to the given name. If no such level exists, it returns an error. If the empty string is given, it returns Info level.
func New ¶ added in v0.7.0
New creates a new logger in the specified format and writes to the provided writer at the provided level. Use the returned leveler to dynamically change the level to a different value after creation.
If debug is true, the logging level is set to the lowest possible value (meaning all messages will be printed), and the output will include source information. This is very expensive, and you should not enable it unless actively debugging.
It returns the configured logger and a leveler which can be used to change the logger's level dynamically. The leveler does not require locking to change the level.
Example ¶
package main import ( "bytes" "log/slog" "github.com/abcxyz/pkg/logging" ) var logger *slog.Logger func main() { // Write to a buffer instead of stdout var b bytes.Buffer logger = logging.New(&b, slog.LevelInfo, logging.FormatJSON, false) }
Output:
func NewFromEnv ¶
NewFromEnv is a convenience function for creating a logger that is configured from the environment. It sources the following environment variables, optionally prefixed with the given prefix:
- LOG_LEVEL: string representation of the log level. It panics if no such log level exists.
- LOG_FORMAT: format in which to output logs (e.g. json, text). It panics if no such format exists.
- LOG_DEBUG: enable the most detailed debug logging. It panics iff the given value is not a valid boolean.
Example ¶
package main import ( "log/slog" "github.com/abcxyz/pkg/logging" ) var logger *slog.Logger func main() { logger = logging.NewFromEnv("MY_APP_") }
Output:
Example (SetLevel) ¶
package main import ( "log/slog" "github.com/abcxyz/pkg/logging" ) var logger *slog.Logger func main() { logger = logging.SetLevel(logging.NewFromEnv("MY_APP_"), slog.LevelWarn) }
Output:
func SetLevel ¶ added in v0.7.0
SetLevel adjusts the level on the provided logger. The handler on the given logger must be a LevelableHandler or else this function panics. If you created a logger through this package, it will automatically satisfy that interface.
This function is safe for concurrent use.
It returns the provided logger for convenience and easier chaining.
Example ¶
package main import ( "log/slog" "github.com/abcxyz/pkg/logging" ) var myLogger = logging.DefaultLogger() func main() { logging.SetLevel(myLogger, slog.LevelDebug) // level is now debug }
Output:
Example (Safe) ¶
package main import ( "log/slog" "github.com/abcxyz/pkg/logging" ) var myLogger = logging.DefaultLogger() func main() { // This example demonstrates the totally safe way to set a level, assuming you // don't know if the logger is capable of changing levels dynamically. typ, ok := myLogger.Handler().(logging.LevelableHandler) if !ok { // not capable of setting levels } typ.SetLevel(slog.LevelDebug) // level is now debug }
Output:
func TestLogger ¶
TestLogger creates a new logger for use in tests. It will only log messages when tests fail and the tests were run with verbose (-v).
Example ¶
_ = func(t *testing.T) { // func TestMyThing(t *testing.T) logger = logging.TestLogger(t) }
Output:
Example (Context) ¶
package main import ( "context" "testing" "github.com/abcxyz/pkg/logging" ) func main() { _ = func(t *testing.T) { // func TestMyThing(t *testing.T) // Most tests rely on the logger in the context, so here's a fast way to // inject a test logger into the context. ctx := logging.WithLogger(context.Background(), logging.TestLogger(t)) // Use ctx in tests. Anything that extracts a logger from the context will // get the test logger now. _ = ctx } }
Output:
func WithLogger ¶
WithLogger creates a new context with the provided logger attached.
Example ¶
package main import ( "context" "log/slog" "os" "github.com/abcxyz/pkg/logging" ) var logger *slog.Logger func main() { ctx := context.Background() logger = logging.New(os.Stdout, slog.LevelDebug, logging.FormatText, true) ctx = logging.WithLogger(ctx, logger) logger = logging.FromContext(ctx) // same logger }
Output:
Types ¶
type Format ¶ added in v0.7.0
type Format string
Format represents the logging format.
func LookupFormat ¶ added in v0.7.0
LookupFormat attempts to get the formatter that corresponds to the given name. If no such formatter exists, it returns an error. If the empty string is given, it returns the JSON formatter.
type LevelHandler ¶ added in v0.7.0
type LevelHandler struct {
// contains filtered or unexported fields
}
LevelHandler is a wrapper around a LevelHandler that gives us the ability to configure level at runtime without users needing to manage a separate LevelVar.
func NewLevelHandler ¶ added in v0.7.0
func NewLevelHandler(leveler slog.Leveler, h slog.Handler) *LevelHandler
NewLevelHandler creates a new handler that is capable of dynamically setting a level in a concurrency-safe way.
func (*LevelHandler) Enabled ¶ added in v0.7.0
Enabled implements Handler.Enabled by reporting whether level is at least as large as h's level.
func (*LevelHandler) Handler ¶ added in v0.7.0
func (h *LevelHandler) Handler() slog.Handler
Handler returns the Handler wrapped by h.
func (*LevelHandler) SetLevel ¶ added in v0.7.0
func (h *LevelHandler) SetLevel(level slog.Level)
SetLevel implements the levelable interface. It adjusts the level of the logger. It is safe for concurrent use.
type LevelableHandler ¶ added in v0.7.0
type LevelableHandler interface { // SetLevel dynamically sets the level on the handler. SetLevel(level slog.Level) }
LevelableHandler is an interface which defines a handler that is able to dynamically set its level.