package simplelog import ( "context" "encoding/json" "fmt" "io" "log/slog" "os" ) // JSONHandler writes each log record to stdout as a JSON document. type JSONHandler struct { // out is where records are written. Nil means os.Stdout, looked up on // every write so that a reassigned os.Stdout is followed. out io.Writer attrs handlerAttrs } // NewJSONHandler returns a new JSONHandler. func NewJSONHandler() *JSONHandler { return &JSONHandler{} } // Handle marshals the record, with its attributes, to one JSON object and // writes it to stdout. A failed write is returned as an error. func (j *JSONHandler) Handle(_ context.Context, record slog.Record) error { jsonData, err := json.Marshal(recordToMap(record, j.attrs)) if err != nil { return err } out := j.out if out == nil { out = os.Stdout } _, err = fmt.Fprintln(out, string(jsonData)) if err != nil { return fmt.Errorf("error writing log record: %w", err) } return nil } // Enabled reports whether the handler processes records at the given // level; it always returns true. func (j *JSONHandler) Enabled(_ context.Context, _ slog.Level) bool { return true } // WithAttrs returns a new handler that also emits attrs, qualified by the // groups open now. The receiver is not modified. func (j *JSONHandler) WithAttrs(attrs []slog.Attr) slog.Handler { if len(attrs) == 0 { return j } return &JSONHandler{out: j.out, attrs: j.attrs.withAttrs(attrs)} } // WithGroup returns a new handler that nests later attributes in an // object named after the group. An empty name returns the receiver. func (j *JSONHandler) WithGroup(name string) slog.Handler { if name == "" { return j } return &JSONHandler{out: j.out, attrs: j.attrs.withGroup(name)} }