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:12-12
type Level int
S
struct

Field

Field is a single structured key/value pair.

pkg/logger/logger.go:39-42
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:45-50
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"
I
interface

Sink

Sink receives fully composed log entries.

pkg/logger/logger.go:53-55
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:58-66
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:69-69
type Option func(*stdLogger)
S
struct

stdLogger

stdLogger is a simple, thread-safe structured logger with pluggable sinks.

pkg/logger/logger.go:72-77
type stdLogger struct

Methods

RegisterSink
Method

RegisterSink adds a sink at runtime.

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
	}

	return &stdLogger{
		sinks:  l.sinks,
		level:  l.level,
		fields: nextFields,
	}
}
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...)
	l.mu.RUnlock()

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

	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{}
F
function

New

New constructs a logger with optional options.

Parameters

opts
...Option

Returns

pkg/logger/logger.go:89-99
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:102-104
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:107-109
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:115-117
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:120-126
func WithFields(fields ...Field) Option

{
	return func(l *stdLogger) {
		for _, f := range fields {
			l.fields[f.Key] = f.Value
		}
	}
}
S
struct
Implements: Sink

ConsoleSink

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

pkg/logger/logger.go:211-213
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:216-221
func NewConsoleSink(w io.Writer) *ConsoleSink

{
	if w == nil {
		w = os.Stdout
	}
	return &ConsoleSink{w: w}
}
S
struct
Implements: Sink

PrometheusSink

PrometheusSink exposes simple counters grouped by log level.

pkg/logger/prometheus_sink.go:10-14
type PrometheusSink struct

Methods

Handler
Method

Handler returns an HTTP handler serving a basic Prometheus text exposition.

Returns

func (*PrometheusSink) Handler() http.Handler
{
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		p.mu.Lock()
		defer p.mu.Unlock()

		w.Header().Set("Content-Type", "text/plain; version=0.0.4")
		for level, value := range p.counters {
			_, _ = fmt.Fprintf(w, "go_logger_logs_total{level=\"%s\"} %d\n", level, value)
		}
	})
}
Log
Method

Log increments the counter for the provided entry level when it passes the threshold.

Parameters

e Entry

Returns

error
func (*PrometheusSink) Log(e Entry) error
{
	if levelFromString(e.Level) < p.minLevel {
		return nil
	}

	p.mu.Lock()
	defer p.mu.Unlock()
	p.counters[e.Level]++
	return nil
}

Fields

Name Type Description
mu sync.Mutex
counters map[string]int64
minLevel Level
F
function

NewPrometheusSink

NewPrometheusSink creates a Prometheus-compatible metrics sink.

Parameters

minLevel
namespace
string

Returns

pkg/logger/prometheus_sink.go:17-20
func NewPrometheusSink(minLevel Level, namespace string) *PrometheusSink

{
	_ = namespace
	return &PrometheusSink{counters: make(map[string]int64), minLevel: minLevel}
}
S
struct

RotatingFileOptions

RotatingFileOptions configures file rotation behavior.

pkg/logger/rotating_file_sink.go:11-17
type RotatingFileOptions struct

Fields

Name Type Description
MaxSizeMB int
MaxBackups int
MaxAgeDays int
Compress bool
LocalTime bool
S
struct
Implements: Sink

RotatingFileSink

RotatingFileSink writes JSON log lines to a rolling file.

pkg/logger/rotating_file_sink.go:20-22
type RotatingFileSink struct

Methods

Log
Method

Log writes a structured entry to the rolling log file.

Parameters

e Entry

Returns

error
func (*RotatingFileSink) Log(e Entry) error
{
	payload, err := json.Marshal(e)
	if err != nil {
		return err
	}

	_, err = r.writer.Write(append(payload, '\n'))
	return err
}
Rotate
Method

Rotate forces the underlying writer to rotate the active log file.

Returns

error
func (*RotatingFileSink) Rotate() error
{
	return r.writer.Rotate()
}
Close
Method

