From c429488738ae97b29794cf589d41c93037d3f7f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Michaud?= Date: Mon, 9 Mar 2020 20:57:53 +0100 Subject: [PATCH] [FEATURE] [BREAKING] Support writing logs in a file. (#686) * [FEATURE] Support writing logs in a file. * Add documentation about logs file path. * Rename logs_level and logs_file_path into log_level and log_file_path. * Update BREAKING.md Fixes #338 Co-authored-by: Amir Zarrinkafsh --- BREAKING.md | 4 +++ cmd/authelia/main.go | 14 +++++--- config.template.yml | 4 ++- docs/configuration/miscellaneous.md | 15 ++++++-- internal/configuration/reader_test.go | 2 +- .../configuration/schema/configuration.go | 3 +- .../configuration/test_resources/config.yml | 2 +- .../configuration/validator/configuration.go | 6 ++-- .../validator/configuration_test.go | 8 ++--- internal/logging/logger.go | 24 +++++++++---- internal/logging/logger_test.go | 34 +++++++++++++++++++ internal/suites/BypassAll/configuration.yml | 2 +- internal/suites/Docker/configuration.yml | 2 +- internal/suites/DuoPush/configuration.yml | 2 +- internal/suites/HAProxy/configuration.yml | 2 +- .../suites/HighAvailability/configuration.yml | 2 +- internal/suites/LDAP/configuration.yml | 2 +- internal/suites/Mariadb/configuration.yml | 2 +- internal/suites/MySQL/configuration.yml | 2 +- internal/suites/NetworkACL/configuration.yml | 2 +- .../suites/OneFactorOnly/configuration.yml | 2 +- internal/suites/Postgres/configuration.yml | 2 +- .../suites/ShortTimeouts/configuration.yml | 2 +- internal/suites/Standalone/configuration.yml | 2 +- internal/suites/Traefik/configuration.yml | 2 +- internal/suites/Traefik2/configuration.yml | 2 +- .../kube/authelia/configs/configuration.yml | 2 +- 27 files changed, 108 insertions(+), 40 deletions(-) create mode 100644 internal/logging/logger_test.go diff --git a/BREAKING.md b/BREAKING.md index e11d3b9e2..bc341323b 100644 --- a/BREAKING.md +++ b/BREAKING.md @@ -6,6 +6,10 @@ recommended not to use the 'latest' Docker image tag blindly but pick a version and read this documentation before upgrading. This is where you will get information about breaking changes and about what you should do to overcome those changes. +## Breaking in v4.7.0 + +`logs_level` configuration key has been renamed to `log_level`. + ## Breaking in v4.0.0 Authelia has been rewritten in Go for better code maintainability and for performance and diff --git a/cmd/authelia/main.go b/cmd/authelia/main.go index 5dd849458..2ed6592a8 100644 --- a/cmd/authelia/main.go +++ b/cmd/authelia/main.go @@ -29,10 +29,6 @@ func startServer() { log.Fatal(errors.New("No config file path provided")) } - if os.Getenv("ENVIRONMENT") == "dev" { - logging.Logger().Info("===> Authelia is running in development mode. <===") - } - config, errs := configuration.Read(configPathFlag) if len(errs) > 0 { @@ -42,7 +38,11 @@ func startServer() { panic(errors.New("Some errors have been reported")) } - switch config.LogsLevel { + if err := logging.InitializeLogger(config.LogFilePath); err != nil { + log.Fatalf("Cannot initialize logger: %v", err) + } + + switch config.LogLevel { case "info": logging.Logger().Info("Logging severity set to info") logging.SetLevel(logrus.InfoLevel) @@ -56,6 +56,10 @@ func startServer() { logging.SetLevel(logrus.TraceLevel) } + if os.Getenv("ENVIRONMENT") == "dev" { + logging.Logger().Info("===> Authelia is running in development mode. <===") + } + var userProvider authentication.UserProvider if config.AuthenticationBackend.File != nil { diff --git a/config.template.yml b/config.template.yml index 6cdb1c5d5..dd063f53c 100644 --- a/config.template.yml +++ b/config.template.yml @@ -9,7 +9,9 @@ port: 9091 # tls_cert: /var/lib/authelia/ssl/cert.pem # Level of verbosity for logs: info, debug, trace -logs_level: debug +log_level: debug +## File path where the logs will be written. If not set logs are written to stdout. +# log_file_path: /var/log/authelia # The secret used to generate JWT tokens when validating user identity by # email confirmation. diff --git a/docs/configuration/miscellaneous.md b/docs/configuration/miscellaneous.md index 246a55c42..824313b60 100644 --- a/docs/configuration/miscellaneous.md +++ b/docs/configuration/miscellaneous.md @@ -29,14 +29,25 @@ following configuration options: tls_cert: /var/lib/authelia/ssl/cert.pem -## Logs level +## Log + +### Log level `optional: true` Defines the level of logs used by Authelia. This level can be set to `trace`, `debug`, `info`. - logs_level: debug + log_level: debug + +### Log file path + +`optional: true` + +Logs can be stored in a file when file path is provided. Otherwise logs +are written to standard output. + + log_file_path: /var/log/authelia.log ## JWT Secret diff --git a/internal/configuration/reader_test.go b/internal/configuration/reader_test.go index 5e455e611..92e0ce9ec 100644 --- a/internal/configuration/reader_test.go +++ b/internal/configuration/reader_test.go @@ -23,7 +23,7 @@ func TestShouldParseConfigFile(t *testing.T) { require.Len(t, errors, 0) assert.Equal(t, 9091, config.Port) - assert.Equal(t, "debug", config.LogsLevel) + assert.Equal(t, "debug", config.LogLevel) assert.Equal(t, "https://home.example.com:8080/", config.DefaultRedirectionURL) assert.Equal(t, "authelia.com", config.TOTP.Issuer) assert.Equal(t, "secret_from_env", config.JWTSecret) diff --git a/internal/configuration/schema/configuration.go b/internal/configuration/schema/configuration.go index d7c518cac..f4178ca7e 100644 --- a/internal/configuration/schema/configuration.go +++ b/internal/configuration/schema/configuration.go @@ -7,7 +7,8 @@ type Configuration struct { TLSCert string `mapstructure:"tls_cert"` TLSKey string `mapstructure:"tls_key"` - LogsLevel string `mapstructure:"logs_level"` + LogLevel string `mapstructure:"log_level"` + LogFilePath string `mapstructure:"log_file_path"` // This secret is used by the identity validation process to forge JWT tokens // representing the permission to proceed with the operation. diff --git a/internal/configuration/test_resources/config.yml b/internal/configuration/test_resources/config.yml index 8bedc2845..833cadd15 100644 --- a/internal/configuration/test_resources/config.yml +++ b/internal/configuration/test_resources/config.yml @@ -5,7 +5,7 @@ host: 127.0.0.1 port: 9091 -logs_level: debug +log_level: debug default_redirection_url: https://home.example.com:8080/ totp: diff --git a/internal/configuration/validator/configuration.go b/internal/configuration/validator/configuration.go index 2e9934bcf..890b2bdc6 100644 --- a/internal/configuration/validator/configuration.go +++ b/internal/configuration/validator/configuration.go @@ -8,7 +8,7 @@ import ( ) var defaultPort = 8080 -var defaultLogsLevel = "info" +var defaultLogLevel = "info" // Validate and adapt the configuration read from file. func Validate(configuration *schema.Configuration, validator *schema.StructValidator) { @@ -20,8 +20,8 @@ func Validate(configuration *schema.Configuration, validator *schema.StructValid configuration.Port = defaultPort } - if configuration.LogsLevel == "" { - configuration.LogsLevel = defaultLogsLevel + if configuration.LogLevel == "" { + configuration.LogLevel = defaultLogLevel } if configuration.TLSKey != "" && configuration.TLSCert == "" { diff --git a/internal/configuration/validator/configuration_test.go b/internal/configuration/validator/configuration_test.go index 24faa68b4..83c6d6f59 100644 --- a/internal/configuration/validator/configuration_test.go +++ b/internal/configuration/validator/configuration_test.go @@ -12,7 +12,7 @@ func newDefaultConfig() schema.Configuration { config := schema.Configuration{} config.Host = "127.0.0.1" config.Port = 9090 - config.LogsLevel = "info" + config.LogLevel = "info" config.JWTSecret = "a_secret" config.AuthenticationBackend.File = new(schema.FileAuthenticationBackendConfiguration) config.AuthenticationBackend.File.Path = "/a/path" @@ -40,7 +40,7 @@ func TestShouldNotUpdateConfig(t *testing.T) { require.Len(t, validator.Errors(), 0) assert.Equal(t, 9090, config.Port) - assert.Equal(t, "info", config.LogsLevel) + assert.Equal(t, "info", config.LogLevel) } func TestShouldValidateAndUpdatePort(t *testing.T) { @@ -68,12 +68,12 @@ func TestShouldValidateAndUpdateHost(t *testing.T) { func TestShouldValidateAndUpdateLogsLevel(t *testing.T) { validator := schema.NewStructValidator() config := newDefaultConfig() - config.LogsLevel = "" + config.LogLevel = "" Validate(&config, validator) require.Len(t, validator.Errors(), 0) - assert.Equal(t, "info", config.LogsLevel) + assert.Equal(t, "info", config.LogLevel) } func TestShouldEnsureNotifierConfigIsProvided(t *testing.T) { diff --git a/internal/logging/logger.go b/internal/logging/logger.go index e83c31781..1d9338bf8 100644 --- a/internal/logging/logger.go +++ b/internal/logging/logger.go @@ -1,16 +1,12 @@ package logging import ( + "os" + logrus_stack "github.com/Gurpartap/logrus-stack" "github.com/sirupsen/logrus" ) -func init() { - callerLevels := []logrus.Level{} - stackLevels := []logrus.Level{logrus.PanicLevel, logrus.FatalLevel, logrus.ErrorLevel} - logrus.AddHook(logrus_stack.NewHook(callerLevels, stackLevels)) -} - // Logger return the standard logrus logger. func Logger() *logrus.Logger { return logrus.StandardLogger() @@ -20,3 +16,19 @@ func Logger() *logrus.Logger { func SetLevel(level logrus.Level) { logrus.SetLevel(level) } + +// InitializeLogger initialize logger +func InitializeLogger(filename string) error { + callerLevels := []logrus.Level{} + stackLevels := []logrus.Level{logrus.PanicLevel, logrus.FatalLevel, logrus.ErrorLevel} + logrus.AddHook(logrus_stack.NewHook(callerLevels, stackLevels)) + + if filename != "" { + f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE, 0600) + if err != nil { + return err + } + logrus.SetOutput(f) + } + return nil +} diff --git a/internal/logging/logger_test.go b/internal/logging/logger_test.go new file mode 100644 index 000000000..6a92ca874 --- /dev/null +++ b/internal/logging/logger_test.go @@ -0,0 +1,34 @@ +package logging + +import ( + "fmt" + "io/ioutil" + "log" + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestShouldWriteLogsToFile(t *testing.T) { + dir, err := ioutil.TempDir("/tmp", "logs-dir") + if err != nil { + log.Fatal(err) + } + defer os.RemoveAll(dir) + + path := fmt.Sprintf("%s/authelia.log", dir) + err = InitializeLogger(path) + require.NoError(t, err) + + Logger().Info("This is a test") + + f, err := os.OpenFile(path, os.O_RDONLY, 0) + require.NoError(t, err) + + b, err := ioutil.ReadAll(f) + require.NoError(t, err) + + assert.Contains(t, string(b), "level=info msg=\"This is a test\"\n") +} diff --git a/internal/suites/BypassAll/configuration.yml b/internal/suites/BypassAll/configuration.yml index 1ef411b6e..de4fe375c 100644 --- a/internal/suites/BypassAll/configuration.yml +++ b/internal/suites/BypassAll/configuration.yml @@ -4,7 +4,7 @@ port: 9091 -logs_level: debug +log_level: debug jwt_secret: unsecure_secret diff --git a/internal/suites/Docker/configuration.yml b/internal/suites/Docker/configuration.yml index 7e861d7de..0b1abef1d 100644 --- a/internal/suites/Docker/configuration.yml +++ b/internal/suites/Docker/configuration.yml @@ -4,7 +4,7 @@ port: 9091 -logs_level: debug +log_level: debug default_redirection_url: https://home.example.com:8080/ diff --git a/internal/suites/DuoPush/configuration.yml b/internal/suites/DuoPush/configuration.yml index 343f4d52d..028d3df7d 100644 --- a/internal/suites/DuoPush/configuration.yml +++ b/internal/suites/DuoPush/configuration.yml @@ -4,7 +4,7 @@ port: 9091 -logs_level: trace +log_level: trace default_redirection_url: https://home.example.com:8080/ diff --git a/internal/suites/HAProxy/configuration.yml b/internal/suites/HAProxy/configuration.yml index a69c05991..54283cd34 100644 --- a/internal/suites/HAProxy/configuration.yml +++ b/internal/suites/HAProxy/configuration.yml @@ -4,7 +4,7 @@ port: 9091 -logs_level: debug +log_level: debug jwt_secret: unsecure_secret diff --git a/internal/suites/HighAvailability/configuration.yml b/internal/suites/HighAvailability/configuration.yml index b3608e2cc..facf8edd7 100644 --- a/internal/suites/HighAvailability/configuration.yml +++ b/internal/suites/HighAvailability/configuration.yml @@ -8,7 +8,7 @@ port: 9091 # Log level # # Level of verbosity for logs -logs_level: debug +log_level: debug jwt_secret: unsecure_secret diff --git a/internal/suites/LDAP/configuration.yml b/internal/suites/LDAP/configuration.yml index 9d17e4076..6fb61a9eb 100644 --- a/internal/suites/LDAP/configuration.yml +++ b/internal/suites/LDAP/configuration.yml @@ -4,7 +4,7 @@ port: 9091 -logs_level: debug +log_level: debug default_redirection_url: https://home.example.com:8080/ diff --git a/internal/suites/Mariadb/configuration.yml b/internal/suites/Mariadb/configuration.yml index 5daa83cbb..c67052bc1 100644 --- a/internal/suites/Mariadb/configuration.yml +++ b/internal/suites/Mariadb/configuration.yml @@ -4,7 +4,7 @@ port: 9091 -logs_level: debug +log_level: debug default_redirection_url: https://home.example.com:8080/ diff --git a/internal/suites/MySQL/configuration.yml b/internal/suites/MySQL/configuration.yml index cdf215996..7d521eea8 100644 --- a/internal/suites/MySQL/configuration.yml +++ b/internal/suites/MySQL/configuration.yml @@ -4,7 +4,7 @@ port: 9091 -logs_level: debug +log_level: debug default_redirection_url: https://home.example.com:8080/ diff --git a/internal/suites/NetworkACL/configuration.yml b/internal/suites/NetworkACL/configuration.yml index 8a79c1677..e10b8d297 100644 --- a/internal/suites/NetworkACL/configuration.yml +++ b/internal/suites/NetworkACL/configuration.yml @@ -4,7 +4,7 @@ port: 9091 -logs_level: debug +log_level: debug jwt_secret: unsecure_password diff --git a/internal/suites/OneFactorOnly/configuration.yml b/internal/suites/OneFactorOnly/configuration.yml index eb8c17279..5ff1e87fe 100644 --- a/internal/suites/OneFactorOnly/configuration.yml +++ b/internal/suites/OneFactorOnly/configuration.yml @@ -4,7 +4,7 @@ port: 9091 -logs_level: debug +log_level: debug default_redirection_url: https://home.example.com:8080/ diff --git a/internal/suites/Postgres/configuration.yml b/internal/suites/Postgres/configuration.yml index c75dabd05..a33794a2a 100644 --- a/internal/suites/Postgres/configuration.yml +++ b/internal/suites/Postgres/configuration.yml @@ -4,7 +4,7 @@ port: 9091 -logs_level: debug +log_level: debug default_redirection_url: https://home.example.com:8080/ diff --git a/internal/suites/ShortTimeouts/configuration.yml b/internal/suites/ShortTimeouts/configuration.yml index 9988c1d3c..05cdb71cb 100644 --- a/internal/suites/ShortTimeouts/configuration.yml +++ b/internal/suites/ShortTimeouts/configuration.yml @@ -4,7 +4,7 @@ port: 9091 -logs_level: debug +log_level: debug jwt_secret: unsecure_secret diff --git a/internal/suites/Standalone/configuration.yml b/internal/suites/Standalone/configuration.yml index 4fe68db98..91aa67dec 100644 --- a/internal/suites/Standalone/configuration.yml +++ b/internal/suites/Standalone/configuration.yml @@ -6,7 +6,7 @@ port: 9091 tls_cert: /var/lib/authelia/ssl/cert.pem tls_key: /var/lib/authelia/ssl/key.pem -logs_level: debug +log_level: debug authentication_backend: file: diff --git a/internal/suites/Traefik/configuration.yml b/internal/suites/Traefik/configuration.yml index b0343f775..1c849b8ea 100644 --- a/internal/suites/Traefik/configuration.yml +++ b/internal/suites/Traefik/configuration.yml @@ -4,7 +4,7 @@ port: 9091 -logs_level: debug +log_level: debug jwt_secret: unsecure_secret diff --git a/internal/suites/Traefik2/configuration.yml b/internal/suites/Traefik2/configuration.yml index b0343f775..1c849b8ea 100644 --- a/internal/suites/Traefik2/configuration.yml +++ b/internal/suites/Traefik2/configuration.yml @@ -4,7 +4,7 @@ port: 9091 -logs_level: debug +log_level: debug jwt_secret: unsecure_secret diff --git a/internal/suites/example/kube/authelia/configs/configuration.yml b/internal/suites/example/kube/authelia/configs/configuration.yml index 97fae4378..3fa78e4e4 100644 --- a/internal/suites/example/kube/authelia/configs/configuration.yml +++ b/internal/suites/example/kube/authelia/configs/configuration.yml @@ -3,7 +3,7 @@ ############################################################### port: 80 -logs_level: debug +log_level: debug default_redirection_url: https://home.example.com:8080