DEV Community

Shenouda Fawzy
Shenouda Fawzy

Posted on • Edited on

Using UTC time in Golang slog

Go introduced slog in Go1.21. That makes logging more flexible and consistent. And when I tried to use it on one of my side projects I found that it logs the time in local timezone, which isn't the best choice for me. Cause for example, I may own a server machine at Stockholm and I live in Egypt, that case when the logs is written, it will be logged in UTC+1 (Stockholm Time), however Egypt is UTC+2. So, I had to interpret it in my mind every time I read a log line. This is tedious. Not only that, imagine a team scattered around the globe, each one will try to do the interpenetration his own. And even sharing log lines won't be efficient for the same reason.

Therefore, a UTC would solve that issue, and wherever I'm located, we will going interpret it straight forward. So, tried to find out how this can be done. But didn't, even asked GPT models, but didn't give me answer (at least the free one) But finally I manged to make it. Here is a full working go program that writes log in UTC time. Further more, it write it in a secure way. The key player here is the ReplaceAttr function in the slog. Where you can override certain log message.

package main

import (
    "log/slog"
    "os"
    "time"
)

func main() {
    cardPan := "4701322211111234"
    cardCvv := "789"
    secLog := SecureLogger()
    secLog.Info("This is secure logger", "secret", cardPan, "secret", cardCvv)
    // time=2024-02-17T15:52:01.119Z level=INFO msg="This is secure logger" secret=47013######11234 secret=***
}

// SecureLogger write logs in a secure way in UTC time
func SecureLogger() *slog.Logger {
    l := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
        ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
            if a.Key == "time" {
                a.Value = slog.AnyValue(time.Now().UTC())
            }

            if a.Key == "secret" {
                // This is probably a card pan, so we can only reveal
                // The first 5 and last 5 and the rest can be masked with #
                if len(a.Value.String()) == 16 {
                    pan := a.Value.String()
                    first5 := pan[:5]
                    last5 := pan[11:]
                    masked := first5 + "######" + last5
                    a.Value = slog.StringValue(masked)
                } else {
                    a.Value = slog.StringValue("***")
                }
            }
            return a
        },
    })

    return slog.New(l)
}

Enter fullscreen mode Exit fullscreen mode

Each log entry has built-in keys which is time, level and message. So I override the time one.
And introduced new secret key, which supposed to be used for logging sensitive elements.

And that's all!

Top comments (0)