Documentation
¶
Overview ¶
Package ecslog provides slog compatible handler which produces structured JSON.
Conceptually it is very similar with slog.JSONHandler, but provides one key functionality. It accepts dot delimited attribute keys and outputs records with appropriate nested JSON objects.
slog.String("event.action": "test") -> {"event":{"action": "test"}}
This approach can be convenient for Elastic Common Schema (ECS), which includes fair amount of nested JSON objects, and fields are usually described using dot notation ("event.action"). Compared to constructing log records with slog.Group, it may be more convenient, but crucially, it allows specifying nested object content in multiple assignments.
datasetLog := log.WithAttrs(slog.String("event.dataset", "audit"))
datasetLog.Info(slog.String("event.action", "test"))
Another advantage of this implementation is deduplication. Specifying single field multiple times will produce deduplicated JSON record, which contains "last" value.
datasetLog := log.WithAttrs(slog.String("event.action", "audit"))
datasetLog.Info(slog.String("event.action", "test"))
// {"event": {"action": "test"}, ...}
Limitations ¶
The approach with dot notation, combined with aim to be as fast as slog.JSONHandler leads to some limitations. They are mainly related to the use of slog.Group. While the handler is compatible with this attribute kind and will handle it as expected most of the time, sometimes it may differ.
- Specifying both `slog.Group("event", ...)` and `slog.String("event.log", ...)` will always ignore the attributes nested with the dot notation, outputing only the group.
- Multiple slog.Group with same keys are not merged, the last[1] one is used.
- Attribute slog.Group with empty key is not inlined. This rule is outlines by slog.Handler, but due to how groups are implemented, it is not possible without some sacrifices on the way.
Example ¶
package main
import (
"log/slog"
"os"
"github.com/oidq/ecslog"
)
func main() {
logger := slog.New(ecslog.NewHandler(os.Stdout, ecslog.WithTimestamp(false))).
With(
slog.String("event.dataset", "testing"),
)
// ...
logger.Info("Test!",
slog.String("event.action", "test"),
)
}
Output: {"message":"Test!","log":{"level":"INFO"},"event":{"dataset":"testing","action":"test"}}
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Handler ¶
type Handler struct {
// contains filtered or unexported fields
}
Handler is slog.Handler which produces JSON structured log output to given io.Writer.
See package documentation for details about record processing.
func NewHandler ¶
NewHandler creates a new slog.Handler instance with given options.
func (*Handler) Handle ¶
Handle processes slog.Record and writes structured JSON line to given io.Writer. For details about the behavior regarding attributes see Handler.
It is called by slog package.
func (*Handler) WithAttrs ¶
WithAttrs creates new slog.Handler with given default attributes. It is called by slog package.
func (*Handler) WithGroup ¶
WithGroup creates new slog.Handler with given default group (see slog.Handler interface) It is called by slog package.
type LogLevelFunc ¶
LogLevelFunc is used in WithLogLevelFunc to control which log entry is going to be logged. For basic control based on slog.Level use WithLogLevel().
type Option ¶
type Option func(*handlerOptions)
func WithLogLevel ¶
WithLogLevel options sets minimum log level to be outputted. Default value is slog.LevelInfo.
This option is exclusive with WithLogLevelFunc.
func WithLogLevelFunc ¶
func WithLogLevelFunc(logLevelF LogLevelFunc) Option
WithLogLevelFunc options sets log level decision function. Given function will be called for each log entry and if it returns false, no log will be produced. Context passed to this function comes from slog.
This option is exclusive with WithLogLevel.
func WithSource ¶
WithSource option can be used to add log source information to logs.
Keys "log.origin.function", "log.origin.file" and "log.origin.line" will filled by information received from log/slog.
func WithTimestamp ¶
WithTimestamp option can be used to disable timestamp ("@timestamp" field) in generated logs.