diff --git a/README.md b/README.md index b25eb2618..8af30d276 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ See the [documentation](docs) to learn how to: 1. [Install or upgrade](docs/install-upgrade.md) the Operator. 1. [Deploy and configure](docs/deploy-configure.md) MongoDB resources. +1. [Configure Logging](docs/logging.md) of the MongoDB resource components. 1. [Create a database user](docs/users.md) with SCRAM authentication. 1. [Secure MongoDB resource connections](docs/secure.md) using TLS. diff --git a/controllers/construct/mongodbstatefulset.go b/controllers/construct/mongodbstatefulset.go index a798dc27a..4f556f231 100644 --- a/controllers/construct/mongodbstatefulset.go +++ b/controllers/construct/mongodbstatefulset.go @@ -2,6 +2,7 @@ package construct import ( "fmt" + "github.com/mongodb/mongodb-kubernetes-operator/pkg/readiness/config" "os" "strconv" "strings" @@ -262,10 +263,10 @@ func AutomationAgentCommand(withAgentAPIKeyExport bool, logLevel string, logFile // To keep consistent with old behavior not setting the logFile in the config does not log to stdout but keeps // the default logFile as defined by DefaultAgentLogFile. Setting the logFile explictly to "/dev/stdout" will log to stdout. agentLogOptions := "" - if logFile != "/dev/stdout" { - agentLogOptions += " -logFile " + logFile + " -logLevel " + logLevel + " -maxLogFileDurationHrs " + strconv.Itoa(maxLogFileDurationHours) - } else { + if logFile == "/dev/stdout" { agentLogOptions += " -logLevel " + logLevel + } else { + agentLogOptions += " -logFile " + logFile + " -logLevel " + logLevel + " -maxLogFileDurationHrs " + strconv.Itoa(maxLogFileDurationHours) } if withAgentAPIKeyExport { @@ -415,11 +416,37 @@ exec mongod -f %s; container.WithArgs([]string{""}), containerSecurityContext, container.WithEnvs( - corev1.EnvVar{ - Name: agentHealthStatusFilePathEnv, - Value: "/healthstatus/agent-health-status.json", - }, + collectEnvVars()..., ), container.WithVolumeMounts(volumeMounts), ) } + +// Function to collect and return the environment variables to be used in the +// MongoDB container. +func collectEnvVars() []corev1.EnvVar { + var envVars []corev1.EnvVar + + envVars = append(envVars, corev1.EnvVar{ + Name: agentHealthStatusFilePathEnv, + Value: "/healthstatus/agent-health-status.json", + }) + + addEnvVarIfSet := func(name string) { + value := os.Getenv(name) + if value != "" { + envVars = append(envVars, corev1.EnvVar{ + Name: name, + Value: value, + }) + } + } + + addEnvVarIfSet(config.ReadinessProbeLoggerBackups) + addEnvVarIfSet(config.ReadinessProbeLoggerMaxSize) + addEnvVarIfSet(config.ReadinessProbeLoggerMaxAge) + addEnvVarIfSet(config.ReadinessProbeLoggerCompress) + addEnvVarIfSet(config.WithAgentFileLogging) + + return envVars +} diff --git a/controllers/construct/mongodbstatefulset_test.go b/controllers/construct/mongodbstatefulset_test.go new file mode 100644 index 000000000..67d78174b --- /dev/null +++ b/controllers/construct/mongodbstatefulset_test.go @@ -0,0 +1,97 @@ +package construct + +import ( + "github.com/mongodb/mongodb-kubernetes-operator/pkg/readiness/config" + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + "testing" +) + +func TestCollectEnvVars(t *testing.T) { + tests := []struct { + name string + envSetup map[string]string + expectedEnv []corev1.EnvVar + }{ + { + name: "Basic env vars set", + envSetup: map[string]string{ + config.ReadinessProbeLoggerBackups: "3", + config.ReadinessProbeLoggerMaxSize: "10M", + config.ReadinessProbeLoggerMaxAge: "7", + config.WithAgentFileLogging: "enabled", + }, + expectedEnv: []corev1.EnvVar{ + { + Name: config.AgentHealthStatusFilePathEnv, + Value: "/healthstatus/agent-health-status.json", + }, + { + Name: config.ReadinessProbeLoggerBackups, + Value: "3", + }, + { + Name: config.ReadinessProbeLoggerMaxSize, + Value: "10M", + }, + { + Name: config.ReadinessProbeLoggerMaxAge, + Value: "7", + }, + { + Name: config.WithAgentFileLogging, + Value: "enabled", + }, + }, + }, + { + name: "Additional env var set", + envSetup: map[string]string{ + config.ReadinessProbeLoggerBackups: "3", + config.ReadinessProbeLoggerMaxSize: "10M", + config.ReadinessProbeLoggerMaxAge: "7", + config.ReadinessProbeLoggerCompress: "true", + config.WithAgentFileLogging: "enabled", + }, + expectedEnv: []corev1.EnvVar{ + { + Name: config.AgentHealthStatusFilePathEnv, + Value: "/healthstatus/agent-health-status.json", + }, + { + Name: config.ReadinessProbeLoggerBackups, + Value: "3", + }, + { + Name: config.ReadinessProbeLoggerMaxSize, + Value: "10M", + }, + { + Name: config.ReadinessProbeLoggerMaxAge, + Value: "7", + }, + { + Name: config.ReadinessProbeLoggerCompress, + Value: "true", + }, + { + Name: config.WithAgentFileLogging, + Value: "enabled", + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Setup environment variables + for key, value := range tt.envSetup { + t.Setenv(key, value) + } + + actualEnvVars := collectEnvVars() + + assert.EqualValues(t, tt.expectedEnv, actualEnvVars) + }) + } +} diff --git a/docs/README.md b/docs/README.md index 2d49ef706..7475a0d10 100644 --- a/docs/README.md +++ b/docs/README.md @@ -6,5 +6,6 @@ - [MongoDB Community Kubernetes Operator Architecture](architecture.md) - [Install and Upgrade the Community Kubernetes Operator](install-upgrade.md) - [Deploy and Configure MongoDBCommunity Resources](deploy-configure.md) +- [Configure Logging of the MongoDB components](logging.md) - [Create Database Users](users.md) - [Secure MongoDBCommunity Resources](secure.md) diff --git a/docs/contributing.md b/docs/contributing.md index f4bd4d85e..d1414eb86 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -140,7 +140,7 @@ kubectl get pods #### (Optional) Create a MongoDBCommunity Resource -Follow the steps outlined [here](./deploy-configure.md) to deploy some resource. +Follow the steps outlined [here](./deploy-configure.md) to deploy some resources. #### Cleanup To remove the operator and any created resources you can run diff --git a/docs/logging.md b/docs/logging.md new file mode 100644 index 000000000..021ae48ed --- /dev/null +++ b/docs/logging.md @@ -0,0 +1,33 @@ +# Configure Logging in MongoDB Community + +This section describes the components which are logging either to a file or stdout, +how to configure them and what their defaults are. + +## MongoDB Processes +### Configuration +The exposed CRD options can be seen [in the crd yaml](https://github.com/mongodb/mongodb-kubernetes-operator/blob/74d13f189566574b862e5670b366b61ec5b65923/config/crd/bases/mongodbcommunity.mongodb.com_mongodbcommunity.yaml#L105-L117). +Additionally, more information regarding configuring systemLog can be found [in the official documentation of systemLog](https://www.mongodb.com/docs/manual/reference/configuration-options/#core-options)]. +`spec.agent.systemLog.destination` configures the logging destination of the mongod process. +### Default Values +By default, MongoDB sends all log output to standard output. + +## MongoDB Agent +### Configuration +`spec.agent.logFile` can be used to configure the output file of the mongoDB agent logging. +The agent will log to standard output with the following setting: `/dev/stdout`. +### Default Values +By default, the MongoDB agent logs to `/var/log/mongodb-mms-automation/automation-agent.log` + +## ReadinessProbe +### Configuration & Default Values +The readinessProbe can be configured via Environment variables. +Below is a table with each environment variable, its explanation and its default value. + +| Environment Variable | Explanation | Default Value | +|---------------------------------|-------------------------------------------------------------------------|-----------------------------------------------| +| READINESS_PROBE_LOGGER_BACKUPS | maximum number of old log files to retain | 5 | +| READINESS_PROBE_LOGGER_MAX_SIZE | maximum size in megabytes | 5 | +| READINESS_PROBE_LOGGER_MAX_AGE | maximum number of days to retain old log files | none | +| READINESS_PROBE_LOGGER_COMPRESS | if the rotated log files should be compressed | false | +| MDB_WITH_AGENT_FILE_LOGGING | whether we should also log to stdout (which shows in kubectl describe) | true | +| LOG_FILE_PATH | path of the logfile of the readinessProbe. | /var/log/mongodb-mms-automation/readiness.log | \ No newline at end of file diff --git a/pkg/readiness/config/config.go b/pkg/readiness/config/config.go index aa0357c33..09b8ca50e 100644 --- a/pkg/readiness/config/config.go +++ b/pkg/readiness/config/config.go @@ -22,10 +22,10 @@ const ( automationConfigSecretEnv = "AUTOMATION_CONFIG_MAP" //nolint logPathEnv = "LOG_FILE_PATH" hostNameEnv = "HOSTNAME" - readinessProbeLoggerBackups = "READINESS_PROBE_LOGGER_BACKUPS" - readinessProbeLoggerMaxSize = "READINESS_PROBE_LOGGER_MAX_SIZE" - readinessProbeLoggerMaxAge = "READINESS_PROBE_LOGGER_MAX_AGE" - readinessProbeLoggerCompress = "READINESS_PROBE_LOGGER_COMPRESS" + ReadinessProbeLoggerBackups = "READINESS_PROBE_LOGGER_BACKUPS" + ReadinessProbeLoggerMaxSize = "READINESS_PROBE_LOGGER_MAX_SIZE" + ReadinessProbeLoggerMaxAge = "READINESS_PROBE_LOGGER_MAX_AGE" + ReadinessProbeLoggerCompress = "READINESS_PROBE_LOGGER_COMPRESS" ) type Config struct { @@ -72,10 +72,10 @@ func BuildFromEnvVariables(clientSet kubernetes.Interface, isHeadless bool, file func GetLogger() *lumberjack.Logger { logger := &lumberjack.Logger{ Filename: readinessProbeLogFilePath(), - MaxBackups: readIntOrDefault(readinessProbeLoggerBackups, 5), - MaxSize: readIntOrDefault(readinessProbeLoggerMaxSize, 5), - MaxAge: readInt(readinessProbeLoggerMaxAge), - Compress: ReadBoolWitDefault(readinessProbeLoggerCompress, "false"), + MaxBackups: readIntOrDefault(ReadinessProbeLoggerBackups, 5), + MaxSize: readIntOrDefault(ReadinessProbeLoggerMaxSize, 5), + MaxAge: readInt(ReadinessProbeLoggerMaxAge), + Compress: ReadBoolWitDefault(ReadinessProbeLoggerCompress, "false"), } return logger }