Backport of fix `-log-file` so that it uses the correct name and only adds timestamps on rotation into release/1.14.x (#24322)

* backport of commit 06b9325bb9e6616789c4fe5e7778459ba98a14ab

* fix server.go imports

---------

Co-authored-by: Peter Wilson <peter.wilson@hashicorp.com>
This commit is contained in:
hc-github-team-secure-vault-core 2023-12-01 07:33:09 -05:00 committed by GitHub
parent 062747a05d
commit 5efd02708e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 237 additions and 125 deletions

2
changelog/24297.txt Normal file
View File

@ -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.

View File

@ -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 {

View File

@ -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 {

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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")

View File

@ -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
}

View File

@ -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,

View File

@ -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,

View File

@ -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,