diff --git a/cmd/authelia/main.go b/cmd/authelia/main.go index 7422bf872..8095c74d8 100644 --- a/cmd/authelia/main.go +++ b/cmd/authelia/main.go @@ -52,11 +52,17 @@ func startServer() { } } - if err := logging.InitializeLogger(config.LogFormat, config.LogFilePath, config.LogKeepStdout); err != nil { + if err := logging.InitializeLogger(config.Logging.Format, config.Logging.FilePath, config.Logging.KeepStdout); err != nil { logger.Fatalf("Cannot initialize logger: %v", err) } - switch config.LogLevel { + switch config.Logging.Level { + case "error": + logger.Info("Logging severity set to error") + logging.SetLevel(logrus.ErrorLevel) + case "warn": + logger.Info("Logging severity set to warn") + logging.SetLevel(logrus.WarnLevel) case "info": logger.Info("Logging severity set to info") logging.SetLevel(logrus.InfoLevel) diff --git a/config.template.yml b/config.template.yml index 5843bad02..72f077b28 100644 --- a/config.template.yml +++ b/config.template.yml @@ -34,17 +34,24 @@ server: ## Must be alphanumeric chars and should not contain any slashes. path: "" + ## Enables the pprof endpoint. + enable_pprof: false + + ## Enables the expvars endpoint. + enable_expvars: false + ## Level of verbosity for logs: info, debug, trace. -log_level: debug +logging: + level: debug -## Format the logs are written as: json, text. -# log_format: json + ## Format the logs are written as: json, text. + # format: json -## File path where the logs will be written. If not set logs are written to stdout. -# log_file_path: /config/authelia.log + ## File path where the logs will be written. If not set logs are written to stdout. + # file_path: /config/authelia.log -## Whether to also log to stdout when a log_file_path is defined. -# log_keep_stdout: false + ## Whether to also log to stdout when a log_file_path is defined. + # keep_stdout: false ## 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 diff --git a/docs/configuration/identity-providers/index.md b/docs/configuration/identity-providers/index.md index b5a62d945..dcebc1a30 100644 --- a/docs/configuration/identity-providers/index.md +++ b/docs/configuration/identity-providers/index.md @@ -2,7 +2,7 @@ layout: default title: Identity Providers parent: Configuration -nav_order: 12 +nav_order: 3 has_children: true --- diff --git a/docs/configuration/logging.md b/docs/configuration/logging.md new file mode 100644 index 000000000..3407e5632 --- /dev/null +++ b/docs/configuration/logging.md @@ -0,0 +1,106 @@ +--- +layout: default +title: Logging +parent: Configuration +nav_order: 4 +--- + +# Logging + +The logging section tunes the logging settings. + +## Configuration + +```yaml +logging: + level: info + format: text + file_path: "" + keep_stdout: false +``` + +## Options + +### level +
+type: string +{: .label .label-config .label-purple } +default: info +{: .label .label-config .label-blue } +required: no +{: .label .label-config .label-green } +
+ +Defines the level of logs used by Authelia. This level can be set to `trace`, `debug`, `info`, `warn`, or `error`. When +setting level to `trace`, you will generate a large amount of log entries and expose the `/debug/vars` and +`/debug/pprof/` endpoints which should not be enabled in production. + +```yaml +logging: + level: debug +``` + +### format +
+type: string +{: .label .label-config .label-purple } +default: text +{: .label .label-config .label-blue } +required: no +{: .label .label-config .label-green } +
+ +Defines the format of the logs written by Authelia. This format can be set to `json` or `text`. + +```yaml +logging: + format: json +``` + +#### JSON format +``` +{"level":"info","msg":"Logging severity set to info","time":"2020-01-01T00:00:00+11:00"} +{"level":"info","msg":"Authelia is listening for non-TLS connections on 0.0.0.0:9091","time":"2020-01-01T00:00:00+11:00"} +``` +#### Text format +``` +time="2020-01-01T00:00:00+11:00" level=info msg="Logging severity set to info" +time="2020-01-01T00:00:00+11:00" level=info msg="Authelia is listening for non-TLS connections on 0.0.0.0:9091" +``` + +### file_path +
+type: string (path) +{: .label .label-config .label-purple } +default: "" +{: .label .label-config .label-blue } +required: no +{: .label .label-config .label-green } +
+ +Logs can be stored in a file when file path is provided. Otherwise logs are written to standard output. When setting the +level to `debug` or `trace` this will generate large amount of log entries. Administrators will need to ensure that +they rotate and/or truncate the logs over time to prevent significant long-term disk usage. + +```yaml +logging: + file_path: /config/authelia.log +``` + +### keep_stdout +
+type: boolean +{: .label .label-config .label-purple } +default: false +{: .label .label-config .label-blue } +required: no +{: .label .label-config .label-green } +
+ +Overrides the behaviour to redirect logging only to the `file_path`. If set to `true` logs will be written to both +standard output, and the defined logging location. + +```yaml +logging: + keep_stdout: true +``` \ No newline at end of file diff --git a/docs/configuration/miscellaneous.md b/docs/configuration/miscellaneous.md index f3c823935..35d356f22 100644 --- a/docs/configuration/miscellaneous.md +++ b/docs/configuration/miscellaneous.md @@ -2,7 +2,7 @@ layout: default title: Miscellaneous parent: Configuration -nav_order: 3 +nav_order: 5 --- # Miscellaneous @@ -93,88 +93,6 @@ key or the CA public key which signed them (don't add the private key). certificates_directory: /config/certs/ ``` -## Logging - -### log_level -
-type: string -{: .label .label-config .label-purple } -default: info -{: .label .label-config .label-blue } -required: no -{: .label .label-config .label-green } -
- -Defines the level of logs used by Authelia. This level can be set to `trace`, `debug` or `info`. When setting log_level -to `trace`, you will generate a large amount of log entries and expose the `/debug/vars` and `/debug/pprof/` endpoints -which should not be enabled in production. - -```yaml -log_level: debug -``` - -### log_format -
-type: string -{: .label .label-config .label-purple } -default: text -{: .label .label-config .label-blue } -required: no -{: .label .label-config .label-green } -
- -Defines the format of the logs written by Authelia. This format can be set to `json` or `text`. - -```yaml -log_format: json -``` - -#### JSON format -``` -{"level":"info","msg":"Logging severity set to info","time":"2020-01-01T00:00:00+11:00"} -{"level":"info","msg":"Authelia is listening for non-TLS connections on 0.0.0.0:9091","time":"2020-01-01T00:00:00+11:00"} -``` -#### Text format -``` -time="2020-01-01T00:00:00+11:00" level=info msg="Logging severity set to info" -time="2020-01-01T00:00:00+11:00" level=info msg="Authelia is listening for non-TLS connections on 0.0.0.0:9091" -``` - -### log_file_path -
-type: string (path) -{: .label .label-config .label-purple } -default: "" -{: .label .label-config .label-blue } -required: no -{: .label .label-config .label-green } -
- -Logs can be stored in a file when file path is provided. Otherwise logs are written to standard output. When setting the -log_level to `debug` or `trace` this will generate large amount of log entries. Administrators will need to ensure that -they rotate and/or truncate the logs over time to prevent significant long-term disk usage. - -```yaml -log_file_path: /config/authelia.log -``` - -### log_keep_stdout -
-type: boolean -{: .label .label-config .label-purple } -default: false -{: .label .label-config .label-blue } -required: no -{: .label .label-config .label-green } -
- -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
type: string diff --git a/docs/configuration/notifier/index.md b/docs/configuration/notifier/index.md index fe4fa5ce1..e2abbe9df 100644 --- a/docs/configuration/notifier/index.md +++ b/docs/configuration/notifier/index.md @@ -2,7 +2,7 @@ layout: default title: Notifier parent: Configuration -nav_order: 6 +nav_order: 8 has_children: true --- diff --git a/docs/configuration/one-time-password.md b/docs/configuration/one-time-password.md index 27a8c57fa..9aa05be98 100644 --- a/docs/configuration/one-time-password.md +++ b/docs/configuration/one-time-password.md @@ -2,7 +2,7 @@ layout: default title: Time-based One-Time Password parent: Configuration -nav_order: 4 +nav_order: 6 --- # Time-based One-Time Password diff --git a/docs/configuration/regulation.md b/docs/configuration/regulation.md index 15dfd3b0d..f4567abb2 100644 --- a/docs/configuration/regulation.md +++ b/docs/configuration/regulation.md @@ -2,7 +2,7 @@ layout: default title: Regulation parent: Configuration -nav_order: 5 +nav_order: 7 --- # Regulation diff --git a/docs/configuration/secrets.md b/docs/configuration/secrets.md index c43160836..fa3374229 100644 --- a/docs/configuration/secrets.md +++ b/docs/configuration/secrets.md @@ -2,7 +2,7 @@ layout: default title: Secrets parent: Configuration -nav_order: 6 +nav_order: 8 --- # Secrets diff --git a/docs/configuration/server.md b/docs/configuration/server.md index 4c0965297..a851cb178 100644 --- a/docs/configuration/server.md +++ b/docs/configuration/server.md @@ -2,7 +2,7 @@ layout: default title: Server parent: Configuration -nav_order: 7 +nav_order: 9 --- # Server @@ -16,6 +16,8 @@ server: read_buffer_size: 4096 write_buffer_size: 4096 path: "" + enable_pprof: false + enable_expvars: false ``` ## Options @@ -72,6 +74,31 @@ server: path: authelia ``` +### enable_pprof +
+type: boolean +{: .label .label-config .label-purple } +default: false +{: .label .label-config .label-blue } +required: no +{: .label .label-config .label-green } +
+ +Enables the go pprof endpoints. + +### enable_expvars +
+type: boolean +{: .label .label-config .label-purple } +default: false +{: .label .label-config .label-blue } +required: no +{: .label .label-config .label-green } +
+ +Enables the go expvars endpoints. + + ## Additional Notes ### Buffer Sizes diff --git a/docs/configuration/session/index.md b/docs/configuration/session/index.md index a41d4a8cc..97006c2b4 100644 --- a/docs/configuration/session/index.md +++ b/docs/configuration/session/index.md @@ -2,7 +2,7 @@ layout: default title: Session parent: Configuration -nav_order: 8 +nav_order: 10 has_children: true --- diff --git a/docs/configuration/storage/index.md b/docs/configuration/storage/index.md index c77cd0e31..7c7677d82 100644 --- a/docs/configuration/storage/index.md +++ b/docs/configuration/storage/index.md @@ -2,7 +2,7 @@ layout: default title: Storage backends parent: Configuration -nav_order: 10 +nav_order: 12 has_children: true --- diff --git a/docs/configuration/theme.md b/docs/configuration/theme.md index 312b9ca4b..a34a69067 100644 --- a/docs/configuration/theme.md +++ b/docs/configuration/theme.md @@ -2,7 +2,7 @@ layout: default title: Theme parent: Configuration -nav_order: 11 +nav_order: 13 --- # Theme diff --git a/examples/compose/lite/authelia/configuration.yml b/examples/compose/lite/authelia/configuration.yml index 95c98da67..fe4a3c4cb 100644 --- a/examples/compose/lite/authelia/configuration.yml +++ b/examples/compose/lite/authelia/configuration.yml @@ -5,7 +5,8 @@ host: 0.0.0.0 port: 9091 -log_level: debug +logging: + level: debug # This secret can also be set using the env variables AUTHELIA_JWT_SECRET_FILE jwt_secret: a_very_important_secret default_redirection_url: https://public.example.com diff --git a/examples/compose/local/authelia/configuration.yml b/examples/compose/local/authelia/configuration.yml index 70801f8c8..8f89c2bfe 100644 --- a/examples/compose/local/authelia/configuration.yml +++ b/examples/compose/local/authelia/configuration.yml @@ -5,7 +5,8 @@ host: 0.0.0.0 port: 9091 -log_level: debug +logging: + level: debug jwt_secret: a_very_important_secret default_redirection_url: https://public.example.com totp: diff --git a/internal/configuration/config.template.yml b/internal/configuration/config.template.yml index 5843bad02..72f077b28 100644 --- a/internal/configuration/config.template.yml +++ b/internal/configuration/config.template.yml @@ -34,17 +34,24 @@ server: ## Must be alphanumeric chars and should not contain any slashes. path: "" + ## Enables the pprof endpoint. + enable_pprof: false + + ## Enables the expvars endpoint. + enable_expvars: false + ## Level of verbosity for logs: info, debug, trace. -log_level: debug +logging: + level: debug -## Format the logs are written as: json, text. -# log_format: json + ## Format the logs are written as: json, text. + # format: json -## File path where the logs will be written. If not set logs are written to stdout. -# log_file_path: /config/authelia.log + ## File path where the logs will be written. If not set logs are written to stdout. + # file_path: /config/authelia.log -## Whether to also log to stdout when a log_file_path is defined. -# log_keep_stdout: false + ## Whether to also log to stdout when a log_file_path is defined. + # keep_stdout: false ## 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 diff --git a/internal/configuration/reader_test.go b/internal/configuration/reader_test.go index c768cf815..cd08c7fc1 100644 --- a/internal/configuration/reader_test.go +++ b/internal/configuration/reader_test.go @@ -164,7 +164,7 @@ func TestShouldErrorParseBadConfigFile(t *testing.T) { require.Len(t, errors, 1) - require.EqualError(t, errors[0], "Error malformed yaml: line 24: did not find expected alphabetic or numeric character") + require.EqualError(t, errors[0], "Error malformed yaml: line 25: did not find expected alphabetic or numeric character") } func TestShouldParseConfigFile(t *testing.T) { @@ -185,7 +185,7 @@ func TestShouldParseConfigFile(t *testing.T) { require.Len(t, errors, 0) assert.Equal(t, 9091, config.Port) - assert.Equal(t, "debug", config.LogLevel) + assert.Equal(t, "debug", config.Logging.Level) 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) @@ -221,7 +221,7 @@ func TestShouldParseAltConfigFile(t *testing.T) { require.Len(t, errors, 0) assert.Equal(t, 9091, config.Port) - assert.Equal(t, "debug", config.LogLevel) + assert.Equal(t, "debug", config.Logging.Level) 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) @@ -253,7 +253,7 @@ func TestShouldNotParseConfigFileWithOldOrUnexpectedKeys(t *testing.T) { return errors[i].Error() < errors[j].Error() }) assert.EqualError(t, errors[0], "config key not expected: loggy_file") - assert.EqualError(t, errors[1], "invalid configuration key 'logs_level' was replaced by 'log_level'") + assert.EqualError(t, errors[1], "invalid configuration key 'logs_level' was replaced by 'logging.level'") } func TestShouldValidateConfigurationTemplate(t *testing.T) { diff --git a/internal/configuration/schema/configuration.go b/internal/configuration/schema/configuration.go index d5390e44e..e65c37ca7 100644 --- a/internal/configuration/schema/configuration.go +++ b/internal/configuration/schema/configuration.go @@ -8,13 +8,16 @@ type Configuration struct { TLSCert string `mapstructure:"tls_cert"` TLSKey string `mapstructure:"tls_key"` CertificatesDirectory string `mapstructure:"certificates_directory"` - LogLevel string `mapstructure:"log_level"` - LogFormat string `mapstructure:"log_format"` - LogFilePath string `mapstructure:"log_file_path"` - LogKeepStdout bool `mapstructure:"log_keep_stdout"` JWTSecret string `mapstructure:"jwt_secret"` DefaultRedirectionURL string `mapstructure:"default_redirection_url"` + // TODO: DEPRECATED START. Remove in 4.33.0. + LogLevel string `mapstructure:"log_level"` + LogFormat string `mapstructure:"log_format"` + LogFilePath string `mapstructure:"log_file_path"` + // TODO: DEPRECATED END. Remove in 4.33.0. + + Logging LoggingConfiguration `mapstructure:"logging"` IdentityProviders IdentityProvidersConfiguration `mapstructure:"identity_providers"` AuthenticationBackend AuthenticationBackendConfiguration `mapstructure:"authentication_backend"` Session SessionConfiguration `mapstructure:"session"` diff --git a/internal/configuration/schema/logging.go b/internal/configuration/schema/logging.go new file mode 100644 index 000000000..a6f6b0fb1 --- /dev/null +++ b/internal/configuration/schema/logging.go @@ -0,0 +1,15 @@ +package schema + +// LoggingConfiguration represents the logging configuration. +type LoggingConfiguration struct { + Level string `mapstructure:"level"` + Format string `mapstructure:"format"` + FilePath string `mapstructure:"file_path"` + KeepStdout bool `mapstructure:"keep_stdout"` +} + +// DefaultLoggingConfiguration is the default logging configuration. +var DefaultLoggingConfiguration = LoggingConfiguration{ + Level: "info", + Format: "text", +} diff --git a/internal/configuration/schema/server.go b/internal/configuration/schema/server.go index 8858d3834..2ede2251e 100644 --- a/internal/configuration/schema/server.go +++ b/internal/configuration/schema/server.go @@ -5,6 +5,8 @@ type ServerConfiguration struct { Path string `mapstructure:"path"` ReadBufferSize int `mapstructure:"read_buffer_size"` WriteBufferSize int `mapstructure:"write_buffer_size"` + EnablePprof bool `mapstructure:"enable_endpoint_pprof"` + EnableExpvars bool `mapstructure:"enable_endpoint_expvars"` } // DefaultServerConfiguration represents the default values of the ServerConfiguration. diff --git a/internal/configuration/test_resources/config.yml b/internal/configuration/test_resources/config.yml index 067dfbedc..647d88292 100644 --- a/internal/configuration/test_resources/config.yml +++ b/internal/configuration/test_resources/config.yml @@ -2,7 +2,8 @@ host: 127.0.0.1 port: 9091 -log_level: debug +logging: + level: debug default_redirection_url: https://home.example.com:8080/ totp: diff --git a/internal/configuration/test_resources/config_alt.yml b/internal/configuration/test_resources/config_alt.yml index a4c7319ac..3218b354d 100644 --- a/internal/configuration/test_resources/config_alt.yml +++ b/internal/configuration/test_resources/config_alt.yml @@ -2,7 +2,8 @@ host: 127.0.0.1 port: 9091 -log_level: debug +logging: + level: debug default_redirection_url: https://home.example.com:8080/ totp: diff --git a/internal/configuration/test_resources/config_bad_quoting.yml b/internal/configuration/test_resources/config_bad_quoting.yml index cdc2cc446..79adaccc0 100644 --- a/internal/configuration/test_resources/config_bad_quoting.yml +++ b/internal/configuration/test_resources/config_bad_quoting.yml @@ -1,7 +1,8 @@ --- host: 0.0.0.0 port: 9091 -log_level: debug +logging: + level: debug jwt_secret: RUtG9TnbXrOl1XLLmDgySw1DGgx9QcrtepIf1uDDBlBVKFZxkVBruYKBi32PvaU diff --git a/internal/configuration/test_resources/config_with_secret.yml b/internal/configuration/test_resources/config_with_secret.yml index c1681b7ac..8256a95f5 100644 --- a/internal/configuration/test_resources/config_with_secret.yml +++ b/internal/configuration/test_resources/config_with_secret.yml @@ -3,7 +3,8 @@ host: 127.0.0.1 port: 9091 jwt_secret: secret_from_config -log_level: debug +logging: + level: debug default_redirection_url: https://home.example.com:8080/ totp: diff --git a/internal/configuration/validator/access_control.go b/internal/configuration/validator/access_control.go index 880a57bfe..fc7680c80 100644 --- a/internal/configuration/validator/access_control.go +++ b/internal/configuration/validator/access_control.go @@ -50,7 +50,11 @@ func IsNetworkValid(network string) (isValid bool) { } // ValidateAccessControl validates access control configuration. -func ValidateAccessControl(configuration schema.AccessControlConfiguration, validator *schema.StructValidator) { +func ValidateAccessControl(configuration *schema.AccessControlConfiguration, validator *schema.StructValidator) { + if configuration.DefaultPolicy == "" { + configuration.DefaultPolicy = denyPolicy + } + if !IsPolicyValid(configuration.DefaultPolicy) { validator.Push(fmt.Errorf("'default_policy' must either be 'deny', 'two_factor', 'one_factor' or 'bypass'")) } diff --git a/internal/configuration/validator/access_control_test.go b/internal/configuration/validator/access_control_test.go index ed810edaf..2e37f45d0 100644 --- a/internal/configuration/validator/access_control_test.go +++ b/internal/configuration/validator/access_control_test.go @@ -24,7 +24,7 @@ func (suite *AccessControl) SetupTest() { } func (suite *AccessControl) TestShouldValidateCompleteConfiguration() { - ValidateAccessControl(suite.configuration, suite.validator) + ValidateAccessControl(&suite.configuration, suite.validator) suite.Assert().False(suite.validator.HasWarnings()) suite.Assert().False(suite.validator.HasErrors()) @@ -33,7 +33,7 @@ func (suite *AccessControl) TestShouldValidateCompleteConfiguration() { func (suite *AccessControl) TestShouldRaiseErrorInvalidDefaultPolicy() { suite.configuration.DefaultPolicy = testInvalidPolicy - ValidateAccessControl(suite.configuration, suite.validator) + ValidateAccessControl(&suite.configuration, suite.validator) suite.Assert().False(suite.validator.HasWarnings()) suite.Require().Len(suite.validator.Errors(), 1) @@ -49,7 +49,7 @@ func (suite *AccessControl) TestShouldRaiseErrorInvalidNetworkGroupNetwork() { }, } - ValidateAccessControl(suite.configuration, suite.validator) + ValidateAccessControl(&suite.configuration, suite.validator) suite.Assert().False(suite.validator.HasWarnings()) suite.Require().Len(suite.validator.Errors(), 1) diff --git a/internal/configuration/validator/configuration.go b/internal/configuration/validator/configuration.go index 0bd640d22..98e1194ee 100644 --- a/internal/configuration/validator/configuration.go +++ b/internal/configuration/validator/configuration.go @@ -9,7 +9,6 @@ import ( ) var defaultPort = 9091 -var defaultLogLevel = "info" // ValidateConfiguration and adapt the configuration read from file. //nolint:gocyclo // This function is likely to always have lots of if/else statements, as long as we keep the flow clean it should be understandable. @@ -37,10 +36,6 @@ func ValidateConfiguration(configuration *schema.Configuration, validator *schem } } - if configuration.LogLevel == "" { - configuration.LogLevel = defaultLogLevel - } - if configuration.JWTSecret == "" { validator.Push(fmt.Errorf("Provide a JWT secret using \"jwt_secret\" key")) } @@ -52,25 +47,19 @@ func ValidateConfiguration(configuration *schema.Configuration, validator *schem } } - if configuration.Theme == "" { - configuration.Theme = "light" - } - ValidateTheme(configuration, validator) if configuration.TOTP == nil { configuration.TOTP = &schema.DefaultTOTPConfiguration } + ValidateLogging(configuration, validator) + ValidateTOTP(configuration.TOTP, validator) ValidateAuthenticationBackend(&configuration.AuthenticationBackend, validator) - if configuration.AccessControl.DefaultPolicy == "" { - configuration.AccessControl.DefaultPolicy = denyPolicy - } - - ValidateAccessControl(configuration.AccessControl, validator) + ValidateAccessControl(&configuration.AccessControl, validator) ValidateRules(configuration.AccessControl, validator) diff --git a/internal/configuration/validator/configuration_test.go b/internal/configuration/validator/configuration_test.go index 751f859dd..5bee64b04 100644 --- a/internal/configuration/validator/configuration_test.go +++ b/internal/configuration/validator/configuration_test.go @@ -14,8 +14,8 @@ func newDefaultConfig() schema.Configuration { config := schema.Configuration{} config.Host = "127.0.0.1" config.Port = 9090 - config.LogLevel = "info" - config.LogFormat = "text" + config.Logging.Level = "info" + config.Logging.Format = "text" config.JWTSecret = testJWTSecret config.AuthenticationBackend.File = &schema.FileAuthenticationBackendConfiguration{ Path: "/a/path", @@ -48,7 +48,7 @@ func TestShouldNotUpdateConfig(t *testing.T) { require.Len(t, validator.Errors(), 0) assert.Equal(t, 9090, config.Port) - assert.Equal(t, "info", config.LogLevel) + assert.Equal(t, "info", config.Logging.Level) } func TestShouldValidateAndUpdatePort(t *testing.T) { @@ -73,17 +73,6 @@ func TestShouldValidateAndUpdateHost(t *testing.T) { assert.Equal(t, "0.0.0.0", config.Host) } -func TestShouldValidateAndUpdateLogsLevel(t *testing.T) { - validator := schema.NewStructValidator() - config := newDefaultConfig() - config.LogLevel = "" - - ValidateConfiguration(&config, validator) - - require.Len(t, validator.Errors(), 0) - assert.Equal(t, "info", config.LogLevel) -} - func TestShouldEnsureNotifierConfigIsProvided(t *testing.T) { validator := schema.NewStructValidator() config := newDefaultConfig() diff --git a/internal/configuration/validator/const.go b/internal/configuration/validator/const.go index fca945dd0..7085ef65a 100644 --- a/internal/configuration/validator/const.go +++ b/internal/configuration/validator/const.go @@ -1,11 +1,16 @@ package validator const ( + errFmtDeprecatedConfigurationKey = "[DEPRECATED] The %s configuration option is deprecated and will be " + + "removed in %s, please use %s instead" + errFmtReplacedConfigurationKey = "invalid configuration key '%s' was replaced by '%s'" + + errFmtLoggingLevelInvalid = "the log level '%s' is invalid, must be one of: %s" + errFmtSessionSecretRedisProvider = "The session secret must be set when using the %s session provider" errFmtSessionRedisPortRange = "The port must be between 1 and 65535 for the %s session provider" errFmtSessionRedisHostRequired = "The host must be provided when using the %s session provider" errFmtSessionRedisHostOrNodesRequired = "Either the host or a node must be provided when using the %s session provider" - errFmtReplacedConfigurationKey = "invalid configuration key '%s' was replaced by '%s'" errOAuthOIDCServerClientRedirectURIFmt = "OIDC Server Client redirect URI %s has an invalid scheme %s, should be http or https" errOAuthOIDCServerClientRedirectURICantBeParsedFmt = "OIDC Client with ID '%s' has an invalid redirect URI '%s' could not be parsed: %v" @@ -43,6 +48,7 @@ const ( "https://www.authelia.com/docs/configuration/access-control.html#combining-subjects-and-the-bypass-policy" ) +var validLoggingLevels = []string{"trace", "debug", "info", "warn", "error"} var validRequestMethods = []string{"GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "TRACE", "CONNECT", "OPTIONS"} // SecretNames contains a map of secret names. @@ -66,19 +72,30 @@ var validKeys = []string{ // Root Keys. "host", "port", - "log_level", - "log_format", - "log_file_path", "default_redirection_url", "theme", "tls_key", "tls_cert", "certificates_directory", + // Logging keys. + "logging.level", + "logging.format", + "logging.file_path", + "logging.keep_stdout", + + // TODO: DEPRECATED START. Remove in 4.33.0. + "log_level", + "log_format", + "log_file_path", + // TODO: DEPRECATED END. Remove in 4.33.0. + // Server Keys. "server.read_buffer_size", "server.write_buffer_size", "server.path", + "server.enable_pprof", + "server.enable_expvars", // TOTP Keys. "totp.issuer", @@ -200,8 +217,8 @@ var replacedKeys = map[string]string{ "authentication_backend.ldap.skip_verify": "authentication_backend.ldap.tls.skip_verify", "authentication_backend.ldap.minimum_tls_version": "authentication_backend.ldap.tls.minimum_version", "notifier.smtp.disable_verify_cert": "notifier.smtp.tls.skip_verify", - "logs_file_path": "log_file", - "logs_level": "log_level", + "logs_file_path": "logging.file_path", + "logs_level": "logging.level", } var specificErrorKeys = map[string]string{ diff --git a/internal/configuration/validator/keys_test.go b/internal/configuration/validator/keys_test.go index ba947422c..348a0399a 100644 --- a/internal/configuration/validator/keys_test.go +++ b/internal/configuration/validator/keys_test.go @@ -106,8 +106,8 @@ func TestReplacedErrors(t *testing.T) { assert.EqualError(t, errs[0], fmt.Sprintf(errFmtReplacedConfigurationKey, "authentication_backend.ldap.skip_verify", "authentication_backend.ldap.tls.skip_verify")) assert.EqualError(t, errs[1], fmt.Sprintf(errFmtReplacedConfigurationKey, "authentication_backend.ldap.minimum_tls_version", "authentication_backend.ldap.tls.minimum_version")) assert.EqualError(t, errs[2], fmt.Sprintf(errFmtReplacedConfigurationKey, "notifier.smtp.disable_verify_cert", "notifier.smtp.tls.skip_verify")) - assert.EqualError(t, errs[3], fmt.Sprintf(errFmtReplacedConfigurationKey, "logs_file_path", "log_file")) - assert.EqualError(t, errs[4], fmt.Sprintf(errFmtReplacedConfigurationKey, "logs_level", "log_level")) + assert.EqualError(t, errs[3], fmt.Sprintf(errFmtReplacedConfigurationKey, "logs_file_path", "logging.file_path")) + assert.EqualError(t, errs[4], fmt.Sprintf(errFmtReplacedConfigurationKey, "logs_level", "logging.level")) } func TestSecretKeysDontRaiseErrors(t *testing.T) { diff --git a/internal/configuration/validator/logging.go b/internal/configuration/validator/logging.go new file mode 100644 index 000000000..d41c6edcd --- /dev/null +++ b/internal/configuration/validator/logging.go @@ -0,0 +1,53 @@ +package validator + +import ( + "fmt" + "strings" + + "github.com/authelia/authelia/internal/configuration/schema" + "github.com/authelia/authelia/internal/utils" +) + +// ValidateLogging validates the logging configuration. +func ValidateLogging(configuration *schema.Configuration, validator *schema.StructValidator) { + applyDeprecatedLoggingConfiguration(configuration, validator) // TODO: DEPRECATED LINE. Remove in 4.33.0. + + if configuration.Logging.Level == "" { + configuration.Logging.Level = schema.DefaultLoggingConfiguration.Level + } + + if configuration.Logging.Format == "" { + configuration.Logging.Format = schema.DefaultLoggingConfiguration.Format + } + + if !utils.IsStringInSlice(configuration.Logging.Level, validLoggingLevels) { + validator.Push(fmt.Errorf(errFmtLoggingLevelInvalid, configuration.Logging.Level, strings.Join(validLoggingLevels, ", "))) + } +} + +// TODO: DEPRECATED FUNCTION. Remove in 4.33.0. +func applyDeprecatedLoggingConfiguration(configuration *schema.Configuration, validator *schema.StructValidator) { + if configuration.LogLevel != "" { + validator.PushWarning(fmt.Errorf(errFmtDeprecatedConfigurationKey, "log_level", "4.33.0", "logging.level")) + + if configuration.Logging.Level == "" { + configuration.Logging.Level = configuration.LogLevel + } + } + + if configuration.LogFormat != "" { + validator.PushWarning(fmt.Errorf(errFmtDeprecatedConfigurationKey, "log_format", "4.33.0", "logging.format")) + + if configuration.Logging.Format == "" { + configuration.Logging.Format = configuration.LogFormat + } + } + + if configuration.LogFilePath != "" { + validator.PushWarning(fmt.Errorf(errFmtDeprecatedConfigurationKey, "log_file_path", "4.33.0", "logging.file_path")) + + if configuration.Logging.FilePath == "" { + configuration.Logging.FilePath = configuration.LogFilePath + } + } +} diff --git a/internal/configuration/validator/logging_test.go b/internal/configuration/validator/logging_test.go new file mode 100644 index 000000000..75739b704 --- /dev/null +++ b/internal/configuration/validator/logging_test.go @@ -0,0 +1,111 @@ +package validator + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/authelia/authelia/internal/configuration/schema" +) + +func TestShouldSetDefaultLoggingValues(t *testing.T) { + config := &schema.Configuration{} + + validator := schema.NewStructValidator() + + ValidateLogging(config, validator) + + assert.Len(t, validator.Warnings(), 0) + assert.Len(t, validator.Errors(), 0) + + require.NotNil(t, config.Logging.KeepStdout) + + assert.Equal(t, "", config.LogLevel) + assert.Equal(t, "", config.LogFormat) + assert.Equal(t, "", config.LogFilePath) + + assert.Equal(t, "info", config.Logging.Level) + assert.Equal(t, "text", config.Logging.Format) + assert.Equal(t, "", config.Logging.FilePath) +} + +func TestShouldRaiseErrorOnInvalidLoggingLevel(t *testing.T) { + config := &schema.Configuration{ + Logging: schema.LoggingConfiguration{ + Level: "TRACE", + }, + } + + validator := schema.NewStructValidator() + + ValidateLogging(config, validator) + + assert.Len(t, validator.Warnings(), 0) + require.Len(t, validator.Errors(), 1) + + assert.EqualError(t, validator.Errors()[0], "the log level 'TRACE' is invalid, must be one of: trace, debug, info, warn, error") +} + +// TODO: DEPRECATED TEST. Remove in 4.33.0. +func TestShouldMigrateDeprecatedLoggingConfig(t *testing.T) { + config := &schema.Configuration{ + LogLevel: "trace", + LogFormat: "json", + LogFilePath: "/a/b/c", + } + + validator := schema.NewStructValidator() + + ValidateLogging(config, validator) + + assert.Len(t, validator.Errors(), 0) + require.Len(t, validator.Warnings(), 3) + + require.NotNil(t, config.Logging.KeepStdout) + + assert.Equal(t, "trace", config.LogLevel) + assert.Equal(t, "json", config.LogFormat) + assert.Equal(t, "/a/b/c", config.LogFilePath) + + assert.Equal(t, "trace", config.Logging.Level) + assert.Equal(t, "json", config.Logging.Format) + assert.Equal(t, "/a/b/c", config.Logging.FilePath) + + assert.EqualError(t, validator.Warnings()[0], fmt.Sprintf(errFmtDeprecatedConfigurationKey, "log_level", "4.33.0", "logging.level")) + assert.EqualError(t, validator.Warnings()[1], fmt.Sprintf(errFmtDeprecatedConfigurationKey, "log_format", "4.33.0", "logging.format")) + assert.EqualError(t, validator.Warnings()[2], fmt.Sprintf(errFmtDeprecatedConfigurationKey, "log_file_path", "4.33.0", "logging.file_path")) +} + +func TestShouldRaiseErrorsAndNotOverwriteConfigurationWhenUsingDeprecatedLoggingConfig(t *testing.T) { + config := &schema.Configuration{ + Logging: schema.LoggingConfiguration{ + Level: "info", + Format: "text", + FilePath: "/x/y/z", + KeepStdout: true, + }, + LogLevel: "debug", + LogFormat: "json", + LogFilePath: "/a/b/c", + } + + validator := schema.NewStructValidator() + + ValidateLogging(config, validator) + + require.NotNil(t, config.Logging.KeepStdout) + + assert.Equal(t, "info", config.Logging.Level) + assert.Equal(t, "text", config.Logging.Format) + assert.True(t, config.Logging.KeepStdout) + assert.Equal(t, "/x/y/z", config.Logging.FilePath) + + assert.Len(t, validator.Errors(), 0) + require.Len(t, validator.Warnings(), 3) + + assert.EqualError(t, validator.Warnings()[0], fmt.Sprintf(errFmtDeprecatedConfigurationKey, "log_level", "4.33.0", "logging.level")) + assert.EqualError(t, validator.Warnings()[1], fmt.Sprintf(errFmtDeprecatedConfigurationKey, "log_format", "4.33.0", "logging.format")) + assert.EqualError(t, validator.Warnings()[2], fmt.Sprintf(errFmtDeprecatedConfigurationKey, "log_file_path", "4.33.0", "logging.file_path")) +} diff --git a/internal/configuration/validator/theme.go b/internal/configuration/validator/theme.go index a3f12e014..d1b67929c 100644 --- a/internal/configuration/validator/theme.go +++ b/internal/configuration/validator/theme.go @@ -9,6 +9,10 @@ import ( // ValidateTheme validates and update Theme configuration. func ValidateTheme(configuration *schema.Configuration, validator *schema.StructValidator) { + if configuration.Theme == "" { + configuration.Theme = "light" + } + validThemes := regexp.MustCompile("light|dark|grey") if !validThemes.MatchString(configuration.Theme) { validator.Push(fmt.Errorf("Theme: %s is not valid, valid themes are: \"light\", \"dark\" or \"grey\"", configuration.Theme)) diff --git a/internal/handlers/handler_verify.go b/internal/handlers/handler_verify.go index 331eece1f..e5ea6ed87 100644 --- a/internal/handlers/handler_verify.go +++ b/internal/handlers/handler_verify.go @@ -339,7 +339,7 @@ func verifySessionHasUpToDateProfile(ctx *middlewares.AutheliaCtx, targetURL *ur } } else { ctx.Logger.Debugf("Updated profile detected for %s.", userSession.Username) - if ctx.Configuration.LogLevel == "trace" { + if ctx.Configuration.Logging.Level == "trace" { generateVerifySessionHasUpToDateProfileTraceLogs(ctx, userSession, details) } userSession.Emails = details.Emails diff --git a/internal/server/server.go b/internal/server/server.go index 445577066..479aa1e4b 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -127,9 +127,11 @@ func registerRoutes(configuration schema.Configuration, providers middlewares.Pr middlewares.RequireFirstFactor(handlers.SecondFactorDuoPost(duoAPI)))) } - // If trace is set, enable pprofhandler and expvarhandler. - if configuration.LogLevel == "trace" { + if configuration.Server.EnablePprof { r.GET("/debug/pprof/{name?}", pprofhandler.PprofHandler) + } + + if configuration.Server.EnableExpvars { r.GET("/debug/vars", expvarhandler.ExpvarHandler) } diff --git a/internal/suites/ActiveDirectory/configuration.yml b/internal/suites/ActiveDirectory/configuration.yml index 7835fd026..e002ebe84 100644 --- a/internal/suites/ActiveDirectory/configuration.yml +++ b/internal/suites/ActiveDirectory/configuration.yml @@ -9,7 +9,8 @@ tls_key: /config/ssl/key.pem theme: grey -log_level: debug +logging: + level: debug default_redirection_url: https://home.example.com:8080/ diff --git a/internal/suites/BypassAll/configuration.yml b/internal/suites/BypassAll/configuration.yml index 1b2341ebc..a57135336 100644 --- a/internal/suites/BypassAll/configuration.yml +++ b/internal/suites/BypassAll/configuration.yml @@ -7,7 +7,8 @@ port: 9091 tls_cert: /config/ssl/cert.pem tls_key: /config/ssl/key.pem -log_level: debug +logging: + level: debug jwt_secret: unsecure_secret diff --git a/internal/suites/CLI/configuration.yml b/internal/suites/CLI/configuration.yml index 1f529d1d5..07ee1db1d 100644 --- a/internal/suites/CLI/configuration.yml +++ b/internal/suites/CLI/configuration.yml @@ -7,7 +7,8 @@ port: 9091 tls_cert: /config/ssl/cert.pem tls_key: /config/ssl/key.pem -log_level: debug +logging: + level: debug jwt_secret: unsecure_secret diff --git a/internal/suites/Docker/configuration.yml b/internal/suites/Docker/configuration.yml index 302abf6ca..8d1eee1c4 100644 --- a/internal/suites/Docker/configuration.yml +++ b/internal/suites/Docker/configuration.yml @@ -7,7 +7,8 @@ port: 9091 tls_cert: /config/ssl/cert.pem tls_key: /config/ssl/key.pem -log_level: debug +logging: + 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 293c70697..bfa8d8d58 100644 --- a/internal/suites/DuoPush/configuration.yml +++ b/internal/suites/DuoPush/configuration.yml @@ -7,7 +7,8 @@ port: 9091 tls_cert: /config/ssl/cert.pem tls_key: /config/ssl/key.pem -log_level: trace +logging: + 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 def48b8a5..eef61d8e1 100644 --- a/internal/suites/HAProxy/configuration.yml +++ b/internal/suites/HAProxy/configuration.yml @@ -7,7 +7,8 @@ port: 9091 tls_cert: /config/ssl/cert.pem tls_key: /config/ssl/key.pem -log_level: debug +logging: + level: debug jwt_secret: unsecure_secret diff --git a/internal/suites/HighAvailability/configuration.yml b/internal/suites/HighAvailability/configuration.yml index 8da779478..7e15edff7 100644 --- a/internal/suites/HighAvailability/configuration.yml +++ b/internal/suites/HighAvailability/configuration.yml @@ -7,7 +7,8 @@ port: 9091 tls_cert: /config/ssl/cert.pem tls_key: /config/ssl/key.pem -log_level: debug +logging: + level: debug jwt_secret: unsecure_secret diff --git a/internal/suites/LDAP/configuration.yml b/internal/suites/LDAP/configuration.yml index 06eba5023..e9e3f6ce3 100644 --- a/internal/suites/LDAP/configuration.yml +++ b/internal/suites/LDAP/configuration.yml @@ -9,7 +9,8 @@ tls_key: /config/ssl/key.pem theme: dark -log_level: debug +logging: + 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 43b330d47..83366bb45 100644 --- a/internal/suites/Mariadb/configuration.yml +++ b/internal/suites/Mariadb/configuration.yml @@ -7,7 +7,8 @@ port: 9091 tls_cert: /config/ssl/cert.pem tls_key: /config/ssl/key.pem -log_level: debug +logging: + 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 8658fb622..13d134ec2 100644 --- a/internal/suites/MySQL/configuration.yml +++ b/internal/suites/MySQL/configuration.yml @@ -7,7 +7,8 @@ port: 9091 tls_cert: /config/ssl/cert.pem tls_key: /config/ssl/key.pem -log_level: debug +logging: + 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 21c728c41..8ff6e86f6 100644 --- a/internal/suites/NetworkACL/configuration.yml +++ b/internal/suites/NetworkACL/configuration.yml @@ -7,7 +7,8 @@ port: 9091 tls_cert: /config/ssl/cert.pem tls_key: /config/ssl/key.pem -log_level: debug +logging: + level: debug jwt_secret: unsecure_password diff --git a/internal/suites/OIDC/configuration.yml b/internal/suites/OIDC/configuration.yml index 44569ce3c..b8fb200e4 100644 --- a/internal/suites/OIDC/configuration.yml +++ b/internal/suites/OIDC/configuration.yml @@ -3,7 +3,8 @@ port: 9091 tls_cert: /config/ssl/cert.pem tls_key: /config/ssl/key.pem -log_level: debug +logging: + level: debug jwt_secret: unsecure_secret diff --git a/internal/suites/OIDCTraefik/configuration.yml b/internal/suites/OIDCTraefik/configuration.yml index 7ad402bd2..d486bed45 100644 --- a/internal/suites/OIDCTraefik/configuration.yml +++ b/internal/suites/OIDCTraefik/configuration.yml @@ -3,7 +3,8 @@ port: 9091 tls_cert: /config/ssl/cert.pem tls_key: /config/ssl/key.pem -log_level: debug +logging: + level: debug jwt_secret: unsecure_secret diff --git a/internal/suites/OneFactorOnly/configuration.yml b/internal/suites/OneFactorOnly/configuration.yml index 9fee88003..fc27b9934 100644 --- a/internal/suites/OneFactorOnly/configuration.yml +++ b/internal/suites/OneFactorOnly/configuration.yml @@ -7,7 +7,8 @@ port: 9091 tls_cert: /config/ssl/cert.pem tls_key: /config/ssl/key.pem -log_level: debug +logging: + level: debug default_redirection_url: https://home.example.com:8080/ diff --git a/internal/suites/PathPrefix/configuration.yml b/internal/suites/PathPrefix/configuration.yml index a306f86ef..6f86ae377 100644 --- a/internal/suites/PathPrefix/configuration.yml +++ b/internal/suites/PathPrefix/configuration.yml @@ -10,7 +10,8 @@ tls_key: /config/ssl/key.pem server: path: auth -log_level: debug +logging: + level: debug jwt_secret: unsecure_secret diff --git a/internal/suites/Postgres/configuration.yml b/internal/suites/Postgres/configuration.yml index b1bfad9d6..eea9fc1fd 100644 --- a/internal/suites/Postgres/configuration.yml +++ b/internal/suites/Postgres/configuration.yml @@ -7,7 +7,8 @@ port: 9091 tls_cert: /config/ssl/cert.pem tls_key: /config/ssl/key.pem -log_level: debug +logging: + 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 4e22ead06..62063fe79 100644 --- a/internal/suites/ShortTimeouts/configuration.yml +++ b/internal/suites/ShortTimeouts/configuration.yml @@ -7,7 +7,8 @@ port: 9091 tls_cert: /config/ssl/cert.pem tls_key: /config/ssl/key.pem -log_level: debug +logging: + level: debug jwt_secret: unsecure_secret diff --git a/internal/suites/Standalone/configuration.yml b/internal/suites/Standalone/configuration.yml index b92785f01..845b8b310 100644 --- a/internal/suites/Standalone/configuration.yml +++ b/internal/suites/Standalone/configuration.yml @@ -7,7 +7,8 @@ port: 9091 tls_cert: /config/ssl/cert.pem tls_key: /config/ssl/key.pem -log_level: debug +logging: + level: debug authentication_backend: file: diff --git a/internal/suites/Traefik/configuration.yml b/internal/suites/Traefik/configuration.yml index def48b8a5..eef61d8e1 100644 --- a/internal/suites/Traefik/configuration.yml +++ b/internal/suites/Traefik/configuration.yml @@ -7,7 +7,8 @@ port: 9091 tls_cert: /config/ssl/cert.pem tls_key: /config/ssl/key.pem -log_level: debug +logging: + level: debug jwt_secret: unsecure_secret diff --git a/internal/suites/Traefik2/configuration.yml b/internal/suites/Traefik2/configuration.yml index c72ff5d76..94bfd4e91 100644 --- a/internal/suites/Traefik2/configuration.yml +++ b/internal/suites/Traefik2/configuration.yml @@ -7,7 +7,8 @@ port: 9091 tls_cert: /config/ssl/cert.pem tls_key: /config/ssl/key.pem -log_level: debug +logging: + 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 3bb74691b..bf9fc50ee 100644 --- a/internal/suites/example/kube/authelia/configs/configuration.yml +++ b/internal/suites/example/kube/authelia/configs/configuration.yml @@ -7,7 +7,8 @@ port: 443 tls_cert: /config/ssl/cert.pem tls_key: /config/ssl/key.pem -log_level: debug +logging: + level: debug default_redirection_url: https://home.example.com:8080 diff --git a/internal/utils/strings.go b/internal/utils/strings.go index 56676f3b1..6f72e2905 100644 --- a/internal/utils/strings.go +++ b/internal/utils/strings.go @@ -19,9 +19,9 @@ func IsStringAlphaNumeric(input string) bool { } // IsStringInSlice checks if a single string is in a slice of strings. -func IsStringInSlice(a string, slice []string) (inSlice bool) { - for _, b := range slice { - if b == a { +func IsStringInSlice(needle string, haystack []string) (inSlice bool) { + for _, b := range haystack { + if b == needle { return true } } @@ -30,9 +30,9 @@ func IsStringInSlice(a string, slice []string) (inSlice bool) { } // IsStringInSliceFold checks if a single string is in a slice of strings but uses strings.EqualFold to compare them. -func IsStringInSliceFold(a string, slice []string) (inSlice bool) { - for _, b := range slice { - if strings.EqualFold(b, a) { +func IsStringInSliceFold(needle string, haystack []string) (inSlice bool) { + for _, b := range haystack { + if strings.EqualFold(b, needle) { return true } } @@ -41,9 +41,9 @@ func IsStringInSliceFold(a string, slice []string) (inSlice bool) { } // IsStringInSliceContains checks if a single string is in an array of strings. -func IsStringInSliceContains(a string, list []string) (inSlice bool) { - for _, b := range list { - if strings.Contains(a, b) { +func IsStringInSliceContains(needle string, haystack []string) (inSlice bool) { + for _, b := range haystack { + if strings.Contains(needle, b) { return true } }