logger
packageAPI reference for the logger
package.
Imports
(11)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.
type clefEntry struct
Fields
| Name | Type | Description |
|---|---|---|
| Timestamp | time.Time | json:"@t" |
| Level | string | json:"@l,omitempty" |
| Message | string | json:"@m" |
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.
type CLEFSink struct
Methods
Log writes e as a CLEF JSON line to the underlying writer.
Parameters
Returns
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 |
Level
Level represents log severity.
type Level int
Field
Field is a single structured key/value pair.
type Field struct
Fields
| Name | Type | Description |
|---|---|---|
| Key | string | json:"key" |
| Value | interface{} | json:"value" |
Entry
Entry is the log payload passed to sinks.
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" |
Logger
Logger is the public logging contract.
type Logger interface
Methods
Option
Option configures the concrete logger on creation.
type Option func(*stdLogger)
stdLogger
stdLogger is a simple, thread-safe structured logger with pluggable sinks.
type stdLogger struct
Methods
RegisterSink adds a sink at runtime.
Parameters
func (*stdLogger) RegisterSink(s Sink)
{
l.mu.Lock()
defer l.mu.Unlock()
l.sinks = append(l.sinks, s)
}
SetLevel changes the log level at runtime.
Parameters
func (*stdLogger) SetLevel(level Level)
{
l.mu.Lock()
defer l.mu.Unlock()
l.level = level
}
With returns a derived logger that shares sinks but has extra bound fields.
Parameters
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 reports whether the given level meets the logger's minimum threshold.
Parameters
Returns
func (*stdLogger) shouldLog(level Level) bool
{
l.mu.RLock()
defer l.mu.RUnlock()
return level >= l.level
}
log constructs an Entry and dispatches it to all registered sinks.
Parameters
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 logs at debug level.
Parameters
func (*stdLogger) Debug(msg string, fields ...Field)
{ l.log(DebugLevel, msg, fields...) }
Info logs at info level.
Parameters
func (*stdLogger) Info(msg string, fields ...Field)
{ l.log(InfoLevel, msg, fields...) }
Warn logs at warn level.
Parameters
func (*stdLogger) Warn(msg string, fields ...Field)
{ l.log(WarnLevel, msg, fields...) }
Error logs at error level.
Parameters
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{} |
Uses
New
New constructs a logger with optional options.
Parameters
Returns
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"})
Uses
WithLevel
WithLevel sets the minimum level for emitted logs.
func WithLevel(level Level) Option
{
return func(l *stdLogger) { l.level = level }
}
WithSink
WithSink adds an initial sink.
func WithSink(s Sink) Option
{
return func(l *stdLogger) { l.sinks = append(l.sinks, s) }
}
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
func WithoutDefaultSink() Option
{
return func(l *stdLogger) { l.sinks = nil }
}
Uses
WithFields
WithFields binds fields to the logger returned from New.
Parameters
Returns
func WithFields(fields ...Field) Option
{
return func(l *stdLogger) {
for _, f := range fields {
l.fields[f.Key] = f.Value
}
}
}
Uses
ConsoleSink
ConsoleSink writes entries as compact JSON lines to an io.Writer.
type ConsoleSink struct
Methods
Fields
| Name | Type | Description |
|---|---|---|
| w | io.Writer |
NewConsoleSink
NewConsoleSink constructs a ConsoleSink.
Parameters
Returns
func NewConsoleSink(w io.Writer) *ConsoleSink
{
if w == nil {
w = os.Stdout
}
return &ConsoleSink{w: w}
}
PrometheusSink
PrometheusSink exposes simple counters grouped by log level.
type PrometheusSink struct
Methods
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)
}
})
}
Fields
| Name | Type | Description |
|---|---|---|
| mu | sync.Mutex | |
| counters | map[string]int64 | |
| minLevel | Level |
Uses
NewPrometheusSink
NewPrometheusSink creates a Prometheus-compatible metrics sink.
Parameters
Returns
func NewPrometheusSink(minLevel Level, namespace string) *PrometheusSink
{
_ = namespace
return &PrometheusSink{counters: make(map[string]int64), minLevel: minLevel}
}
Uses
RotatingFileOptions
RotatingFileOptions configures file rotation behavior.
type RotatingFileOptions struct
Fields
| Name | Type | Description |
|---|---|---|
| MaxSizeMB | int | |
| MaxBackups | int | |
| MaxAgeDays | int | |
| Compress | bool | |
| LocalTime | bool |
RotatingFileSink
RotatingFileSink writes JSON log lines to a rolling file.
type RotatingFileSink struct
Methods
Log writes a structured entry to the rolling log file.
Parameters
Returns
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 forces the underlying writer to rotate the active log file.
Returns
func (*RotatingFileSink) Rotate() error
{
return r.writer.Rotate()
}
Close closes the underlying rotating log writer.
Returns
func (*RotatingFileSink) Close() error
{
return r.writer.Close()
}
Fields
| Name | Type | Description |
|---|---|---|
| writer | *lumberjack.Logger |
NewRotatingFileSink
NewRotatingFileSink creates a sink backed by a rolling log file.
Parameters
Returns
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
}
TelegramSink
TelegramSink posts selected log entries to a Telegram chat.
type TelegramSink struct
Methods
Log forwards the entry to Telegram when it passes the configured level threshold.
Parameters
Returns
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 |
Uses
NewTelegramSink
NewTelegramSink constructs a Telegram sink.
Parameters
Returns
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
}
Uses
NewTelegramSinkFromEnv
NewTelegramSinkFromEnv creates a Telegram sink from environment variables.
Parameters
Returns
func NewTelegramSinkFromEnv(minLevel Level) (*TelegramSink, error)
{
return NewTelegramSink(os.Getenv("TELEGRAM_BOT_TOKEN"), os.Getenv("TELEGRAM_CHAT_ID"), minLevel)
}
Uses
levelFromString
Parameters
Returns
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
}
}