diff --git a/changelog/24297.txt b/changelog/24297.txt new file mode 100644 index 000000000..d1433cfcd --- /dev/null +++ b/changelog/24297.txt @@ -0,0 +1,2 @@ +```release-note:change +logging: Vault server, Agent and Proxy now honor log file value and only add a timestamp on rotation. \ No newline at end of file diff --git a/command/agent.go b/command/agent.go index 612441519..4e140d9a9 100644 --- a/command/agent.go +++ b/command/agent.go @@ -20,7 +20,7 @@ import ( systemd "github.com/coreos/go-systemd/daemon" ctconfig "github.com/hashicorp/consul-template/config" - hclog "github.com/hashicorp/go-hclog" + "github.com/hashicorp/go-hclog" "github.com/hashicorp/go-multierror" "github.com/hashicorp/go-secure-stdlib/gatedwriter" "github.com/hashicorp/go-secure-stdlib/parseutil" @@ -39,7 +39,7 @@ import ( "github.com/hashicorp/vault/command/agent/template" "github.com/hashicorp/vault/command/agentproxyshared" "github.com/hashicorp/vault/command/agentproxyshared/auth" - cache "github.com/hashicorp/vault/command/agentproxyshared/cache" + "github.com/hashicorp/vault/command/agentproxyshared/cache" "github.com/hashicorp/vault/command/agentproxyshared/sink" "github.com/hashicorp/vault/command/agentproxyshared/sink/file" "github.com/hashicorp/vault/command/agentproxyshared/sink/inmem" @@ -63,6 +63,7 @@ const ( // flagNameAgentExitAfterAuth is used as an Agent specific flag to indicate // that agent should exit after a single successful auth flagNameAgentExitAfterAuth = "exit-after-auth" + nameAgent = "agent" ) type AgentCommand struct { @@ -1123,15 +1124,17 @@ func (c *AgentCommand) newLogger() (hclog.InterceptLogger, error) { return nil, errs } - logCfg := &logging.LogConfig{ - Name: "agent", - LogLevel: logLevel, - LogFormat: logFormat, - LogFilePath: c.config.LogFile, - LogRotateDuration: logRotateDuration, - LogRotateBytes: c.config.LogRotateBytes, - LogRotateMaxFiles: c.config.LogRotateMaxFiles, + logCfg, err := logging.NewLogConfig(nameAgent) + if err != nil { + return nil, err } + logCfg.Name = nameAgent + logCfg.LogLevel = logLevel + logCfg.LogFormat = logFormat + logCfg.LogFilePath = c.config.LogFile + logCfg.LogRotateDuration = logRotateDuration + logCfg.LogRotateBytes = c.config.LogRotateBytes + logCfg.LogRotateMaxFiles = c.config.LogRotateMaxFiles l, err := logging.Setup(logCfg, c.logWriter) if err != nil { diff --git a/command/proxy.go b/command/proxy.go index 0eee175af..c6f707cd6 100644 --- a/command/proxy.go +++ b/command/proxy.go @@ -27,7 +27,7 @@ import ( "github.com/hashicorp/vault/api" "github.com/hashicorp/vault/command/agentproxyshared" "github.com/hashicorp/vault/command/agentproxyshared/auth" - cache "github.com/hashicorp/vault/command/agentproxyshared/cache" + "github.com/hashicorp/vault/command/agentproxyshared/cache" "github.com/hashicorp/vault/command/agentproxyshared/sink" "github.com/hashicorp/vault/command/agentproxyshared/sink/file" "github.com/hashicorp/vault/command/agentproxyshared/sink/inmem" @@ -59,6 +59,7 @@ const ( // flagNameProxyExitAfterAuth is used as a Proxy specific flag to indicate // that proxy should exit after a single successful auth flagNameProxyExitAfterAuth = "exit-after-auth" + nameProxy = "proxy" ) type ProxyCommand struct { @@ -983,15 +984,17 @@ func (c *ProxyCommand) newLogger() (log.InterceptLogger, error) { return nil, errors } - logCfg := &logging.LogConfig{ - Name: "proxy", - LogLevel: logLevel, - LogFormat: logFormat, - LogFilePath: c.config.LogFile, - LogRotateDuration: logRotateDuration, - LogRotateBytes: c.config.LogRotateBytes, - LogRotateMaxFiles: c.config.LogRotateMaxFiles, + logCfg, err := logging.NewLogConfig(nameProxy) + if err != nil { + return nil, err } + logCfg.Name = nameProxy + logCfg.LogLevel = logLevel + logCfg.LogFormat = logFormat + logCfg.LogFilePath = c.config.LogFile + logCfg.LogRotateDuration = logRotateDuration + logCfg.LogRotateBytes = c.config.LogRotateBytes + logCfg.LogRotateMaxFiles = c.config.LogRotateMaxFiles l, err := logging.Setup(logCfg, c.logWriter) if err != nil { diff --git a/command/server.go b/command/server.go index 279e5c681..9a221567d 100644 --- a/command/server.go +++ b/command/server.go @@ -1815,14 +1815,16 @@ func (c *ServerCommand) configureLogging(config *server.Config) (hclog.Intercept return nil, err } - logCfg := &loghelper.LogConfig{ - LogLevel: logLevel, - LogFormat: logFormat, - LogFilePath: config.LogFile, - LogRotateDuration: logRotateDuration, - LogRotateBytes: config.LogRotateBytes, - LogRotateMaxFiles: config.LogRotateMaxFiles, + logCfg, err := loghelper.NewLogConfig("vault") + if err != nil { + return nil, err } + logCfg.LogLevel = logLevel + logCfg.LogFormat = logFormat + logCfg.LogFilePath = config.LogFile + logCfg.LogRotateDuration = logRotateDuration + logCfg.LogRotateBytes = config.LogRotateBytes + logCfg.LogRotateMaxFiles = config.LogRotateMaxFiles return loghelper.Setup(logCfg, c.logWriter) } diff --git a/helper/logging/logfile.go b/helper/logging/logfile.go index 9417e9ca8..2ea9764b9 100644 --- a/helper/logging/logfile.go +++ b/helper/logging/logfile.go @@ -57,7 +57,8 @@ func (l *LogFile) Write(b []byte) (n int, err error) { if err := l.openNew(); err != nil { return 0, err } - } else if err := l.rotate(); err != nil { // Check for the last contact and rotate if necessary + } + if err := l.rotate(); err != nil { // Check for the last contact and rotate if necessary return 0, err } @@ -82,21 +83,20 @@ func (l *LogFile) fileNamePattern() string { } func (l *LogFile) openNew() error { - fileNamePattern := l.fileNamePattern() - - createTime := now() - newFileName := fmt.Sprintf(fileNamePattern, strconv.FormatInt(createTime.UnixNano(), 10)) + newFileName := l.fileName newFilePath := filepath.Join(l.logPath, newFileName) - // Try creating a file. We truncate the file because we are the only authority to write the logs - filePointer, err := os.OpenFile(newFilePath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o640) + // Try creating or opening the active log file. Since the active log file + // always has the same name, append log entries to prevent overwriting + // previous log data. + filePointer, err := os.OpenFile(newFilePath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o640) if err != nil { return err } - // New file, new 'bytes' tracker, new creation time :) :) + // New file, new bytes tracker, new creation time :) l.fileInfo = filePointer - l.lastCreated = createTime + l.lastCreated = now() l.bytesWritten = 0 return nil } @@ -109,6 +109,9 @@ func (l *LogFile) rotate() error { if err := l.fileInfo.Close(); err != nil { return err } + if err := l.renameCurrentFile(); err != nil { + return err + } if err := l.pruneFiles(); err != nil { return err } @@ -148,3 +151,13 @@ func removeFiles(files []string) (err error) { } return err } + +func (l *LogFile) renameCurrentFile() error { + fileNamePattern := l.fileNamePattern() + createTime := now() + currentFilePath := filepath.Join(l.logPath, l.fileName) + oldFileName := fmt.Sprintf(fileNamePattern, strconv.FormatInt(createTime.UnixNano(), 10)) + oldFilePath := filepath.Join(l.logPath, oldFileName) + + return os.Rename(currentFilePath, oldFilePath) +} diff --git a/helper/logging/logger.go b/helper/logging/logger.go index 1efac27be..8768ab552 100644 --- a/helper/logging/logger.go +++ b/helper/logging/logger.go @@ -11,7 +11,7 @@ import ( "strings" "time" - log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/go-hclog" "github.com/hashicorp/go-multierror" ) @@ -32,7 +32,7 @@ type LogConfig struct { Name string // LogLevel is the minimum level to be logged. - LogLevel log.Level + LogLevel hclog.Level // LogFormat is the log format to use, supported formats are 'standard' and 'json'. LogFormat LogFormat @@ -48,10 +48,27 @@ type LogConfig struct { // LogRotateMaxFiles is the maximum number of past archived log files to keep LogRotateMaxFiles int + + // DefaultFileName should be set to the value to be used if the LogFilePath + // ends in a path separator such as '/var/log/' + // Examples of the default name are as follows: 'vault', 'agent' or 'proxy. + // The creator of this struct *must* ensure that it is assigned before doing + // anything with LogConfig! + DefaultFileName string +} + +// NewLogConfig should be used to initialize the LogConfig struct. +func NewLogConfig(defaultFileName string) (*LogConfig, error) { + defaultFileName = strings.TrimSpace(defaultFileName) + if defaultFileName == "" { + return nil, errors.New("default file name is required") + } + + return &LogConfig{DefaultFileName: defaultFileName}, nil } func (c *LogConfig) isLevelInvalid() bool { - return c.LogLevel == log.NoLevel || c.LogLevel == log.Off || c.LogLevel.String() == "unknown" + return c.LogLevel == hclog.NoLevel || c.LogLevel == hclog.Off || c.LogLevel.String() == "unknown" } func (c *LogConfig) isFormatJson() bool { @@ -104,7 +121,7 @@ func parseFullPath(fullPath string) (directory, fileName string, err error) { } // Setup creates a new logger with the specified configuration and writer -func Setup(config *LogConfig, w io.Writer) (log.InterceptLogger, error) { +func Setup(config *LogConfig, w io.Writer) (hclog.InterceptLogger, error) { // Validate the log level if config.isLevelInvalid() { return nil, fmt.Errorf("invalid log level: %v", config.LogLevel) @@ -121,7 +138,9 @@ func Setup(config *LogConfig, w io.Writer) (log.InterceptLogger, error) { if err != nil { return nil, err } - + if fileName == "" { + fileName = fmt.Sprintf("%s.log", config.DefaultFileName) + } if config.LogRotateDuration == 0 { config.LogRotateDuration = defaultRotateDuration } @@ -142,7 +161,7 @@ func Setup(config *LogConfig, w io.Writer) (log.InterceptLogger, error) { writers = append(writers, logFile) } - logger := log.NewInterceptLogger(&log.LoggerOptions{ + logger := hclog.NewInterceptLogger(&hclog.LoggerOptions{ Name: config.Name, Level: config.LogLevel, IndependentLevels: true, @@ -169,21 +188,21 @@ func ParseLogFormat(format string) (LogFormat, error) { // ParseLogLevel returns the hclog.Level that corresponds with the provided level string. // This differs hclog.LevelFromString in that it supports additional level strings. -func ParseLogLevel(logLevel string) (log.Level, error) { - var result log.Level +func ParseLogLevel(logLevel string) (hclog.Level, error) { + var result hclog.Level logLevel = strings.ToLower(strings.TrimSpace(logLevel)) switch logLevel { case "trace": - result = log.Trace + result = hclog.Trace case "debug": - result = log.Debug + result = hclog.Debug case "notice", "info", "": - result = log.Info + result = hclog.Info case "warn", "warning": - result = log.Warn + result = hclog.Warn case "err", "error": - result = log.Error + result = hclog.Error default: return -1, errors.New(fmt.Sprintf("unknown log level: %s", logLevel)) } @@ -192,11 +211,11 @@ func ParseLogLevel(logLevel string) (log.Level, error) { } // TranslateLoggerLevel returns the string that corresponds with logging level of the hclog.Logger. -func TranslateLoggerLevel(logger log.Logger) (string, error) { +func TranslateLoggerLevel(logger hclog.Logger) (string, error) { logLevel := logger.GetLevel() switch logLevel { - case log.Trace, log.Debug, log.Info, log.Warn, log.Error: + case hclog.Trace, hclog.Debug, hclog.Info, hclog.Warn, hclog.Error: return logLevel.String(), nil default: return "", fmt.Errorf("unknown log level") diff --git a/helper/logging/logger_test.go b/helper/logging/logger_test.go index 30ff1783a..323c761e0 100644 --- a/helper/logging/logger_test.go +++ b/helper/logging/logger_test.go @@ -8,15 +8,17 @@ import ( "encoding/json" "errors" "os" + "path/filepath" "testing" - log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/go-hclog" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestLogger_SetupBasic(t *testing.T) { - cfg := &LogConfig{Name: "test-system", LogLevel: log.Info} + cfg := newTestLogConfig(t) + cfg.LogLevel = hclog.Info logger, err := Setup(cfg, nil) require.NoError(t, err) @@ -26,16 +28,15 @@ func TestLogger_SetupBasic(t *testing.T) { } func TestLogger_SetupInvalidLogLevel(t *testing.T) { - cfg := &LogConfig{} + cfg := newTestLogConfig(t) _, err := Setup(cfg, nil) assert.Containsf(t, err.Error(), "invalid log level", "expected error %s", err) } func TestLogger_SetupLoggerErrorLevel(t *testing.T) { - cfg := &LogConfig{ - LogLevel: log.Error, - } + cfg := newTestLogConfig(t) + cfg.LogLevel = hclog.Error var buf bytes.Buffer @@ -48,15 +49,16 @@ func TestLogger_SetupLoggerErrorLevel(t *testing.T) { output := buf.String() - require.Contains(t, output, "[ERROR] test error msg") - require.NotContains(t, output, "[INFO] test info msg") + require.Contains(t, output, "[ERROR] test-system: test error msg") + require.NotContains(t, output, "[INFO] test-system: test info msg") } func TestLogger_SetupLoggerDebugLevel(t *testing.T) { - cfg := LogConfig{LogLevel: log.Debug} + cfg := newTestLogConfig(t) + cfg.LogLevel = hclog.Debug var buf bytes.Buffer - logger, err := Setup(&cfg, &buf) + logger, err := Setup(cfg, &buf) require.NoError(t, err) require.NotNil(t, logger) @@ -65,15 +67,14 @@ func TestLogger_SetupLoggerDebugLevel(t *testing.T) { output := buf.String() - require.Contains(t, output, "[INFO] test info msg") - require.Contains(t, output, "[DEBUG] test debug msg") + require.Contains(t, output, "[INFO] test-system: test info msg") + require.Contains(t, output, "[DEBUG] test-system: test debug msg") } -func TestLogger_SetupLoggerWithName(t *testing.T) { - cfg := &LogConfig{ - LogLevel: log.Debug, - Name: "test-system", - } +func TestLogger_SetupLoggerWithoutName(t *testing.T) { + cfg := newTestLogConfig(t) + cfg.Name = "" + cfg.LogLevel = hclog.Info var buf bytes.Buffer logger, err := Setup(cfg, &buf) @@ -82,15 +83,13 @@ func TestLogger_SetupLoggerWithName(t *testing.T) { logger.Warn("test warn msg") - require.Contains(t, buf.String(), "[WARN] test-system: test warn msg") + require.Contains(t, buf.String(), "[WARN] test warn msg") } func TestLogger_SetupLoggerWithJSON(t *testing.T) { - cfg := &LogConfig{ - LogLevel: log.Debug, - LogFormat: JSONFormat, - Name: "test-system", - } + cfg := newTestLogConfig(t) + cfg.LogLevel = hclog.Debug + cfg.LogFormat = JSONFormat var buf bytes.Buffer logger, err := Setup(cfg, &buf) @@ -108,13 +107,68 @@ func TestLogger_SetupLoggerWithJSON(t *testing.T) { require.Equal(t, jsonOutput["@message"], "test warn msg") } +func TestLogger_SetupLoggerWithValidLogPathMissingFileName(t *testing.T) { + tmpDir := t.TempDir() + cfg := newTestLogConfig(t) + cfg.LogLevel = hclog.Info + cfg.LogFilePath = tmpDir + "/" // add the trailing slash to the temp dir + var buf bytes.Buffer + + logger, err := Setup(cfg, &buf) + require.NoError(t, err) + require.NotNil(t, logger) + + logger.Info("juan?") + + m, err := filepath.Glob(cfg.LogFilePath + "*") + require.NoError(t, err) + require.Truef(t, len(m) == 1, "no files were found") +} + +func TestLogger_SetupLoggerWithValidLogPathFileName(t *testing.T) { + tmpDir := t.TempDir() + cfg := newTestLogConfig(t) + cfg.LogLevel = hclog.Info + cfg.LogFilePath = filepath.Join(tmpDir, "juan.log") + var buf bytes.Buffer + + logger, err := Setup(cfg, &buf) + require.NoError(t, err) + require.NotNil(t, logger) + + logger.Info("juan?") + f, err := os.Stat(cfg.LogFilePath) + require.NoError(t, err) + require.NotNil(t, f) +} + +func TestLogger_SetupLoggerWithValidLogPathFileNameRotate(t *testing.T) { + tmpDir := t.TempDir() + cfg := newTestLogConfig(t) + cfg.LogLevel = hclog.Info + cfg.LogFilePath = filepath.Join(tmpDir, "juan.log") + cfg.LogRotateBytes = 1 // set a tiny number of bytes to force rotation + var buf bytes.Buffer + + logger, err := Setup(cfg, &buf) + require.NoError(t, err) + require.NotNil(t, logger) + + logger.Info("juan?") + logger.Info("john?") + f, err := os.Stat(cfg.LogFilePath) + require.NoError(t, err) + require.NotNil(t, f) + m, err := filepath.Glob(tmpDir + "/juan-*") // look for juan-{timestamp}.log + require.NoError(t, err) + require.Truef(t, len(m) == 1, "no files were found") +} + func TestLogger_SetupLoggerWithValidLogPath(t *testing.T) { tmpDir := t.TempDir() - - cfg := &LogConfig{ - LogLevel: log.Info, - LogFilePath: tmpDir, //+ "/", - } + cfg := newTestLogConfig(t) + cfg.LogLevel = hclog.Info + cfg.LogFilePath = tmpDir + "/" // add the trailing slash to the temp dir var buf bytes.Buffer logger, err := Setup(cfg, &buf) @@ -123,10 +177,10 @@ func TestLogger_SetupLoggerWithValidLogPath(t *testing.T) { } func TestLogger_SetupLoggerWithInValidLogPath(t *testing.T) { - cfg := &LogConfig{ - LogLevel: log.Info, - LogFilePath: "nonexistentdir/", - } + cfg := newTestLogConfig(t) + cfg.LogLevel = hclog.Info + cfg.LogLevel = hclog.Info + cfg.LogFilePath = "nonexistentdir/" var buf bytes.Buffer logger, err := Setup(cfg, &buf) @@ -142,10 +196,9 @@ func TestLogger_SetupLoggerWithInValidLogPathPermission(t *testing.T) { assert.NoError(t, err, "unexpected error testing with invalid log path permission") defer os.RemoveAll(tmpDir) - cfg := &LogConfig{ - LogLevel: log.Info, - LogFilePath: tmpDir + "/", - } + cfg := newTestLogConfig(t) + cfg.LogLevel = hclog.Info + cfg.LogFilePath = tmpDir + "/" var buf bytes.Buffer logger, err := Setup(cfg, &buf) @@ -188,10 +241,10 @@ func TestLogger_SetupLoggerWithInvalidLogFilePath(t *testing.T) { for name, tc := range cases { name := name tc := tc - cfg := &LogConfig{ - LogLevel: log.Info, - LogFilePath: tc.path, - } + cfg := newTestLogConfig(t) + cfg.LogLevel = hclog.Info + cfg.LogFilePath = tc.path + _, err := Setup(cfg, &bytes.Buffer{}) assert.Error(t, err, "%s: expected error due to *", name) assert.Contains(t, err.Error(), tc.message, "%s: error message does not match: %s", name, err.Error()) @@ -199,26 +252,34 @@ func TestLogger_SetupLoggerWithInvalidLogFilePath(t *testing.T) { } func TestLogger_ChangeLogLevels(t *testing.T) { - cfg := &LogConfig{ - LogLevel: log.Debug, - Name: "test-system", - } + cfg := newTestLogConfig(t) + cfg.LogLevel = hclog.Debug var buf bytes.Buffer logger, err := Setup(cfg, &buf) require.NoError(t, err) require.NotNil(t, logger) - assert.Equal(t, log.Debug, logger.GetLevel()) + assert.Equal(t, hclog.Debug, logger.GetLevel()) // Create new named loggers from the base logger and change the levels logger2 := logger.Named("test2") logger3 := logger.Named("test3") - logger2.SetLevel(log.Info) - logger3.SetLevel(log.Error) + logger2.SetLevel(hclog.Info) + logger3.SetLevel(hclog.Error) - assert.Equal(t, log.Debug, logger.GetLevel()) - assert.Equal(t, log.Info, logger2.GetLevel()) - assert.Equal(t, log.Error, logger3.GetLevel()) + assert.Equal(t, hclog.Debug, logger.GetLevel()) + assert.Equal(t, hclog.Info, logger2.GetLevel()) + assert.Equal(t, hclog.Error, logger3.GetLevel()) +} + +func newTestLogConfig(t *testing.T) *LogConfig { + t.Helper() + + cfg, err := NewLogConfig("test") + require.NoError(t, err) + cfg.Name = "test-system" + + return cfg } diff --git a/website/content/docs/agent-and-proxy/agent/index.mdx b/website/content/docs/agent-and-proxy/agent/index.mdx index 5551caf8a..ebd1e1d1f 100644 --- a/website/content/docs/agent-and-proxy/agent/index.mdx +++ b/website/content/docs/agent-and-proxy/agent/index.mdx @@ -83,14 +83,17 @@ See the [caching](/vault/docs/agent-and-proxy/agent/caching#api) page for detail are `standard` and `json`. This can also be specified via the `VAULT_LOG_FORMAT` environment variable. -- `-log-file` ((#\_log_file)) - writes all the Vault agent log messages - to a file. This value is used as a prefix for the log file name. The current timestamp - is appended to the file name. If the value ends in a path separator, `vault-agent` - will be appended to the value. If the file name is missing an extension, `.log` - is appended. For example, setting `log-file` to `/var/log/` would result in a log - file path of `/var/log/vault-agent-{timestamp}.log`. `log-file` can be combined with - [`-log-rotate-bytes`](#_log_rotate_bytes) and [`-log-rotate-duration`](#_log_rotate_duration) - for a fine-grained log rotation experience. +- `-log-file` ((#\_log_file)) - the absolute path where Vault Agent should save + log messages. Paths that end with a path separator use the default file name, + `agent.log`. Paths that do not end with a file extension use the default + `.log` extension. If the log file rotates, Vault Agent appends the current + timestamp to the file name at the time of rotation. For example: + + `log-file` | Full log file | Rotated log file + ---------- | ------------- | ---------------- + `/var/log` | `/var/log/agent.log` | `/var/log/agent-{timestamp}.log` + `/var/log/my-diary` | `/var/log/my-diary.log` | `/var/log/my-diary-{timestamp}.log` + `/var/log/my-diary.txt` | `/var/log/my-diary.txt` | `/var/log/my-diary-{timestamp}.txt` - `-log-rotate-bytes` ((#\_log_rotate_bytes)) - to specify the number of bytes that should be written to a log before it needs to be rotated. Unless specified, diff --git a/website/content/docs/agent-and-proxy/proxy/index.mdx b/website/content/docs/agent-and-proxy/proxy/index.mdx index fdaae8ab8..086ff87ed 100644 --- a/website/content/docs/agent-and-proxy/proxy/index.mdx +++ b/website/content/docs/agent-and-proxy/proxy/index.mdx @@ -75,14 +75,17 @@ also be specified via the `VAULT_LOG_LEVEL` environment variable. are `standard` and `json`. This can also be specified via the `VAULT_LOG_FORMAT` environment variable. -- `-log-file` ((#\_log_file)) - writes all the Vault proxy log messages -to a file. This value is used as a prefix for the log file name. The current timestamp -is appended to the file name. If the value ends in a path separator, `vault-proxy` -will be appended to the value. If the file name is missing an extension, `.log` -is appended. For example, setting `log-file` to `/var/log/` would result in a log -file path of `/var/log/vault-proxy-{timestamp}.log`. `log-file` can be combined with -[`-log-rotate-bytes`](#_log_rotate_bytes) and [`-log-rotate-duration`](#_log_rotate_duration) -for a fine-grained log rotation experience. +- `-log-file` ((#\_log_file)) - the absolute path where Vault Proxy should save + log messages. Paths that end with a path separator use the default file name, + `proxy.log`. Paths that do not end with a file extension use the default + `.log` extension. If the log file rotates, Vault Proxy appends the current + timestamp to the file name at the time of rotation. For example: + + `log-file` | Full log file | Rotated log file + ---------- | ------------- | ---------------- + `/var/log` | `/var/log/proxy.log` | `/var/log/proxy-{timestamp}.log` + `/var/log/my-diary` | `/var/log/my-diary.log` | `/var/log/my-diary-{timestamp}.log` + `/var/log/my-diary.txt` | `/var/log/my-diary.txt` | `/var/log/my-diary-{timestamp}.txt` - `-log-rotate-bytes` ((#\_log_rotate_bytes)) - to specify the number of bytes that should be written to a log before it needs to be rotated. Unless specified, diff --git a/website/content/docs/commands/server.mdx b/website/content/docs/commands/server.mdx index 8c9f08f05..8a12a738a 100644 --- a/website/content/docs/commands/server.mdx +++ b/website/content/docs/commands/server.mdx @@ -60,15 +60,18 @@ flags](/vault/docs/commands) included on all commands. are `standard` and `json`. This can also be specified via the `VAULT_LOG_FORMAT` environment variable. -- `-log-file` ((#\_log_file)) - writes all the Vault log messages - to a file. This value is used as a prefix for the log file name. The current timestamp - is appended to the file name. If the value ends in a path separator, `vault` - will be appended to the value. If the file name is missing an extension, `.log` - is appended. For example, setting `log-file` to `/var/log/` would result in a log - file path of `/var/log/vault-{timestamp}.log`. `log-file` can be combined with - [`-log-rotate-bytes`](#_log_rotate_bytes) and [`-log-rotate-duration`](#_log_rotate_duration) - for a fine-grained log rotation experience. This output operates in addition to existing - outputs, meaning logs will continue to be written to journald / stdout (where appropriate). +- `-log-file` ((#\_log_file)) - the absolute path where Vault should save log + messages in addition to other, existing outputs like journald / stdout. Paths + that end with a path separator use the default file name, `vault.log`. Paths + that do not end with a file extension use the default `.log` extension. If the + log file rotates, Vault appends the current timestamp to the file name + at the time of rotation. For example: + + `log-file` | Full log file | Rotated log file + ---------- | ------------- | ---------------- + `/var/log` | `/var/log/vault.log` | `/var/log/vault-{timestamp}.log` + `/var/log/my-diary` | `/var/log/my-diary.log` | `/var/log/my-diary-{timestamp}.log` + `/var/log/my-diary.txt` | `/var/log/my-diary.txt` | `/var/log/my-diary-{timestamp}.txt` - `-log-rotate-bytes` ((#\_log_rotate_bytes)) - to specify the number of bytes that should be written to a log before it needs to be rotated. Unless specified,