X-Git-Url: http://www.git.cypherpunks.ru/?p=gorecfile.git;a=blobdiff_plain;f=slog%2Fhandler.go;fp=slog%2Fhandler.go;h=0a2acd4e547b01cb52e39a8a80c33cc78a091831;hp=0000000000000000000000000000000000000000;hb=530284958d3d776e249514dccacaba53468ff24a;hpb=ac9b31f3dfa1dbdf5c4571cfaf3c5b498faa0c0b diff --git a/slog/handler.go b/slog/handler.go new file mode 100644 index 0000000..0a2acd4 --- /dev/null +++ b/slog/handler.go @@ -0,0 +1,128 @@ +package slog + +import ( + "bytes" + "context" + "io" + "log/slog" + "sync" + "time" + + "go.cypherpunks.ru/recfile" +) + +type RecfileHandler struct { + W io.Writer + Level slog.Level + LevelKey string + MsgKey string + TimeKey string + attrs []slog.Attr + group string + m *sync.Mutex +} + +func NewRecfileHandler( + w io.Writer, + level slog.Level, + levelKey, msgKey, timeKey string, +) *RecfileHandler { + return &RecfileHandler{ + W: w, + Level: level, + LevelKey: levelKey, + MsgKey: msgKey, + TimeKey: timeKey, + m: new(sync.Mutex), + } +} + +func (h *RecfileHandler) Enabled(ctx context.Context, level slog.Level) bool { + return level >= h.Level +} + +func (h *RecfileHandler) WithAttrs(attrs []slog.Attr) slog.Handler { + return &RecfileHandler{ + W: h.W, + Level: h.Level, + LevelKey: h.LevelKey, + MsgKey: h.MsgKey, + TimeKey: h.TimeKey, + attrs: append(h.attrs, attrs...), + group: h.group, + m: h.m, + } +} + +func (h *RecfileHandler) WithGroup(name string) slog.Handler { + neu := RecfileHandler{ + W: h.W, + Level: h.Level, + LevelKey: h.LevelKey, + MsgKey: h.MsgKey, + TimeKey: h.TimeKey, + attrs: h.attrs, + group: h.group + name + "_", + m: h.m, + } + return &neu +} + +func writeValue(w *recfile.Writer, group string, attr slog.Attr) (err error) { + if attr.Value.Kind() == slog.KindAny { + multiline, ok := attr.Value.Any().([]string) + if ok { + if len(multiline) > 0 { + _, err = w.WriteFieldMultiline(group+attr.Key, multiline) + return + } + return + } + } + _, err = w.WriteFields(recfile.Field{ + Name: group + attr.Key, + Value: attr.Value.String(), + }) + return +} + +func (h *RecfileHandler) Handle(ctx context.Context, rec slog.Record) (err error) { + var b bytes.Buffer + w := recfile.NewWriter(&b) + _, err = w.RecordStart() + if err != nil { + panic(err) + } + var fields []recfile.Field + if h.LevelKey != "" { + fields = append(fields, recfile.Field{ + Name: h.LevelKey, + Value: rec.Level.String(), + }) + } + if h.TimeKey != "" { + fields = append(fields, recfile.Field{ + Name: h.TimeKey, + Value: rec.Time.UTC().Format(time.RFC3339Nano), + }) + } + fields = append(fields, recfile.Field{Name: h.MsgKey, Value: rec.Message}) + _, err = w.WriteFields(fields...) + if err != nil { + return + } + for _, attr := range h.attrs { + writeValue(w, h.group, attr) + } + rec.Attrs(func(attr slog.Attr) bool { return writeValue(w, h.group, attr) == nil }) + h.m.Lock() + n, err := h.W.Write(b.Bytes()) + h.m.Unlock() + if err != nil { + return + } + if n != b.Len() { + return io.EOF + } + return +}