diff --git a/support/log/logger.go b/support/log/logger.go index ed92945b..942b25f0 100644 --- a/support/log/logger.go +++ b/support/log/logger.go @@ -6,7 +6,6 @@ import ( ) type Level int -type Format int const ( EnvKeyLogCtx = "FLOGO_LOG_CTX" @@ -14,17 +13,12 @@ const ( DefaultLogDateFormat = "2006-01-02 15:04:05.000" EnvKeyLogLevel = "FLOGO_LOG_LEVEL" DefaultLogLevel = InfoLevel - EnvKeyLogFormat = "FLOGO_LOG_FORMAT" - DefaultLogFormat = FormatConsole TraceLevel Level = iota DebugLevel InfoLevel WarnLevel ErrorLevel - - FormatConsole Format = iota - FormatJson ) type Logger interface { @@ -128,13 +122,7 @@ func configureLogging() { rootLogLevel = DefaultLogLevel } - logFormat := DefaultLogFormat - envLogFormat := strings.ToUpper(os.Getenv(EnvKeyLogFormat)) - if envLogFormat == "JSON" { - logFormat = FormatJson - } - - rootLogger = newZapRootLogger("flogo", logFormat) + rootLogger = newZapRootLogger("flogo") SetLogLevel(rootLogger, rootLogLevel) } diff --git a/support/log/zap.go b/support/log/zap.go index 8b806b37..5998dc65 100644 --- a/support/log/zap.go +++ b/support/log/zap.go @@ -2,6 +2,9 @@ package log import ( "fmt" + + "github.com/project-flogo/core/support/log/zapconfig" + "github.com/project-flogo/core/support/log/zapcores" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) @@ -135,9 +138,20 @@ func toZapLogLevel(level Level) zapcore.Level { return zapcore.InfoLevel } -func newZapRootLogger(name string, format Format) Logger { +func newZapRootLogger(name string) Logger { + + zl, lvl, _ := newZapLogger() - zl, lvl, _ := newZapLogger(format) + // appending all available cores together + if len(zapcores.RegisteredCores()) != 0 { + for _, value := range zapcores.RegisteredCores() { + zl = zl.WithOptions( + zap.WrapCore( + func(c zapcore.Core) zapcore.Core { + return zapcore.NewTee(value, zl.Core()) + })) + } + } var rootLogger Logger if name == "" { @@ -147,64 +161,37 @@ func newZapRootLogger(name string, format Format) Logger { } if traceEnabled { - tl, _, _ := newZapTraceLogger(format) + tl, _, _ := newZapTraceLogger() + + // appending all available cores together for tracing logs + if len(zapcores.RegisteredTraceCores()) != 0 { + for _, value := range zapcores.RegisteredTraceCores() { + tl = tl.WithOptions( + zap.WrapCore( + func(c zapcore.Core) zapcore.Core { + return zapcore.NewTee(value, tl.Core()) + })) + } + } + traceLogger = tl.Sugar() } return rootLogger } -func newZapLogger(logFormat Format) (*zap.Logger, *zap.AtomicLevel, error) { - cfg := zap.NewProductionConfig() - cfg.DisableCaller = true - - eCfg := cfg.EncoderConfig - eCfg.TimeKey = "timestamp" - eCfg.EncodeTime = zapcore.ISO8601TimeEncoder - //eCfg.EncodeTime = zapcore.EpochNanosTimeEncoder - - if logFormat == FormatConsole { - eCfg.EncodeLevel = zapcore.CapitalLevelEncoder - cfg.Encoding = "console" - eCfg.EncodeName = nameEncoder - } - - cfg.EncoderConfig = eCfg +func newZapLogger() (*zap.Logger, *zap.AtomicLevel, error) { - lvl := cfg.Level - zl, err := cfg.Build(zap.AddCallerSkip(1)) + zl, err := zapconfig.DefaultCfg().LogCfg().Build(zap.AddCallerSkip(1)) - return zl, &lvl, err + return zl, zapconfig.DefaultCfg().LogLvl(), err } -func newZapTraceLogger(logFormat Format) (*zap.Logger, *zap.AtomicLevel, error) { - cfg := zap.NewProductionConfig() - eCfg := cfg.EncoderConfig - eCfg.TimeKey = "timestamp" - eCfg.EncodeTime = zapcore.ISO8601TimeEncoder +func newZapTraceLogger() (*zap.Logger, *zap.AtomicLevel, error) { - if logFormat == FormatConsole { - eCfg.EncodeLevel = zapcore.CapitalLevelEncoder - cfg.Encoding = "console" - eCfg.EncodeName = nameEncoder - eCfg.EncodeLevel = traceLevelEncoder - } - - cfg.EncoderConfig = eCfg - - lvl := cfg.Level - lvl.SetLevel(zapcore.DebugLevel) - zl, err := cfg.Build(zap.AddCallerSkip(1)) - - return zl, &lvl, err -} - -func traceLevelEncoder(l zapcore.Level, enc zapcore.PrimitiveArrayEncoder) { - enc.AppendString("[TRACE]") -} + zl, err := zapconfig.DefaultCfg().TraceLogCfg().Build(zap.AddCallerSkip(1)) -func nameEncoder(loggerName string, enc zapcore.PrimitiveArrayEncoder) { - enc.AppendString("[" + loggerName + "] -") + return zl, zapconfig.DefaultCfg().TraceLogLvl(), err } func newZapChildLogger(logger Logger, name string) (Logger, error) { diff --git a/support/log/zapconfig/zapconfig.go b/support/log/zapconfig/zapconfig.go new file mode 100644 index 00000000..0d4c1feb --- /dev/null +++ b/support/log/zapconfig/zapconfig.go @@ -0,0 +1,114 @@ +package zapconfig + +import ( + "os" + "strings" + + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +type Format int + +const ( + EnvKeyLogFormat = "FLOGO_LOG_FORMAT" + DefaultLogFormat = FormatConsole + FormatConsole Format = iota + FormatJSON +) + +type defaultCfgImpl struct { + logConfig zap.Config + logLevel *zap.AtomicLevel + traceLogConfig zap.Config + traceLogLevel *zap.AtomicLevel +} + +// DefaultConfig returns default configuration values +type DefaultConfig interface { + LogCfg() zap.Config + LogLvl() *zap.AtomicLevel + TraceLogCfg() zap.Config + TraceLogLvl() *zap.AtomicLevel +} + +var defaultCfg DefaultConfig + +func init() { + defaultCfg = createDefaultConfiguration() +} + +// DefaultCfg returns default configuration +func DefaultCfg() DefaultConfig { + return defaultCfg +} + +func (d *defaultCfgImpl) LogCfg() zap.Config { + return d.logConfig +} + +func (d *defaultCfgImpl) LogLvl() *zap.AtomicLevel { + return d.logLevel +} + +func (d *defaultCfgImpl) TraceLogCfg() zap.Config { + return d.traceLogConfig +} + +func (d *defaultCfgImpl) TraceLogLvl() *zap.AtomicLevel { + return d.traceLogLevel +} + +func createDefaultConfiguration() DefaultConfig { + + logFormat := DefaultLogFormat + envLogFormat := strings.ToUpper(os.Getenv(EnvKeyLogFormat)) + if envLogFormat == "JSON" { + logFormat = FormatJSON + } + + cfg := zap.NewProductionConfig() + cfg.DisableCaller = true + + eCfg := cfg.EncoderConfig + eCfg.TimeKey = "timestamp" + eCfg.EncodeTime = zapcore.ISO8601TimeEncoder + //eCfg.EncodeTime = zapcore.EpochNanosTimeEncoder + + if logFormat == FormatConsole { + eCfg.EncodeLevel = zapcore.CapitalLevelEncoder + cfg.Encoding = "console" + eCfg.EncodeName = nameEncoder + } + + cfg.EncoderConfig = eCfg + + lvl := cfg.Level + + // trace log configuration + tcfg := cfg + + if strings.Compare(tcfg.Encoding, "console") == 0 { + tcfg.EncoderConfig.EncodeLevel = traceLevelEncoder + } + + tlvl := tcfg.Level + tlvl.SetLevel(zapcore.DebugLevel) + + defaultCfg := &defaultCfgImpl{ + logConfig: cfg, + logLevel: &lvl, + traceLogConfig: tcfg, + traceLogLevel: &tlvl, + } + + return defaultCfg +} + +func nameEncoder(loggerName string, enc zapcore.PrimitiveArrayEncoder) { + enc.AppendString("[" + loggerName + "] -") +} + +func traceLevelEncoder(l zapcore.Level, enc zapcore.PrimitiveArrayEncoder) { + enc.AppendString("[TRACE]") +} diff --git a/support/log/zapcores/zapcores.go b/support/log/zapcores/zapcores.go new file mode 100644 index 00000000..59119001 --- /dev/null +++ b/support/log/zapcores/zapcores.go @@ -0,0 +1,36 @@ +package zapcores + +import ( + "go.uber.org/zap/zapcore" +) + +// zapCores holds log cores +var zapCores map[string]zapcore.Core + +// zapTraceCores holds trace log cores +var zapTraceCores map[string]zapcore.Core + +func init() { + zapCores = make(map[string]zapcore.Core) + zapTraceCores = make(map[string]zapcore.Core) +} + +// RegisterLogCore adds core to zapCores +func RegisterLogCore(name string, core zapcore.Core) { + zapCores[name] = core +} + +// RegisterTraceLogCore adds trace core to zapTraceCores +func RegisterTraceLogCore(name string, core zapcore.Core) { + zapTraceCores[name] = core +} + +// RegisteredCores returns complete log core map +func RegisteredCores() map[string]zapcore.Core { + return zapCores +} + +// RegisteredTraceCores returns complete trace log core map +func RegisteredTraceCores() map[string]zapcore.Core { + return zapTraceCores +}