Skip to content

Instantly share code, notes, and snippets.

@lxfontes
Created August 19, 2024 13:36
Show Gist options
  • Save lxfontes/7a8d28a256a764cba2108600ad5d1aa7 to your computer and use it in GitHub Desktop.
Save lxfontes/7a8d28a256a764cba2108600ad5d1aa7 to your computer and use it in GitHub Desktop.
wasi slog
package main
// logger := slog.New(DefaultOptions().NewHandler())
// a 'context' attribute will be promote to wasilog 'context' field
// logger = logger.With("context", "Get")
//
// logger.Info("Hello world")
// logger.Warn("Hello world 1", "key", "value")
// logger.Info("Hello world 2", slog.String("key", "value"))
// logger.Info("Hello world 3", slog.Any("key", 123), slog.String("context", "SomethingElse"))
//
// 2024-08-19T13:30:58.279639Z INFO log: wasmcloud_host::wasmbus::handler: Hello world component_id="demo_image_processor-task_manager" level=Level::Info context="Get"
// 2024-08-19T13:30:58.279860Z WARN log: wasmcloud_host::wasmbus::handler: key="value" Hello world 1 component_id="demo_image_processor-task_manager" level=Level::Warn context="Get"
// 2024-08-19T13:30:58.279950Z INFO log: wasmcloud_host::wasmbus::handler: key="value" Hello world 2 component_id="demo_image_processor-task_manager" level=Level::Info context="Get"
// 2024-08-19T13:30:58.280050Z INFO log: wasmcloud_host::wasmbus::handler: key="123" Hello world 3 component_id="demo_image_processor-task_manager" level=Level::Info context="SomethingElse"
import (
"context"
"fmt"
"log/slog"
"strings"
slogcommon "github.com/samber/slog-common"
// need compiled wit with wasi logging
. "github.com/cosmonic-labs/wasmcloud.space/components/task-manager/gen"
)
type WasiLoggingOption struct {
// log level (default: debug)
Level slog.Leveler
// optional: fetch attributes from context
AttrFromContext []func(ctx context.Context) []slog.Attr
ReplaceAttr func(groups []string, a slog.Attr) slog.Attr
}
type WebassemblyHandler struct {
option WasiLoggingOption
attrs []slog.Attr
groups []string
}
var _ slog.Handler = (*WebassemblyHandler)(nil)
func wasiLevel(level slog.Level) WasiLoggingLoggingLevel {
switch level {
case slog.LevelDebug:
return WasiLoggingLoggingLevelDebug()
case slog.LevelInfo:
return WasiLoggingLoggingLevelInfo()
case slog.LevelWarn:
return WasiLoggingLoggingLevelWarn()
case slog.LevelError:
return WasiLoggingLoggingLevelError()
default:
return WasiLoggingLoggingLevelDebug()
}
}
func wasiConverter(replaceAttr func(groups []string, a slog.Attr) slog.Attr, loggerAttr []slog.Attr, groups []string, record *slog.Record) (string, string) {
attrs := slogcommon.AppendRecordAttrsToAttrs(loggerAttr, groups, record)
attrs = slogcommon.ReplaceAttrs(replaceAttr, []string{}, attrs...)
attrs = slogcommon.RemoveEmptyAttrs(attrs)
extra := slogcommon.AttrsToString(attrs...)
context, ok := extra["context"]
if ok {
delete(extra, "context")
}
var formattedAttrs []string
for k, v := range extra {
formattedAttrs = append(formattedAttrs, fmt.Sprintf("%s=%q", k, v))
}
formattedAttrs = append(formattedAttrs, record.Message)
return strings.Join(formattedAttrs, " "), context
}
func DefaultOptions() WasiLoggingOption {
return WasiLoggingOption{
Level: slog.LevelDebug,
AttrFromContext: []func(ctx context.Context) []slog.Attr{},
}
}
func (o WasiLoggingOption) NewHandler() slog.Handler {
return &WebassemblyHandler{
option: o,
}
}
func (h *WebassemblyHandler) Enabled(_ context.Context, level slog.Level) bool {
return level >= h.option.Level.Level()
}
func (h *WebassemblyHandler) Handle(ctx context.Context, record slog.Record) error {
fromContext := slogcommon.ContextExtractor(ctx, h.option.AttrFromContext)
message, logContext := wasiConverter(h.option.ReplaceAttr, append(h.attrs, fromContext...), h.groups, &record)
WasiLoggingLoggingLog(wasiLevel(record.Level), logContext, message)
return nil
}
func (h *WebassemblyHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
return &WebassemblyHandler{
option: h.option,
attrs: slogcommon.AppendAttrsToGroup(h.groups, h.attrs, attrs...),
groups: h.groups,
}
}
func (h *WebassemblyHandler) WithGroup(name string) slog.Handler {
// https://cs.opensource.google/go/x/exp/+/46b07846:slog/handler.go;l=247
if name == "" {
return h
}
return &WebassemblyHandler{
option: h.option,
attrs: h.attrs,
groups: append(h.groups, name),
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment