sneak 3dbe6954d7 Add a failing test pinning the discarded slog attributes
Every handler in this package accepts slog attributes and then throws
them away: Handle never reads record.Attrs, and WithAttrs and WithGroup
return the receiver unchanged in ConsoleHandler, JSONHandler and
WebhookHandler alike. So slog.Info("casting", "device", d, "file", f)
emits the message and silently loses both fields, which makes properly
structured logging carry less information than the interpolated
log.Printf calls it replaces.

The test asserts on the bytes the handlers actually write - os.Stdout
for the console and JSON handlers, the posted body for the webhook
handler - rather than on internal state, because the output is where the
loss is observable. It covers record attributes, WithAttrs accumulation,
WithAttrs not mutating its receiver so sibling loggers cannot leak
attributes into each other, WithGroup qualification, slog.Group nesting,
and LogValuer resolution, for each handler and through MultiplexHandler.

It also pins the properties a fix must not get wrong on the way past. A
value the caller logged is read and never written to, even when a group
later claims the same key - for maps and for slices, through the record
path and the derived-logger path, in all three handlers. A duration is
a number of nanoseconds in the json payload and the readable "3s" form
on the console. A console key is quoted on the same terms as a console
value, and as one token including its group prefix, so that the "=" that
separates the pair is always the first one outside quotes: a key of
"a=b" reads as "a=b"=v rather than the ambiguous a=b=v. The four
slog.Handler contract edge cases hold: an empty Attr is ignored, an
empty group is elided with its key, a group with an empty key is
inlined, and WithGroup("") is a no-op. And the two rules that follow
from the json payload being an object hold too: the record's own field
names win a collision, and a repeated key keeps its last value - except
where both are groups, which merge - while the console line keeps both.

This commit adds only the test, and it fails. The fix follows.

Refs: #19
2026-08-10 13:21:32 +00:00
2024-06-14 05:39:08 -07:00
2024-06-10 02:39:01 -07:00
2024-06-14 05:39:03 -07:00
fmt
2024-06-14 05:47:29 -07:00
2024-05-22 14:52:20 -07:00
2024-05-13 21:43:47 -07:00
2024-05-22 14:52:20 -07:00
2024-06-14 05:53:22 -07:00
2024-06-14 05:53:22 -07:00
2024-05-13 21:43:47 -07:00
2024-05-13 21:43:47 -07:00

simplelog

Summary

simplelog is an opinionated logging package designed to facilitate easy and structured logging in Go applications with an absolute minimum of boilerplate.

The idea is that you can add a single import line which replaces the stdlib log/slog default handler, and solve the 90% case for logging.

Current Status

Released v1.0.0 2024-06-14. Works as intended. No known bugs.

Features

  • if output is a tty, outputs pretty color logs
  • if output is not a tty, outputs json
  • supports delivering each log message via a webhook

Planned Features

  • supports delivering logs via tcp RELP (e.g. to remote rsyslog using imrelp)

Installation

To use simplelog, first ensure your project is set up with Go modules:

go mod init your_project_name

Then, add SimpleLog to your project:

go get sneak.berlin/go/simplelog

Usage

Below is an example of how to use SimpleLog in a Go application. This example is provided in the form of a main.go file, which demonstrates logging at various levels using structured logging syntax.

package main

import (
	"log/slog"
	_ "sneak.berlin/go/simplelog"
)

func main() {

    // log structured data with slog as usual:
	slog.Info("User login attempt", slog.String("user", "JohnDoe"), slog.Int("attempt", 3))
	slog.Warn("Configuration mismatch", slog.String("expected", "config.json"), slog.String("found", "config.dev.json"))
	slog.Error("Failed to save data", slog.String("reason", "permission denied"))
}

License

WTFPL

Description
sane logging defaults for go
Readme WTFPL 186 KiB
Languages
Go 89.6%
Dockerfile 4.6%
Makefile 3.8%
Shell 2%