After playing with it some more:

This also does the trick

h := NewHandler(os.Stdout, &MyOptions{Level: slog.LevelDebug, TimeFormat:
time.DateTime})
l := slog.New(h)
slog.SetDefault(l)

slog.Debug("hello")
slog.Info("hello")
slog.Warn("hello")
slog.Error("hello")





type MyOptions struct {
// Enable source code location (Default: false)
AddSource bool

// Minimum level to log (Default: slog.LevelInfo)
Level slog.Leveler

// ReplaceAttr is called to rewrite each non-group attribute before it is
logged.
// See https://pkg.go.dev/log/slog#HandlerOptions for details.
ReplaceAttr func(groups []string, attr slog.Attr) slog.Attr

// Time format (Default: time.StampMilli)
TimeFormat string
}

type MyHandler struct {
opts MyOptions
prefix string // preformatted group names followed by a dot
preformat string // preformatted Attrs, with an initial space
timeFormat string

mu sync.Mutex
w io.Writer
}

func NewHandler(w io.Writer, opts *MyOptions) *MyHandler {
h := &MyHandler{w: w}
if opts != nil {
h.opts = *opts
}
if h.opts.ReplaceAttr == nil {
h.opts.ReplaceAttr = func(_ []string, a slog.Attr) slog.Attr { return a }
}
if opts.TimeFormat != "" {
h.timeFormat = opts.TimeFormat
}

return h
}

func (h *MyHandler) Enabled(ctx context.Context, level slog.Level) bool {
minLevel := slog.LevelInfo
if h.opts.Level != nil {
minLevel = h.opts.Level.Level()
}
return level >= minLevel
}

func (h *MyHandler) WithGroup(name string) slog.Handler {
return &MyHandler{
w: h.w,
opts: h.opts,
preformat: h.preformat,
prefix: h.prefix + name + ".",
}
}

func (h *MyHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
var buf []byte
for _, a := range attrs {
buf = h.appendAttr(buf, h.prefix, a)
}
return &MyHandler{
w: h.w,
opts: h.opts,
prefix: h.prefix,
preformat: h.preformat + string(buf),
}
}

func (h *MyHandler) Handle(ctx context.Context, r slog.Record) error {
var buf []byte
if !r.Time.IsZero() {
buf = r.Time.AppendFormat(buf, h.timeFormat)
buf = append(buf, ' ')
}

levText := (r.Level.String() + " ")[0:5]

buf = append(buf, levText...)
buf = append(buf, ' ')
if h.opts.AddSource && r.PC != 0 {
fs := runtime.CallersFrames([]uintptr{r.PC})
f, _ := fs.Next()
buf = append(buf, f.File...)
buf = append(buf, ':')
buf = strconv.AppendInt(buf, int64(f.Line), 10)
buf = append(buf, ' ')
}
buf = append(buf, r.Message...)
buf = append(buf, h.preformat...)
r.Attrs(func(a slog.Attr) bool {
buf = h.appendAttr(buf, h.prefix, a)
return true
})
buf = append(buf, '\n')
h.mu.Lock()
defer h.mu.Unlock()
_, err := h.w.Write(buf)
return err
}

func (h *MyHandler) appendAttr(buf []byte, prefix string, a slog.Attr) []
byte {
if a.Equal(slog.Attr{}) {
return buf
}
if a.Value.Kind() != slog.KindGroup {
buf = append(buf, ' ')
buf = append(buf, prefix...)
buf = append(buf, a.Key...)
buf = append(buf, '=')
return fmt.Appendf(buf, "%v", a.Value.Any())
}
// Group
if a.Key != "" {
prefix += a.Key + "."
}
for _, a := range a.Value.Group() {
buf = h.appendAttr(buf, prefix, a)
}
return buf
}


Op di 29 aug 2023 om 09:16 schreef 'Sean Liao' via golang-nuts <
golang-nuts@googlegroups.com>:

> cycle:
> https://go.dev//issues/61892
>
> default handler, copied/exported:
> https://pkg.go.dev/github.com/jba/slog/handlers/loghandler
>
> - sean
>
>
> On Tue, Aug 29, 2023 at 7:53 AM Marcello H <marcel...@gmail.com> wrote:
>
>> Yesterday, I came up with the same question and found this:
>> "github.com/lmittmann/tint"
>>
>> (This solution still uses os.Stdout, but I think this can do what you
>> need.)
>>
>> An example:
>> logOptions := &tint.Options{
>> NoColor: true,
>> Level: slog.LevelError,
>> TimeFormat: time.DateTime,
>> }
>> logHandler := tint.NewHandler(os.Stdout, logOptions)
>> logger := slog.New(logHandler)
>> slog.SetDefault(logger)
>> slog.Info("this does not show")
>> slog.Debug("this debug info does not show")
>> logOptions.Level = slog.LevelInfo
>> slog.Info("this is now visible")
>> slog.Debug("this debug info still does not show")
>> logOptions.Level = slog.LevelDebug
>> slog.Info("this is still visible")
>> slog.Debug("this debug info also shows")
>> Op dinsdag 29 augustus 2023 om 03:00:01 UTC+2 schreef Mike Schinkel:
>>
>>> Hi Tamás,
>>>
>>> Have you actually tried that and gotten it to work? It does not compile
>>> for me but this does (note method call vs. property reference):
>>>
>>> slog.SetDefault(slog.New(myHandler{Handler:slog.Default().Handler()}))
>>>
>>> However, when delegating the Handle() method it seems to cause an
>>> infinite
>>> loop:
>>>
>>> func (m MyHandler) Handle(ctx context.Context, r slog.Record) error {
>>>     return m.Handler.Handle(ctx, r)
>>> }
>>>
>>> See https://goplay.tools/snippet/qw07m0YflLd
>>>
>>> I know about this because just this past weekend I was trying to write a
>>> TeeHandler to output the default to the screen and JSON to a file just
>>> this
>>> past weekend and ran into an infinite loop problem with the default
>>> handler.
>>>
>>> I tried my best to figure out why it needed to be structured the way it
>>> was
>>> in that it seems to call itself recursively. I wanted to post a question
>>> to
>>> this list to see if there was a workaround, or if not to see if there
>>> might
>>> be interest in allowing it to work, but I could not get my head around
>>> it so
>>> eventually gave up and just used the TextHandler instead.
>>>
>>> Shame though. It would be nice to be able to reuse the default handler
>>> but
>>> AFACT it is not possible (though if I am wrong I would love for someone
>>> to
>>> show me how to get it to work.)
>>>
>>> -Mike
>>>
>>>
>>> On Monday, August 28, 2023 at 12:50:50 PM UTC-4 Tamás Gulácsi wrote:
>>>
>>> slog.SetDefault(slog.New(myHandler{Handler:slog.Default().Handler}))
>>>
>>> vl...@mailbox.org a következőt írta (2023. augusztus 28., hétfő,
>>> 15:06:37 UTC+2):
>>>
>>> Hi,
>>>
>>> When reading trough the log/slog documentation, it seems one can create
>>> a logger with a different handler, which is either NewTextHandler or
>>> NewJSONHandler.
>>>
>>> Why can't I configure the defaultHandler? Let's say I want my logger to
>>> behave exactly like the defaultHandler, but output to a logfile or
>>> Stdout instead.
>>>
>>> The defaultHandler's output is different compared to the NewTextHandler:
>>>
>>> slog.Info("ok"), gives me:
>>>
>>> INFO ok
>>>
>>> The NextTextHandler gives me:
>>>
>>> level=INFO msg="ok"
>>>
>>>
>>> Regards,
>>>
>>> --
>> You received this message because you are subscribed to the Google Groups
>> "golang-nuts" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to golang-nuts+unsubscr...@googlegroups.com.
>> To view this discussion on the web visit
>> https://groups.google.com/d/msgid/golang-nuts/df136f1e-0283-46fa-a0b7-ce17a0722fd9n%40googlegroups.com
>> <https://groups.google.com/d/msgid/golang-nuts/df136f1e-0283-46fa-a0b7-ce17a0722fd9n%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>>
> --
> You received this message because you are subscribed to a topic in the
> Google Groups "golang-nuts" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/golang-nuts/aJPXT2NF-Lc/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> golang-nuts+unsubscr...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/golang-nuts/CAGabyPo9NZJBf%3Dj-W_8tUS%3DqkmwHRWVpjCbFz04jZW_P8KEOow%40mail.gmail.com
> <https://groups.google.com/d/msgid/golang-nuts/CAGabyPo9NZJBf%3Dj-W_8tUS%3DqkmwHRWVpjCbFz04jZW_P8KEOow%40mail.gmail.com?utm_medium=email&utm_source=footer>
> .
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CADBSaR28mnPtC-bB-udasPpu%2BdsatFB5mOKoH0KL2sSATpkjMA%40mail.gmail.com.

Reply via email to