feat: add option to keep stdout logging with log_file_path (#2037)

Currently if a `log_file_path` is defined Authelia will redirect all logging from standard output to said defined location. This change allows users to keep standard output logging along with a defined `log_file_path`.
pull/2048/head
Amir Zarrinkafsh 2021-05-31 14:02:54 +10:00 committed by GitHub
parent 03a1b004cf
commit 05df642f3e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 58 additions and 5 deletions

View File

@ -52,7 +52,7 @@ func startServer() {
} }
} }
if err := logging.InitializeLogger(config.LogFormat, config.LogFilePath); err != nil { if err := logging.InitializeLogger(config.LogFormat, config.LogFilePath, config.LogKeepStdout); err != nil {
logger.Fatalf("Cannot initialize logger: %v", err) logger.Fatalf("Cannot initialize logger: %v", err)
} }

View File

@ -43,6 +43,9 @@ log_level: debug
## File path where the logs will be written. If not set logs are written to stdout. ## File path where the logs will be written. If not set logs are written to stdout.
# log_file_path: /config/authelia.log # log_file_path: /config/authelia.log
## Whether to also log to stdout when a log_file_path is defined.
# log_keep_stdout: false
## The secret used to generate JWT tokens when validating user identity by email confirmation. JWT Secret can also be ## The secret used to generate JWT tokens when validating user identity by email confirmation. JWT Secret can also be
## set using a secret: https://www.authelia.com/docs/configuration/secrets.html ## set using a secret: https://www.authelia.com/docs/configuration/secrets.html
jwt_secret: a_very_important_secret jwt_secret: a_very_important_secret

View File

@ -158,6 +158,23 @@ they rotate and/or truncate the logs over time to prevent significant long-term
log_file_path: /config/authelia.log log_file_path: /config/authelia.log
``` ```
### log_keep_stdout
<div markdown="1">
type: boolean
{: .label .label-config .label-purple }
default: false
{: .label .label-config .label-blue }
required: no
{: .label .label-config .label-green }
</div>
Overrides the behaviour to redirect logging only to the `log_file_path`. If set to `true` logs will be written to both
standard output, and the defined logging location.
```yaml
log_keep_stdout: true
```
## jwt_secret ## jwt_secret
<div markdown="1"> <div markdown="1">
type: string type: string

View File

@ -43,6 +43,9 @@ log_level: debug
## File path where the logs will be written. If not set logs are written to stdout. ## File path where the logs will be written. If not set logs are written to stdout.
# log_file_path: /config/authelia.log # log_file_path: /config/authelia.log
## Whether to also log to stdout when a log_file_path is defined.
# log_keep_stdout: false
## The secret used to generate JWT tokens when validating user identity by email confirmation. JWT Secret can also be ## The secret used to generate JWT tokens when validating user identity by email confirmation. JWT Secret can also be
## set using a secret: https://www.authelia.com/docs/configuration/secrets.html ## set using a secret: https://www.authelia.com/docs/configuration/secrets.html
jwt_secret: a_very_important_secret jwt_secret: a_very_important_secret

View File

@ -11,6 +11,7 @@ type Configuration struct {
LogLevel string `mapstructure:"log_level"` LogLevel string `mapstructure:"log_level"`
LogFormat string `mapstructure:"log_format"` LogFormat string `mapstructure:"log_format"`
LogFilePath string `mapstructure:"log_file_path"` LogFilePath string `mapstructure:"log_file_path"`
LogKeepStdout bool `mapstructure:"log_keep_stdout"`
JWTSecret string `mapstructure:"jwt_secret"` JWTSecret string `mapstructure:"jwt_secret"`
DefaultRedirectionURL string `mapstructure:"default_redirection_url"` DefaultRedirectionURL string `mapstructure:"default_redirection_url"`

View File

@ -1,6 +1,7 @@
package logging package logging
import ( import (
"io"
"os" "os"
logrus_stack "github.com/Gurpartap/logrus-stack" logrus_stack "github.com/Gurpartap/logrus-stack"
@ -18,7 +19,7 @@ func SetLevel(level logrus.Level) {
} }
// InitializeLogger initialize logger. // InitializeLogger initialize logger.
func InitializeLogger(format, filename string) error { func InitializeLogger(format, filename string, stdout bool) error {
callerLevels := []logrus.Level{} callerLevels := []logrus.Level{}
stackLevels := []logrus.Level{logrus.PanicLevel, logrus.FatalLevel, logrus.ErrorLevel} stackLevels := []logrus.Level{logrus.PanicLevel, logrus.FatalLevel, logrus.ErrorLevel}
logrus.AddHook(logrus_stack.NewHook(callerLevels, stackLevels)) logrus.AddHook(logrus_stack.NewHook(callerLevels, stackLevels))
@ -43,7 +44,12 @@ func InitializeLogger(format, filename string) error {
}) })
} }
logrus.SetOutput(f) if stdout {
logLocations := io.MultiWriter(os.Stdout, f)
logrus.SetOutput(logLocations)
} else {
logrus.SetOutput(f)
}
} }
return nil return nil

View File

@ -20,7 +20,30 @@ func TestShouldWriteLogsToFile(t *testing.T) {
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
path := fmt.Sprintf("%s/authelia.log", dir) path := fmt.Sprintf("%s/authelia.log", dir)
err = InitializeLogger("text", path) err = InitializeLogger("text", path, false)
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")
}
func TestShouldWriteLogsToFileAndStdout(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("text", path, true)
require.NoError(t, err) require.NoError(t, err)
Logger().Info("This is a test") Logger().Info("This is a test")
@ -43,7 +66,7 @@ func TestShouldFormatLogsAsJSON(t *testing.T) {
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
path := fmt.Sprintf("%s/authelia.log", dir) path := fmt.Sprintf("%s/authelia.log", dir)
err = InitializeLogger("json", path) err = InitializeLogger("json", path, false)
require.NoError(t, err) require.NoError(t, err)
Logger().Info("This is a test") Logger().Info("This is a test")