Close closes the underlying rotating log writer.

Returns

error
func (*RotatingFileSink) Close() error
{
	return r.writer.Close()
}

Fields

Name Type Description
writer *lumberjack.Logger
F
function

NewRotatingFileSink

NewRotatingFileSink creates a sink backed by a rolling log file.

Parameters

path
string

Returns

pkg/logger/rotating_file_sink.go:25-44
func NewRotatingFileSink(path string, opts RotatingFileOptions) (*RotatingFileSink, error)

{
	if path == "" {
		return nil, errors.New("logger: rotating file path is required")
	}

	if opts.MaxSizeMB <= 0 {
		opts.MaxSizeMB = 10
	}

	return &RotatingFileSink{
		writer: &lumberjack.Logger{
			Filename:   path,
			MaxSize:    opts.MaxSizeMB,
			MaxBackups: opts.MaxBackups,
			MaxAge:     opts.MaxAgeDays,
			Compress:   opts.Compress,
			LocalTime:  opts.LocalTime,
		},
	}, nil
}
S
struct
Implements: Sink

TelegramSink

TelegramSink posts selected log entries to a Telegram chat.

pkg/logger/telegram_sink.go:15-20
type TelegramSink struct

Methods

Log
Method

Log forwards the entry to Telegram when it passes the configured level threshold.

Parameters

e Entry

Returns

error
func (*TelegramSink) Log(e Entry) error
{
	if levelFromString(e.Level) < t.minLevel {
		return nil
	}

	fields, err := json.Marshal(e.Fields)
	if err != nil {
		return err
	}

	var body bytes.Buffer
	body.WriteString("[")
	body.WriteString(e.Level)
	body.WriteString("] ")
	body.WriteString(e.Msg)
	body.WriteString("\ntime: ")
	body.WriteString(e.Time.Format(time.RFC3339))
	if len(fields) > 0 {
		body.WriteString("\nfields: ")
		body.Write(fields)
	}

	apiURL := "https://api.telegram.org/bot" + url.PathEscape(t.botToken) + "/sendMessage"
	form := url.Values{}
	form.Set("chat_id", t.chatID)
	form.Set("text", body.String())

	resp, err := t.client.PostForm(apiURL, form)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
		return fmt.Errorf("telegram sink: unexpected status %d", resp.StatusCode)
	}
	return nil
}

Fields

Name Type Description
botToken string
chatID string
minLevel Level
client *http.Client
F
function

NewTelegramSink

NewTelegramSink constructs a Telegram sink.

Parameters

botToken
string
chatID
string
minLevel

Returns

error
pkg/logger/telegram_sink.go:23-33
func NewTelegramSink(botToken, chatID string, minLevel Level) (*TelegramSink, error)

{
	if botToken == "" || chatID == "" {
		return nil, errors.New("botToken and chatID required")
	}
	return &TelegramSink{
		botToken: botToken,
		chatID:   chatID,
		minLevel: minLevel,
		client:   &http.Client{Timeout: 5 * time.Second},
	}, nil
}
F
function

NewTelegramSinkFromEnv

NewTelegramSinkFromEnv creates a Telegram sink from environment variables.

Parameters

minLevel

Returns

error
pkg/logger/telegram_sink.go:36-38
func NewTelegramSinkFromEnv(minLevel Level) (*TelegramSink, error)

{
	return NewTelegramSink(os.Getenv("TELEGRAM_BOT_TOKEN"), os.Getenv("TELEGRAM_CHAT_ID"), minLevel)
}
F
function

levelFromString

Parameters

s
string

Returns

pkg/logger/telegram_sink.go:80-93
func levelFromString(s string) Level

{
	switch s {
	case "debug":
		return DebugLevel
	case "info":
		return InfoLevel
	case "warn":
		return WarnLevel
	case "error":
		return ErrorLevel
	default:
		return InfoLevel
	}
}