From 069b4879f7e1905bc00152f8f714daa75831459e Mon Sep 17 00:00:00 2001 From: Tristan Claverie Date: Tue, 19 Dec 2017 09:21:48 +0100 Subject: [PATCH] Add support for several logging hooks at the same time and log to a directory Signed-off-by: Tristan Claverie --- .../cmd/dendrite-client-api-server/main.go | 4 +- .../dendrite-federation-api-server/main.go | 4 +- .../dendrite-federation-sender-server/main.go | 4 +- .../cmd/dendrite-media-api-server/main.go | 4 +- .../cmd/dendrite-monolith-server/main.go | 4 +- .../dendrite-public-rooms-api-server/main.go | 4 +- .../dendrite/cmd/dendrite-room-server/main.go | 4 +- .../cmd/dendrite-sync-api-server/main.go | 4 +- .../matrix-org/dendrite/common/log.go | 74 ++++++++++++++++--- 9 files changed, 89 insertions(+), 17 deletions(-) diff --git a/src/github.com/matrix-org/dendrite/cmd/dendrite-client-api-server/main.go b/src/github.com/matrix-org/dendrite/cmd/dendrite-client-api-server/main.go index 07f815b89..e1bfc5a40 100644 --- a/src/github.com/matrix-org/dendrite/cmd/dendrite-client-api-server/main.go +++ b/src/github.com/matrix-org/dendrite/cmd/dendrite-client-api-server/main.go @@ -35,6 +35,8 @@ import ( sarama "gopkg.in/Shopify/sarama.v1" ) +const componentName = "clientapi" + var ( configPath = flag.String("config", "dendrite.yaml", "The path to the config file, For more information see the config file in this repository") ) @@ -49,7 +51,7 @@ func main() { log.Fatalf("Invalid config file: %s", err) } - common.SetupFileLogging(string(cfg.Logging.FPath), cfg.Derived.LogLevel) + common.SetupHookLogging(cfg.Logging, componentName) closer, err := cfg.SetupTracing("DendriteClientAPI") if err != nil { diff --git a/src/github.com/matrix-org/dendrite/cmd/dendrite-federation-api-server/main.go b/src/github.com/matrix-org/dendrite/cmd/dendrite-federation-api-server/main.go index 4e199f92e..805fec70c 100644 --- a/src/github.com/matrix-org/dendrite/cmd/dendrite-federation-api-server/main.go +++ b/src/github.com/matrix-org/dendrite/cmd/dendrite-federation-api-server/main.go @@ -31,6 +31,8 @@ import ( log "github.com/sirupsen/logrus" ) +const componentName = "federationapi" + var ( configPath = flag.String("config", "dendrite.yaml", "The path to the config file. For more information, see the config file in this repository.") ) @@ -48,7 +50,7 @@ func main() { log.Fatalf("Invalid config file: %s", err) } - common.SetupFileLogging(string(cfg.Logging.FPath), cfg.Derived.LogLevel) + common.SetupHookLogging(cfg.Logging, componentName) closer, err := cfg.SetupTracing("DendriteFederationAPI") if err != nil { diff --git a/src/github.com/matrix-org/dendrite/cmd/dendrite-federation-sender-server/main.go b/src/github.com/matrix-org/dendrite/cmd/dendrite-federation-sender-server/main.go index d55c16e71..439c3424c 100644 --- a/src/github.com/matrix-org/dendrite/cmd/dendrite-federation-sender-server/main.go +++ b/src/github.com/matrix-org/dendrite/cmd/dendrite-federation-sender-server/main.go @@ -31,6 +31,8 @@ import ( sarama "gopkg.in/Shopify/sarama.v1" ) +const componentName = "federationsender" + var configPath = flag.String("config", "dendrite.yaml", "The path to the config file. For more information, see the config file in this repository.") func main() { @@ -46,7 +48,7 @@ func main() { log.Fatalf("Invalid config file: %s", err) } - common.SetupFileLogging(string(cfg.Logging.FPath), cfg.Derived.LogLevel) + common.SetupHookLogging(cfg.Logging, componentName) closer, err := cfg.SetupTracing("DendriteFederationSender") if err != nil { diff --git a/src/github.com/matrix-org/dendrite/cmd/dendrite-media-api-server/main.go b/src/github.com/matrix-org/dendrite/cmd/dendrite-media-api-server/main.go index 050edf511..dd7612ccb 100644 --- a/src/github.com/matrix-org/dendrite/cmd/dendrite-media-api-server/main.go +++ b/src/github.com/matrix-org/dendrite/cmd/dendrite-media-api-server/main.go @@ -29,6 +29,8 @@ import ( log "github.com/sirupsen/logrus" ) +const componentName = "mediaapi" + var ( configPath = flag.String("config", "dendrite.yaml", "The path to the config file. For more information, see the config file in this repository.") ) @@ -46,7 +48,7 @@ func main() { log.Fatalf("Invalid config file: %s", err) } - common.SetupFileLogging(string(cfg.Logging.FPath), cfg.Derived.LogLevel) + common.SetupHookLogging(cfg.Logging, componentName) closer, err := cfg.SetupTracing("DendriteMediaAPI") if err != nil { diff --git a/src/github.com/matrix-org/dendrite/cmd/dendrite-monolith-server/main.go b/src/github.com/matrix-org/dendrite/cmd/dendrite-monolith-server/main.go index 27b98c200..ee111820f 100644 --- a/src/github.com/matrix-org/dendrite/cmd/dendrite-monolith-server/main.go +++ b/src/github.com/matrix-org/dendrite/cmd/dendrite-monolith-server/main.go @@ -61,6 +61,8 @@ import ( sarama "gopkg.in/Shopify/sarama.v1" ) +const componentName = "monolith" + var ( configPath = flag.String("config", "dendrite.yaml", "The path to the config file. For more information, see the config file in this repository.") httpBindAddr = flag.String("http-bind-address", ":8008", "The HTTP listening port for the server") @@ -82,7 +84,7 @@ func main() { log.Fatalf("Invalid config file: %s", err) } - common.SetupFileLogging(string(cfg.Logging.FPath), cfg.Derived.LogLevel) + common.SetupHookLogging(cfg.Logging, componentName) closer, err := cfg.SetupTracing("DendriteMonolith") if err != nil { diff --git a/src/github.com/matrix-org/dendrite/cmd/dendrite-public-rooms-api-server/main.go b/src/github.com/matrix-org/dendrite/cmd/dendrite-public-rooms-api-server/main.go index 953bd2c20..33f80cb43 100644 --- a/src/github.com/matrix-org/dendrite/cmd/dendrite-public-rooms-api-server/main.go +++ b/src/github.com/matrix-org/dendrite/cmd/dendrite-public-rooms-api-server/main.go @@ -31,6 +31,8 @@ import ( sarama "gopkg.in/Shopify/sarama.v1" ) +const componentName = "publicroomsapi" + var configPath = flag.String("config", "dendrite.yaml", "The path to the config file. For more information, see the config file in this repository.") func main() { @@ -46,7 +48,7 @@ func main() { log.Fatalf("Invalid config file: %s", err) } - common.SetupFileLogging(string(cfg.Logging.FPath), cfg.Derived.LogLevel) + common.SetupHookLogging(cfg.Logging, componentName) closer, err := cfg.SetupTracing("DendritePublicRoomsAPI") if err != nil { diff --git a/src/github.com/matrix-org/dendrite/cmd/dendrite-room-server/main.go b/src/github.com/matrix-org/dendrite/cmd/dendrite-room-server/main.go index 4713046c4..907a456d5 100644 --- a/src/github.com/matrix-org/dendrite/cmd/dendrite-room-server/main.go +++ b/src/github.com/matrix-org/dendrite/cmd/dendrite-room-server/main.go @@ -30,6 +30,8 @@ import ( sarama "gopkg.in/Shopify/sarama.v1" ) +const componentName = "roomserver" + var ( configPath = flag.String("config", "dendrite.yaml", "The path to the config file. For more information, see the config file in this repository.") ) @@ -47,7 +49,7 @@ func main() { log.Fatalf("Invalid config file: %s", err) } - common.SetupFileLogging(string(cfg.Logging.FPath), cfg.Derived.LogLevel) + common.SetupHookLogging(cfg.Logging, componentName) closer, err := cfg.SetupTracing("DendriteRoomServer") if err != nil { diff --git a/src/github.com/matrix-org/dendrite/cmd/dendrite-sync-api-server/main.go b/src/github.com/matrix-org/dendrite/cmd/dendrite-sync-api-server/main.go index 4b4cf8572..5f527a17f 100644 --- a/src/github.com/matrix-org/dendrite/cmd/dendrite-sync-api-server/main.go +++ b/src/github.com/matrix-org/dendrite/cmd/dendrite-sync-api-server/main.go @@ -35,6 +35,8 @@ import ( sarama "gopkg.in/Shopify/sarama.v1" ) +const componentName = "syncapi" + var configPath = flag.String("config", "dendrite.yaml", "The path to the config file. For more information, see the config file in this repository.") func main() { @@ -50,7 +52,7 @@ func main() { log.Fatalf("Invalid config file: %s", err) } - common.SetupFileLogging(string(cfg.Logging.FPath), cfg.Derived.LogLevel) + common.SetupHookLogging(cfg.Logging, componentName) closer, err := cfg.SetupTracing("DendriteSyncAPI") if err != nil { diff --git a/src/github.com/matrix-org/dendrite/common/log.go b/src/github.com/matrix-org/dendrite/common/log.go index 0aad8e4b6..d7ea6942b 100644 --- a/src/github.com/matrix-org/dendrite/common/log.go +++ b/src/github.com/matrix-org/dendrite/common/log.go @@ -17,7 +17,9 @@ package common import ( "os" "path" + "path/filepath" + "github.com/matrix-org/dendrite/common/config" "github.com/matrix-org/dugong" "github.com/sirupsen/logrus" ) @@ -31,6 +33,27 @@ func (f utcFormatter) Format(entry *logrus.Entry) ([]byte, error) { return f.Formatter.Format(entry) } +// Wrapper hook which allows to filter entries according to their level. +// Dendrite supports multiples levels of logging at the same time, hence it is not +// possible to just use logrus.SetLevel to control that. +type logLevelHook struct { + level logrus.Level + logrus.Hook +} + +// All the levels supported by this hook. +func (h *logLevelHook) Levels() []logrus.Level { + levels := make([]logrus.Level, 0) + + for _, level := range logrus.AllLevels { + if level <= h.level { + levels = append(levels, level) + } + } + + return levels +} + // SetupStdLogging configures the logging format to standard output. Typically, it is called when the config is not yet loaded. func SetupStdLogging() { logrus.SetFormatter(&utcFormatter{ @@ -44,13 +67,46 @@ func SetupStdLogging() { }) } -// SetupFileLogging configures the logging format to a file. -func SetupFileLogging(logFile string, logLevel logrus.Level) { - logrus.SetLevel(logLevel) - if logFile != "" { - _ = os.MkdirAll(path.Dir(logFile), os.ModePerm) - logrus.AddHook(dugong.NewFSHook( - logFile, +// SetupHookLogging configures the logging hooks defined in the configuration. +// If something fails here it means that the logging was improperly configured, +// so we just exit with the error +func SetupHookLogging(hooks []config.Hook, componentName string) { + for _, hook := range hooks { + switch hook.Type { + case "file": + checkFileHookParams(hook.Params) + setupFileHook(hook, componentName) + default: + logrus.Fatalf("Unrecognized hook type: %s", hook.Type) + } + } +} + +// File type hooks should be provided a path to a directory to store log files +func checkFileHookParams(params map[string]interface{}) { + path, ok := params["path"] + if !ok { + logrus.Fatalf("Expecting a parameter \"path\" for logging hook of type \"file\"") + } + + if _, ok := path.(string); !ok { + logrus.Fatalf("Parameter \"path\" for logging hook of type \"file\" should be a string") + } +} + +// Add a new FSHook to the logger. Each component will log in its own file +func setupFileHook(hook config.Hook, componentName string) { + dirPath := (hook.Params["path"]).(string) + fullPath := filepath.Join(dirPath, componentName+".log") + + if err := os.MkdirAll(path.Dir(fullPath), os.ModePerm); err != nil { + logrus.Fatalf("Couldn't create directory %s: %q", path.Dir(fullPath), err) + } + + logrus.AddHook(&logLevelHook{ + hook.Level, + dugong.NewFSHook( + fullPath, &utcFormatter{ &logrus.TextFormatter{ TimestampFormat: "2006-01-02T15:04:05.000000000Z07:00", @@ -60,6 +116,6 @@ func SetupFileLogging(logFile string, logLevel logrus.Level) { }, }, &dugong.DailyRotationSchedule{GZip: true}, - )) - } + ), + }) }