Dynamic logging is something I believe should be implemented in any micro-service environment. I suppose I should start with I mean by dynamic logging.. Simply put the following point should be covered.
- Maintainer should be able to change the log level of the application mid-execution.
Sample Application
Using the go.uber.org/zap
library LevelEnablerFunc you should be able to implement the interface using any protocol you want? (Haven't tested this).. That being said, for my sample application I will be using an HTTP interface and so I will use the zap built-in ServeHttp method.
First we need to define our logger and build and build an http router to accept log level changes. This is completed by utilizing the above mentioned ServeHttp
function built into the zap.AtomicLevel
object.
Setup Logger
config := zap.NewProductionEncoderConfig()
...
encoder := zapcore.NewJSONEncoder(config)
atom := zap.NewAtomicLevel()
logr := zap.New(zapcore.NewCore(encoder, zapcore.Lock(os.Stdout), atom))
Dynamic log level interface
mux := http.NewServeMux()
mux.Handle("/log_level", atom)
go http.ListenAndServe(":1065", mux)
I am running a simple loop that repeats various logging messages to allow us to see the expected output. After building and running the application we can interact with it via curl.
Change logging levels
curl -X PUT -d '{"level":"debug"}' localhost:1065/log_level
curl -X PUT -d '{"level":"info"}' localhost:1065/log_level
curl -X PUT -d '{"level":"info"}' localhost:1065/ # EXPECTED 404
curl -X GET localhost:1065/log_level
NOTE: GIF seems to be broken again... but clicking the link should show you... ill fix it later 😂
Sample Application Code
package main
import (
"net/http"
"os"
"time"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
func main() {
undo := initLogger()
defer undo()
for {
zap.S().Info("test_logs")
zap.S().Debug("test_logs_debug")
time.Sleep(1000 * time.Millisecond)
}
}
func initLogger() func() {
config := zap.NewProductionEncoderConfig()
config.EncodeTime = func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
nanos := t.UnixNano()
millis := nanos / int64(time.Millisecond)
enc.AppendInt64(millis)
}
encoder := zapcore.NewJSONEncoder(config)
atom := zap.NewAtomicLevel()
logr := zap.New(zapcore.NewCore(encoder, zapcore.Lock(os.Stdout), atom))
mux := http.NewServeMux()
mux.Handle("/log_level", atom)
go http.ListenAndServe(":1065", mux)
return zap.ReplaceGlobals(logr)
}
Top comments (2)
If anyone can enlighten me as to how to get my gif to work, I would be eternally grateful! 😢 I have it written as the following.
It works when I try it in hackmd..
seems the gif was too large??? 🤣 🤣
200MP max size, according to the Firefox dev console I was requesting 380MP..
reduced the size by 1% and it seemed to work... 😕