log

package
v1.35.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 19, 2026 License: MIT Imports: 5 Imported by: 0

README

Log Package

The log package acts as a helpful abstraction around the slog Logger that is built into the standard library in Go.

Engineers in GitLab must use this package in order to instantiate loggers for their application to ensure that there is consistency across all of our services in how we emit logs from our systems.

Usage

// returns a new JSON logger that outputs logs to the stdout
logger := log.New()

// A standard Info line
// Note: We strongly encourage that you use the *Context methods
// for observability purposes to ensure you'll be benefiting from
// field enrichment.
logger.InfoContext(ctx, "some info")
Logger Configuration
logger := log.New(
    // log.WithWriter - allows you to pass in a custom io.Writer
    // should you wish.
    log.WithWriter(os.Stderr),

    // allows you fine-grained control over how the
    // slog handler is configured.
    log.WithHandlerOptions(&slog.HandlerOptions{
        AddSource: true,
        Level: slog.LevelDebug,
    }),

    // allows you to set the output to text format
    log.WithTextFormat(),
)
Writing to Files

If you need to write to specific files, you can achieve this like so:

f, err := os.Create("test.out")
assert.Nil(t, err)
logger := log.New(log.WithWriter(f))
logger.Info("hello")

This would create a test.out file into which your log messages would be pushed.

Testing Your Observability

The logs that our systems output represent an often-neglected part of our API. Additional reporting systems and alerts are typically built on top of log lines and a lack of testing makes these setups rather fragile in nature.

It's strongly encouraged that all engineers bake in some form of assertions on the logs that they rely on for additional observability configuration within their tests.

// NewWithRecorder returns a logRecorder struct that
// captures all log lines emitted by the `logger`
logger, logRecorder := log.NewWithRecorder()

// We can then perform assertions on things like how many log lines
// have been emitted
assert.Len(t, recorder.Records, 1)

// As well as the shape of individual log lines
assert.Equal(t, "test message", recorder.Records[0].Message)
assert.Equal(t, tt.expectedLevel, recorder.Records[0].Level.String())
assert.Contains(t, recorder.Records[0].Attrs, slog.Attr{Key: "key", Value: slog.AnyValue("value")})

These log lines are captured in a Records field which is a slice of type testRecord:

// testRecord - a representation of a single log message
type testRecord struct {
    Level   slog.Level
    Message string
    Attrs   map[string]any
}

Context Logger

There is some important information we need to emit for every log message whenever a request is processed. This could be things such as the pipeline_id or the GitLab project ID.

You can store this information within the context and it will automatically enrich subsequent log emissions with these fields. This is super handy if you need to correlate log lines together by various fields for investigatory purposes.

ctx := log.WithFields(
    slog.String(fields.GitLabUserName, "1234abc")
)

logger.InfoContext(ctx, "hello world")
// emitted log line will contain the `gl_user_name` field alongside
// "hello world" - this is imported from the `fields` package.
Canonical Logger

Canonical logging is a technique that can be used to help reduce the volume of logs being emitted from your systems. You are effectively aggregating all of the fields that you care about through the lifecycle of a request and then logging a single line at the end of the lifecycle.

// pass this logger along the request lifecycle
ctx := context.Background()
ctx = log.WithFields(ctx, slog.String("step", "1"))

// at the point at which you need to emit the
// final log line which will then include all of the
// fields that have been collected within the
// context up until this point.
logger.InfoContext(ctx, "canonical_log")

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func EnrichRecordWithMetaData

func EnrichRecordWithMetaData(ctx context.Context, r slog.Record) slog.Record

func Fields

func Fields(ctx context.Context) []slog.Attr

func New

func New() *slog.Logger

New - a handy wrapper that configures the slog.Logger in a consistent fashion. Engineers should always default to using this constructor to ensure that they can take advantage of future global enhancements to our logging setup.

func NewContextHandler

func NewContextHandler(baseHandler slog.Handler) slog.Handler

func NewWithConfig added in v1.35.0

func NewWithConfig(cfg *Config) *slog.Logger

NewWithConfig - a constructor that allows you to overwrite some of the core constructs within the Logger for your own nefarious purposes.

func WithFields

func WithFields(ctx context.Context, attrs ...slog.Attr) context.Context

WithField - provides a way to inject more fields into a logger that is then persisted in the context. This is useful in situations where they need to employ canonical logging in order to limit the number of log lines that they emit.

Types

type Config

type Config struct {
	Writer        io.Writer
	UseTextFormat bool
	Clock         TimeFunc
}

Config holds the configuration for creating a new logger.

type ContextHandler

type ContextHandler struct {
	BaseHandler slog.Handler
}

func (*ContextHandler) Enabled

func (c *ContextHandler) Enabled(ctx context.Context, level slog.Level) bool

func (*ContextHandler) Handle

func (c *ContextHandler) Handle(ctx context.Context, r slog.Record) error

func (*ContextHandler) WithAttrs

func (c *ContextHandler) WithAttrs(attrs []slog.Attr) slog.Handler

func (*ContextHandler) WithGroup

func (c *ContextHandler) WithGroup(name string) slog.Handler

type TimeFunc added in v1.35.0

type TimeFunc func() time.Time

TimeFunc - exclusively used for testing purposes please do not use in production.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL