open-vault/command/log_flags.go

179 lines
5.1 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package command
import (
"flag"
"os"
"strconv"
"github.com/hashicorp/vault/internalshared/configutil"
"github.com/posener/complete"
)
// logFlags are the 'log' related flags that can be shared across commands.
type logFlags struct {
flagCombineLogs bool
flagLogLevel string
flagLogFormat string
flagLogFile string
flagLogRotateBytes int
flagLogRotateDuration string
flagLogRotateMaxFiles int
}
// valuesProvider has the intention of providing a way to supply a func with a
// way to retrieve values for flags and environment variables without having to
// directly call a specific implementation.
// The reasoning for its existence is to facilitate testing.
type valuesProvider struct {
flagProvider func(string) (flag.Value, bool)
envVarProvider func(string) (string, bool)
}
// addLogFlags will add the set of 'log' related flags to a flag set.
func (f *FlagSet) addLogFlags(l *logFlags) {
f.BoolVar(&BoolVar{
Name: flagNameCombineLogs,
Target: &l.flagCombineLogs,
Default: false,
Hidden: true,
})
f.StringVar(&StringVar{
Name: flagNameLogLevel,
Target: &l.flagLogLevel,
Default: notSetValue,
EnvVar: EnvVaultLogLevel,
Completion: complete.PredictSet("trace", "debug", "info", "warn", "error"),
Usage: "Log verbosity level. Supported values (in order of detail) are " +
"\"trace\", \"debug\", \"info\", \"warn\", and \"error\".",
})
f.StringVar(&StringVar{
Name: flagNameLogFormat,
Target: &l.flagLogFormat,
Default: notSetValue,
EnvVar: EnvVaultLogFormat,
Completion: complete.PredictSet("standard", "json"),
Usage: `Log format. Supported values are "standard" and "json".`,
})
f.StringVar(&StringVar{
Name: flagNameLogFile,
Target: &l.flagLogFile,
Usage: "Path to the log file that Vault should use for logging",
})
f.IntVar(&IntVar{
Name: flagNameLogRotateBytes,
Target: &l.flagLogRotateBytes,
Usage: "Number of bytes that should be written to a log before it needs to be rotated. " +
"Unless specified, there is no limit to the number of bytes that can be written to a log file",
})
f.StringVar(&StringVar{
Name: flagNameLogRotateDuration,
Target: &l.flagLogRotateDuration,
Usage: "The maximum duration a log should be written to before it needs to be rotated. " +
"Must be a duration value such as 30s",
})
f.IntVar(&IntVar{
Name: flagNameLogRotateMaxFiles,
Target: &l.flagLogRotateMaxFiles,
Usage: "The maximum number of older log file archives to keep",
})
}
// envVarValue attempts to get a named value from the environment variables.
// The value will be returned as a string along with a boolean value indiciating
// to the caller whether the named env var existed.
func envVarValue(key string) (string, bool) {
if key == "" {
return "", false
}
return os.LookupEnv(key)
}
// flagValue attempts to find the named flag in a set of FlagSets.
// The flag.Value is returned if it was specified, and the boolean value indicates
// to the caller if the flag was specified by the end user.
func (f *FlagSets) flagValue(flagName string) (flag.Value, bool) {
var result flag.Value
var isFlagSpecified bool
if f != nil {
f.Visit(func(fl *flag.Flag) {
if fl.Name == flagName {
result = fl.Value
isFlagSpecified = true
}
})
}
return result, isFlagSpecified
}
// overrideValue uses the provided keys to check CLI flags and environment
// variables for values that may be used to override any specified configuration.
func (p *valuesProvider) overrideValue(flagKey, envVarKey string) (string, bool) {
var result string
found := true
flg, flgFound := p.flagProvider(flagKey)
env, envFound := p.envVarProvider(envVarKey)
switch {
case flgFound:
result = flg.String()
case envFound:
result = env
default:
found = false
}
return result, found
}
// applyLogConfigOverrides will accept a shared config and specifically attempt to update the 'log' related config keys.
// For each 'log' key, we aggregate file config, env vars and CLI flags to select the one with the highest precedence.
// This method mutates the config object passed into it.
func (f *FlagSets) applyLogConfigOverrides(config *configutil.SharedConfig) {
p := &valuesProvider{
flagProvider: f.flagValue,
envVarProvider: envVarValue,
}
// Update log level
if val, found := p.overrideValue(flagNameLogLevel, EnvVaultLogLevel); found {
config.LogLevel = val
}
// Update log format
if val, found := p.overrideValue(flagNameLogFormat, EnvVaultLogFormat); found {
config.LogFormat = val
}
// Update log file name
if val, found := p.overrideValue(flagNameLogFile, ""); found {
config.LogFile = val
}
// Update log rotation duration
if val, found := p.overrideValue(flagNameLogRotateDuration, ""); found {
config.LogRotateDuration = val
}
// Update log max files
if val, found := p.overrideValue(flagNameLogRotateMaxFiles, ""); found {
config.LogRotateMaxFiles, _ = strconv.Atoi(val)
}
// Update log rotation max bytes
if val, found := p.overrideValue(flagNameLogRotateBytes, ""); found {
config.LogRotateBytes, _ = strconv.Atoi(val)
}
}