From a3ec44cd37d176b3d5bbd5181b58080e07146cfe Mon Sep 17 00:00:00 2001 From: wei liu Date: Thu, 28 Jul 2022 11:36:30 +0800 Subject: [PATCH] support dynamic change log level through http (#18430) Signed-off-by: Wei Liu --- internal/log/log.go | 7 ++++++ internal/log/log_test.go | 54 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/internal/log/log.go b/internal/log/log.go index 1b4bd9f137..b3052bdfdd 100644 --- a/internal/log/log.go +++ b/internal/log/log.go @@ -31,6 +31,7 @@ package log import ( "fmt" + "net/http" "os" "sync/atomic" @@ -55,6 +56,12 @@ func init() { r := utils.NewRateLimiter(1.0, 60.0) _globalR.Store(r) + + updateLoglLevel := func(w http.ResponseWriter, req *http.Request) { + _globalP.Load().(*ZapProperties).Level.ServeHTTP(w, req) + } + + http.HandleFunc("/log/level", updateLoglLevel) } // InitLogger initializes a zap logger. diff --git a/internal/log/log_test.go b/internal/log/log_test.go index c8efd5ddfc..e9ccb3199c 100644 --- a/internal/log/log_test.go +++ b/internal/log/log_test.go @@ -33,7 +33,11 @@ package log import ( "bufio" "bytes" + "context" + "encoding/json" "fmt" + "io/ioutil" + "net/http" "testing" "time" @@ -113,6 +117,56 @@ func TestLevelGetterAndSetter(t *testing.T) { assert.Equal(t, zap.ErrorLevel, GetLevel()) } +func TestUpdateLogLevelThroughHttp(t *testing.T) { + httpServer := &http.Server{Addr: ":9081"} + go func() { + if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed { + Fatal(err.Error()) + } + }() + + SetLevel(zap.DebugLevel) + assert.Equal(t, zap.DebugLevel, GetLevel()) + + // replace global logger, log change will not be affected. + conf := &Config{Level: "info", File: FileLogConfig{}, DisableTimestamp: true} + logger, p, _ := InitLogger(conf) + ReplaceGlobals(logger, p) + assert.Equal(t, zap.InfoLevel, GetLevel()) + + // change log level through http + payload, err := json.Marshal(map[string]interface{}{"level": "error"}) + if err != nil { + Fatal(err.Error()) + } + + req, err := http.NewRequest(http.MethodPut, "http://localhost:9081/log/level", bytes.NewBuffer(payload)) + req.Header.Set("Content-Type", "application/json") + if err != nil { + Fatal(err.Error()) + } + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + Fatal(err.Error()) + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + Fatal(err.Error()) + } + assert.Equal(t, "{\"level\":\"error\"}\n", string(body)) + assert.Equal(t, zap.ErrorLevel, GetLevel()) + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + if err := httpServer.Shutdown(ctx); err != nil { + Fatal(err.Error()) + } +} + func TestSampling(t *testing.T) { sample, drop := make(chan zapcore.SamplingDecision, 1), make(chan zapcore.SamplingDecision, 1) samplingConf := zap.SamplingConfig{