From d301c812e5eb7f7c70b5a9db51351b782f58ea13 Mon Sep 17 00:00:00 2001 From: ChenYarong Date: Sat, 6 Jan 2024 11:29:57 +0800 Subject: [PATCH] Add exportable custom plain logger (#1171) * Add exportable custom plain logger * fix for ci * add copyright * remove unused function * Change the log directory to current directory --------- Co-authored-by: chenyarong --- pkg/logger/export.go | 12 ++++++ pkg/logger/hub.go | 57 ++++++++++++++++++++++++++++ pkg/logger/logger.go | 28 ++++++++++++++ pkg/logger/logger_test.go | 79 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 176 insertions(+) create mode 100644 pkg/logger/hub.go create mode 100644 pkg/logger/logger_test.go diff --git a/pkg/logger/export.go b/pkg/logger/export.go index 831951985d..2c1a4c5101 100644 --- a/pkg/logger/export.go +++ b/pkg/logger/export.go @@ -21,11 +21,21 @@ import ( "net/url" "time" + "github.com/megaease/easegress/v2/pkg/option" "github.com/megaease/easegress/v2/pkg/util/fasttime" "github.com/megaease/easegress/v2/pkg/util/stringtool" "github.com/openzipkin/zipkin-go/model" + "go.uber.org/zap" ) +// MustNewPlainLogger creates a plain logger, it panics if any error occurs. +func MustNewPlainLogger(opt *option.Options, filename string, maxCacheCount uint32) *zap.SugaredLogger { + l := mustNewPlainLogger(opt, filename, maxCacheCount) + lh.register(filename, l) + + return l +} + type lazyLogBuilder struct { fn func() string } @@ -68,6 +78,8 @@ func Sync() { httpFilterAccessLogger.Sync() httpFilterDumpLogger.Sync() restAPILogger.Sync() + + lh.sync() } // APIAccess logs admin api log. diff --git a/pkg/logger/hub.go b/pkg/logger/hub.go new file mode 100644 index 0000000000..8ba3a16c7a --- /dev/null +++ b/pkg/logger/hub.go @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2017, MegaEase + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package logger + +import ( + "sync" + + "go.uber.org/zap" +) + +var lh *logHub + +func init() { + lh = &logHub{ + loggers: make(map[string]*zap.SugaredLogger), + mu: &sync.RWMutex{}, + } +} + +type logHub struct { + loggers map[string]*zap.SugaredLogger + + mu *sync.RWMutex +} + +// register registers a logger with name. +func (lh *logHub) register(name string, logger *zap.SugaredLogger) { + lh.mu.Lock() + defer lh.mu.Unlock() + + lh.loggers[name] = logger +} + +// sync syncs all loggers. +func (lh *logHub) sync() { + lh.mu.RLock() + defer lh.mu.RUnlock() + + for _, logger := range lh.loggers { + logger.Sync() + } +} diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index 3026ba57f8..f2d679a502 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -19,6 +19,7 @@ package logger import ( + "fmt" "io" "os" "path/filepath" @@ -111,6 +112,7 @@ func SetLogLevel(level zapcore.Level) { globalLogLevel.SetLevel(level) } +// GetLogLevel returns log level. func GetLogLevel() string { return globalLogLevel.String() } @@ -231,3 +233,29 @@ func newPlainLogger(opt *option.Options, filename string, maxCacheCount uint32) return zap.New(core).Sugar() } + +func mustNewPlainLogger(opt *option.Options, filename string, maxCacheCount uint32) *zap.SugaredLogger { + encoderConfig := zapcore.EncoderConfig{ + TimeKey: "", + LevelKey: "", + NameKey: "", + CallerKey: "", + MessageKey: "message", + StacktraceKey: "", + LineEnding: zapcore.DefaultLineEnding, + } + + var err error + var fr io.Writer = os.Stdout + if opt.AbsLogDir != "" { + fr, err = newLogFile(filepath.Join(opt.AbsLogDir, filename), maxCacheCount) + if err != nil { + panic(fmt.Errorf("new log file %s failed: %w", filename, err)) + } + } + + syncer := zapcore.AddSync(fr) + core := zapcore.NewCore(zapcore.NewConsoleEncoder(encoderConfig), syncer, globalLogLevel) // use global log level + + return zap.New(core).Sugar() +} diff --git a/pkg/logger/logger_test.go b/pkg/logger/logger_test.go new file mode 100644 index 0000000000..9a6015ffa4 --- /dev/null +++ b/pkg/logger/logger_test.go @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2017, MegaEase + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package logger + +import ( + "os" + "testing" + + "github.com/megaease/easegress/v2/pkg/option" +) + +func TestMustPlainLogger(t *testing.T) { + opt := &option.Options{AbsLogDir: "."} + defer func() { + if rv := recover(); rv != nil { + t.Errorf("mustPlainLogger() panic: %v", rv) + } + }() + + MustNewPlainLogger(opt, "test.log", 1) + _, err := os.Stat("test.log") + if err == nil { + return + } + + if os.IsNotExist(err) { + t.Errorf("mustPlainLogger() failed: %v", err) + } +} + +func TestMustPlainLoggerPanic(t *testing.T) { + opt := &option.Options{AbsLogDir: "."} + defer func() { + if rv := recover(); rv != nil { + t.Logf("mustPlainLogger() panic: %v", rv) + } + }() + + MustNewPlainLogger(opt, "test.log", 0) + _, err := os.Stat("test.log") + if err == nil { + return + } + + if os.IsNotExist(err) { + t.Errorf("mustPlainLogger() failed: %v", err) + } +} + +func TestMustPlainLoggerWrite(t *testing.T) { + opt := &option.Options{AbsLogDir: "."} + defer func() { + if rv := recover(); rv != nil { + t.Errorf("mustPlainLogger() panic: %v", rv) + } + }() + + l := MustNewPlainLogger(opt, "test.log", 0) + l.Errorf("test error") + l.Info("test info") + l.Debug("test debug") + l.Sync() + t.Logf("mustPlainLogger() success") +}