From c6e3e179a6f46fcb3edb2668534cdfa7483939c3 Mon Sep 17 00:00:00 2001 From: kolaente Date: Sun, 31 Jan 2021 16:28:52 +0100 Subject: [PATCH] Add custom logger for watermill --- config.yml.sample | 4 ++ pkg/config/config.go | 4 ++ pkg/events/events.go | 8 ++-- pkg/log/logging.go | 1 + pkg/log/watermill_logger.go | 93 +++++++++++++++++++++++++++++++++++++ pkg/log/xorm_logger.go | 2 +- 6 files changed, 107 insertions(+), 5 deletions(-) create mode 100644 pkg/log/watermill_logger.go diff --git a/config.yml.sample b/config.yml.sample index 250610660..714a04aec 100644 --- a/config.yml.sample +++ b/config.yml.sample @@ -136,6 +136,10 @@ log: http: "stdout" # Echo has its own logging which usually is unnessecary, which is why it is disabled by default. Possible values are stdout, stderr, file or off to disable standard logging. echo: "off" + # Whether or not to log events. Useful for debugging. Possible values are stdout, stderr, file or off to disable events logging. + events: "stdout" + # The log level for event log messages. Possible values (case-insensitive) are ERROR, INFO, DEBUG. + eventslevel: "info" ratelimit: # whether or not to enable the rate limit diff --git a/pkg/config/config.go b/pkg/config/config.go index 4301a1a30..3ca6ffe61 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -101,6 +101,8 @@ const ( LogHTTP Key = `log.http` LogEcho Key = `log.echo` LogPath Key = `log.path` + LogEvents Key = `log.events` + LogEventsLevel Key = `log.eventslevel` RateLimitEnabled Key = `ratelimit.enabled` RateLimitKind Key = `ratelimit.kind` @@ -281,6 +283,8 @@ func InitDefaultConfig() { LogHTTP.setDefault("stdout") LogEcho.setDefault("off") LogPath.setDefault(ServiceRootpath.GetString() + "/logs") + LogEvents.setDefault("stdout") + LogEventsLevel.setDefault("INFO") // Rate Limit RateLimitEnabled.setDefault(false) RateLimitKind.setDefault("user") diff --git a/pkg/events/events.go b/pkg/events/events.go index ead1ada9b..f483ee33e 100644 --- a/pkg/events/events.go +++ b/pkg/events/events.go @@ -21,16 +21,14 @@ import ( "encoding/json" "time" + "code.vikunja.io/api/pkg/log" "github.com/ThreeDotsLabs/watermill" "github.com/ThreeDotsLabs/watermill/message" "github.com/ThreeDotsLabs/watermill/message/router/middleware" "github.com/ThreeDotsLabs/watermill/pubsub/gochannel" ) -var ( - pubsub *gochannel.GoChannel - logger = watermill.NewStdLogger(false, false) -) +var pubsub *gochannel.GoChannel type Event interface { TopicName() string @@ -38,6 +36,8 @@ type Event interface { } func InitEvents() (err error) { + logger := log.NewWatermillLogger() + router, err := message.NewRouter( message.RouterConfig{}, logger, diff --git a/pkg/log/logging.go b/pkg/log/logging.go index 705c0d002..8d85adae6 100644 --- a/pkg/log/logging.go +++ b/pkg/log/logging.go @@ -49,6 +49,7 @@ func InitLogger() { config.LogDatabase.Set("off") config.LogHTTP.Set("off") config.LogEcho.Set("off") + config.LogEvents.Set("off") return } diff --git a/pkg/log/watermill_logger.go b/pkg/log/watermill_logger.go new file mode 100644 index 000000000..15e900115 --- /dev/null +++ b/pkg/log/watermill_logger.go @@ -0,0 +1,93 @@ +// Vikunja is a to-do list application to facilitate your life. +// Copyright 2018-2021 Vikunja and contributors. All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public Licensee as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public Licensee for more details. +// +// You should have received a copy of the GNU Affero General Public Licensee +// along with this program. If not, see . + +package log + +import ( + "fmt" + "strings" + "time" + + "code.vikunja.io/api/pkg/config" + "github.com/ThreeDotsLabs/watermill" + "github.com/op/go-logging" + "xorm.io/xorm/log" +) + +const watermillFmt = `%{color}%{time:` + time.RFC3339Nano + `}: %{level}` + "\t" + `▶ [EVENTS] %{id:03x}%{color:reset} %{message}` + +const watermillLogModule = `vikunja_events` + +type WatermillLogger struct { + logger *logging.Logger + level log.LogLevel +} + +func NewWatermillLogger() *WatermillLogger { + lvl := strings.ToUpper(config.LogEventsLevel.GetString()) + level, err := logging.LogLevel(lvl) + if err != nil { + Criticalf("Error setting events log level %s: %s", lvl, err.Error()) + } + + watermillLogger := &WatermillLogger{ + logger: logging.MustGetLogger(watermillLogModule), + } + + logBackend := logging.NewLogBackend(GetLogWriter("events"), "", 0) + backend := logging.NewBackendFormatter(logBackend, logging.MustStringFormatter(watermillFmt+"\n")) + + backendLeveled := logging.AddModuleLevel(backend) + backendLeveled.SetLevel(level, watermillLogModule) + + watermillLogger.logger.SetBackend(backendLeveled) + + return watermillLogger +} + +func concatFields(fields watermill.LogFields) string { + full := "" + + for key, val := range fields { + full += fmt.Sprintf("%s=%s, ", key, val) + } + + if full != "" { + full = full[:len(full)-2] + } + + return full +} + +func (w *WatermillLogger) Error(msg string, err error, fields watermill.LogFields) { + w.logger.Errorf("%s: %s, %s", msg, err, concatFields(fields)) +} + +func (w *WatermillLogger) Info(msg string, fields watermill.LogFields) { + w.logger.Infof("%s, %s", msg, concatFields(fields)) +} + +func (w *WatermillLogger) Debug(msg string, fields watermill.LogFields) { + w.logger.Debugf("%s, %s", msg, concatFields(fields)) +} + +func (w *WatermillLogger) Trace(msg string, fields watermill.LogFields) { + w.logger.Debugf("%s, %s", msg, concatFields(fields)) +} + +func (w *WatermillLogger) With(fields watermill.LogFields) watermill.LoggerAdapter { + return w +} diff --git a/pkg/log/xorm_logger.go b/pkg/log/xorm_logger.go index 7b8109641..1af21cb18 100644 --- a/pkg/log/xorm_logger.go +++ b/pkg/log/xorm_logger.go @@ -44,7 +44,7 @@ func NewXormLogger(lvl string) *XormLogger { } level, err := logging.LogLevel(lvl) if err != nil { - Critical("Error setting database log level: %s", err.Error()) + Criticalf("Error setting database log level: %s", err.Error()) } xormLogger := &XormLogger{