logger API

logger

package

API reference for the logger package.

S
struct

clefEntry

clefEntry is the JSON structure for a Compact Log Event Format (CLEF) line.
Fields are flattened at root level; @l is omitted for Information.

pkg/logger/clef_sink.go:20-24
type clefEntry struct

Fields

Name Type Description
Timestamp time.Time json:"@t"
Level string json:"@l,omitempty"
Message string json:"@m"
S
struct
Implements: Sink

CLEFSink

CLEFSink writes log entries as CLEF-compatible JSON lines.
Each line is a single JSON object with @t, @l (omitted for Information),
@m, and all structured fields flattened at the root level, matching the
format emitted by Serilog’s RenderedCompactJsonFormatter, so that Go and
C# service logs are queryable with the same field selectors in Grafana/Loki.

pkg/logger/clef_sink.go:31-33
type CLEFSink struct

Methods

Log
Method

Log writes e as a CLEF JSON line to the underlying writer.

Parameters

e Entry

Returns

error
func (*CLEFSink) Log(e Entry) error
{
	// Build a flat map so structured fields sit at the root level.
	m := make(map[string]any, len(e.Fields)+3)
	for k, v := range e.Fields {
		m[k] = v
	}

	m["@t"] = e.Time.UTC().Format(time.RFC3339Nano)
	m["@m"] = e.Msg

	// @l is omitted for Information per the CLEF spec.
	if lvl, ok := clefLevel[e.Level]; ok {
		m["@l"] = lvl
	}

	b, err := json.Marshal(m)
	if err != nil {
		return err
	}
	_, err = c.w.Write(append(b, '\n'))
	return err
}

Fields

Name Type Description
w io.Writer
F
function

NewCLEFSink

NewCLEFSink constructs a CLEFSink. When w is nil, os.Stdout is used.

Parameters

Returns

pkg/logger/clef_sink.go:36-41
func NewCLEFSink(w io.Writer) *CLEFSink

{
	if w == nil {
		w = os.Stdout
	}
	return &CLEFSink{w: w}
}
T
type

Level

Level represents log severity.

pkg/logger/logger.go:13-13
type Level int
S
struct

Field

Field is a single structured key/value pair.

pkg/logger/logger.go:48-51
type Field struct

Fields

Name Type Description
Key string json:"key"
Value interface{} json:"value"
S
struct

Entry

Entry is the log payload passed to sinks.

pkg/logger/logger.go:54-61
type Entry struct

Fields

Name Type Description
Level string json:"level"
Time time.Time json:"time"
Msg string json:"msg"
Fields map[string]interface{} json:"fields,omitempty"
TraceID string json:"trace_id,omitempty"
SpanID string json:"span_id,omitempty"
I
interface

Sink

Sink receives log entries for processing.

pkg/logger/logger.go:64-66
type Sink interface

Methods

Log
Method

Parameters

e Entry

Returns

error
func Log(...)
I
interface

Logger

Logger is the public logging contract.

pkg/logger/logger.go:69-77
type Logger interface

Methods

With
Method

Parameters

fields ...Field

Returns

func With(...)
Debug
Method

Parameters

msg string
fields ...Field
func Debug(...)
Info
Method

Parameters

msg string
fields ...Field
func Info(...)
Warn
Method

Parameters

msg string
fields ...Field
func Warn(...)
Error
Method

Parameters

msg string
fields ...Field
func Error(...)
RegisterSink
Method

Parameters

s Sink
func RegisterSink(...)
SetLevel
Method

Parameters

l Level
func SetLevel(...)
T
type

Option

Option configures the concrete logger on creation.

pkg/logger/logger.go:80-80
type Option func(*stdLogger)
S
struct

stdLogger

pkg/logger/logger.go:82-91
type stdLogger struct

Methods

processAsync
Method
func (*stdLogger) processAsync()
{
	defer l.wg.Done()
	for e := range l.ch {
		l.mu.RLock()
		sinks := l.sinks
		l.mu.RUnlock()
		for _, sink := range sinks {
			_ = sink.Log(e)
		}
	}
}
RegisterSink
Method

Parameters

s Sink
func (*stdLogger) RegisterSink(s Sink)
{
	l.mu.Lock()
	defer l.mu.Unlock()
	l.sinks = append(l.sinks, s)
}
SetLevel
Method

SetLevel changes the log level at runtime.

Parameters

level Level
func (*stdLogger) SetLevel(level Level)
{
	l.mu.Lock()
	defer l.mu.Unlock()
	l.level = level
}
With
Method

With returns a derived logger that shares sinks but has extra bound fields.

Parameters

fields ...Field

Returns

func (*stdLogger) With(fields ...Field) Logger
{
	l.mu.RLock()
	defer l.mu.RUnlock()

	nextFields := make(map[string]interface{}, len(l.fields)+len(fields))
	for k, v := range l.fields {
		nextFields[k] = v
	}
	for _, f := range fields {
		nextFields[f.Key] = f.Value
	}

	child := &stdLogger{
		sinks:  append([]Sink(nil), l.sinks...),
		level:  l.level,
		fields: nextFields,
		ctx:    l.ctx,
		async:  l.async,
		ch:     l.ch,
	}
	return child
}
shouldLog
Method

shouldLog reports whether the given level meets the logger's minimum threshold.

Parameters

level Level

Returns

bool
func (*stdLogger) shouldLog(level Level) bool
{
	l.mu.RLock()
	defer l.mu.RUnlock()
	return level >= l.level
}
log
Method

log constructs an Entry and dispatches it to all registered sinks.

Parameters

