/* * Copyright 2020 The Dragonfly Authors * * 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 ( "fmt" "strings" "go.uber.org/atomic" "go.uber.org/zap" "go.uber.org/zap/zapcore" "gopkg.in/natefinch/lumberjack.v2" ) type LogRotateConfig struct { MaxSize int MaxAge int MaxBackups int } var ( CoreLogFileName = "core.log" GrpcLogFileName = "grpc.log" GinLogFileName = "gin.log" GCLogFileName = "gc.log" StorageGCLogFileName = "storage-gc.log" JobLogFileName = "job.log" StatSeedLogFileName = "stat/seed.log" DownloaderLogFileName = "downloader.log" KeepAliveLogFileName = "keepalive.log" ) const ( encodeTimeFormat = "2006-01-02 15:04:05.000" ) var coreLevel = zap.NewAtomicLevelAt(zapcore.InfoLevel) var customCoreLevel atomic.Bool var grpcLevel = zap.NewAtomicLevelAt(zapcore.WarnLevel) var customGrpcLevel atomic.Bool func CreateLogger(filePath string, compress bool, stats bool, verbose bool, logLevel string, config LogRotateConfig) (*zap.Logger, zap.AtomicLevel, error) { rotateConfig := &lumberjack.Logger{ Filename: filePath, MaxSize: config.MaxSize, MaxAge: config.MaxAge, MaxBackups: config.MaxBackups, LocalTime: true, Compress: compress, } syncer := zapcore.AddSync(rotateConfig) encoderConfig := zap.NewProductionEncoderConfig() encoderConfig.EncodeTime = zapcore.TimeEncoderOfLayout(encodeTimeFormat) var level = zap.NewAtomicLevelAt(zap.InfoLevel) // Use logLevel first, then fallback to verbose flag. if logLevel != "" { switch strings.ToLower(logLevel) { case "debug": level = zap.NewAtomicLevelAt(zapcore.DebugLevel) case "info": level = zap.NewAtomicLevelAt(zapcore.InfoLevel) case "warn": level = zap.NewAtomicLevelAt(zapcore.WarnLevel) case "error": level = zap.NewAtomicLevelAt(zapcore.ErrorLevel) default: fmt.Printf("Warning: invalid log level '%s', using 'info' instead\n", logLevel) } } else if verbose { level = zap.NewAtomicLevelAt(zapcore.DebugLevel) } if strings.HasSuffix(filePath, GrpcLogFileName) && customGrpcLevel.Load() { level = grpcLevel } else if strings.HasSuffix(filePath, CoreLogFileName) && customCoreLevel.Load() { level = coreLevel } core := zapcore.NewCore( zapcore.NewJSONEncoder(encoderConfig), syncer, level, ) var opts []zap.Option if !stats { opts = append(opts, zap.AddCaller(), zap.AddStacktrace(zap.WarnLevel), zap.AddCallerSkip(1)) } return zap.New(core, opts...), level, nil } func SetCoreLevel(level zapcore.Level) { customCoreLevel.Store(true) coreLevel.SetLevel(level) } func SetGrpcLevel(level zapcore.Level) { customGrpcLevel.Store(true) grpcLevel.SetLevel(level) }