loading...

Golang Dynamic Logging for Microservices

rusty_sys_dev profile image Scott ・2 min read

This is my first time writing a post like this.. If anyone has any comments or opinions please let me know.

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

APP_GIF

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)
}

Posted on by:

Discussion

pic
Editor guide
 

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.

![APP_GIF](https://i.imgur.com/iHNIhOF.gif)

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... 😕