level Level
msg string
fields ...Field
func (*stdLogger) log(level Level, msg string, fields ...Field)
{
	if !l.shouldLog(level) {
		return
	}

	entry := Entry{
		Level: level.String(),
		Time:  time.Now().UTC(),
		Msg:   msg,
		Fields: map[string]interface{}{},
	}

	l.mu.RLock()
	for k, v := range l.fields {
		entry.Fields[k] = v
	}
	sinks := append([]Sink(nil), l.sinks...)
	ctx := l.ctx
	l.mu.RUnlock()

	if ctx != nil {
		if tid, ok := ctx.Value("trace_id").(string); ok {
			entry.TraceID = tid
		}
		if sid, ok := ctx.Value("span_id").(string); ok {
			entry.SpanID = sid
		}
	}

	for _, f := range fields {
		entry.Fields[f.Key] = f.Value
	}

	if l.async {
		select {
		case l.ch <- entry:
		default:
		}
		return
	}

	for _, sink := range sinks {
		_ = sink.Log(entry)
	}
}
Debug
Method

Debug logs at debug level.

Parameters

msg string
fields ...Field
func (*stdLogger) Debug(msg string, fields ...Field)
{ l.log(DebugLevel, msg, fields...) }
Info
Method

Info logs at info level.

Parameters

msg string
fields ...Field
func (*stdLogger) Info(msg string, fields ...Field)
{ l.log(InfoLevel, msg, fields...) }
Warn
Method

Warn logs at warn level.

Parameters

msg string
fields ...Field
func (*stdLogger) Warn(msg string, fields ...Field)
{ l.log(WarnLevel, msg, fields...) }
Error
Method

Error logs at error level.

Parameters

msg string
fields ...Field
func (*stdLogger) Error(msg string, fields ...Field)
{ l.log(ErrorLevel, msg, fields...) }

Fields

Name Type Description
mu sync.RWMutex
sinks []Sink
level Level
fields map[string]interface{}
ctx context.Context
async bool
ch chan Entry
wg sync.WaitGroup
F
function

New

New constructs a logger with optional options.

Parameters

opts
...Option

Returns

pkg/logger/logger.go:103-113
func New(opts ...Option) Logger

{
	l := &stdLogger{
		level:  InfoLevel,
		fields: map[string]interface{}{},
		sinks:  []Sink{NewConsoleSink(nil)},
	}
	for _, o := range opts {
		o(l)
	}
	return l
}

Example

log := logger.New(
	logger.WithLevel(logger.DebugLevel),
	logger.WithoutDefaultSink(),
	logger.WithSink(mySink),
)
log.Info("started", logger.Field{Key: "version", Value: "1.0"})
F
function

WithLevel

WithLevel sets the minimum level for emitted logs.

Parameters

level

Returns

pkg/logger/logger.go:116-118
func WithLevel(level Level) Option

{
	return func(l *stdLogger) { l.level = level }
}
F
function

WithSink

WithSink adds an initial sink.

Parameters

s

Returns

pkg/logger/logger.go:121-123
func WithSink(s Sink) Option

{
	return func(l *stdLogger) { l.sinks = append(l.sinks, s) }
}
F
function

WithoutDefaultSink

WithoutDefaultSink removes the default ConsoleSink added by New.
Use before WithSink to create a logger with only custom sinks:

logger.New(logger.WithoutDefaultSink(), logger.WithSink(clefSink))

Returns

pkg/logger/logger.go:129-131
func WithoutDefaultSink() Option

{
	return func(l *stdLogger) { l.sinks = nil }
}
F
function

WithFields

WithFields binds fields to the logger returned from New.

Parameters

fields
...Field

Returns

pkg/logger/logger.go:134-140
func WithFields(fields ...Field) Option

{
	return func(l *stdLogger) {
		for _, f := range fields {
			l.fields[f.Key] = f.Value
		}
	}
}
F
function

WithAsync

WithAsync enables asynchronous logging with a buffered channel
of the specified size.

Parameters

bufSize
int

Returns

pkg/logger/logger.go:144-151
func WithAsync(bufSize int) Option

{
	return func(l *stdLogger) {
		l.async = true
		l.ch = make(chan Entry, bufSize)
		l.wg.Add(1)
		go l.processAsync()
	}
}
F
function

WithContext

WithContext binds a context to the logger, allowing sinks
to extract trace/span IDs for distributed tracing.

Parameters

Returns

pkg/logger/logger.go:167-169
func WithContext(ctx context.Context) Option

{
	return func(l *stdLogger) { l.ctx = ctx }
}
F
function

RegisterSink

RegisterSink adds a sink at runtime.

Parameters

l
s
pkg/logger/logger.go:172-178
func RegisterSink(l Logger, s Sink)

{
	if sl, ok := l.(*stdLogger); ok {
		sl.mu.Lock()
		defer sl.mu.Unlock()
		sl.sinks = append(sl.sinks, s)
	}
}
S
struct
Implements: Sink

ConsoleSink

ConsoleSink writes entries as compact JSON lines to an io.Writer.

pkg/logger/logger.go:281-283
type ConsoleSink struct

Methods

Log
Method

Log writes a structured entry to the underlying writer.

Parameters

e Entry

Returns

error
func (*ConsoleSink) Log(e Entry) error
{
	b, err := json.Marshal(e)
	if err != nil {
		return err
	}
	_, err = c.w.Write(append(b, '\n'))
	return err
}

Fields

Name Type Description
w io.Writer
F
function

NewConsoleSink

NewConsoleSink constructs a ConsoleSink.

Parameters

Returns

pkg/logger/logger.go:286-291
func NewConsoleSink(w io.Writer) *ConsoleSink

{
	if w == nil {
		w = os.Stdout
	}
	return &ConsoleSink{w: w}
}