feat: support admin/access logs on standard streams

The access-log and admin-access-log options now accept stdout, stderr, or - for
stdout in addition to file paths. Standard stream destinations are kept open
during shutdown and SIGHUP handling, while file destinations continue to support
normal reopen behavior for log rotation. CLI help, embedded config comments, and
the example configuration describe the new destination values.

Fixes #2245
This commit is contained in:
Ben McClelland
2026-09-02 14:21:28 -07:00
parent 535cc9d521
commit 5f9041ff5f
6 changed files with 46 additions and 22 deletions
+2 -2
View File
@@ -442,13 +442,13 @@ func initFlags() []cli.Flag {
},
&cli.StringFlag{
Name: "access-log",
Usage: "enable server access logging to specified file",
Usage: "enable server access logging to specified file, stdout, stderr, or - for stdout",
EnvVars: []string{"LOGFILE", "VGW_ACCESS_LOG"},
Destination: &accessLog,
},
&cli.StringFlag{
Name: "admin-access-log",
Usage: "enable admin server access logging to specified file",
Usage: "enable admin server access logging to specified file, stdout, stderr, or - for stdout",
EnvVars: []string{"LOGFILE", "VGW_ADMIN_ACCESS_LOG"},
Destination: &adminLogFile,
},
+2 -2
View File
@@ -483,13 +483,13 @@ func initFlags() []cli.Flag {
},
&cli.StringFlag{
Name: "access-log",
Usage: "enable server access logging to specified file",
Usage: "enable server access logging to specified file, stdout, stderr, or - for stdout",
EnvVars: []string{"LOGFILE", "VGW_ACCESS_LOG"},
Destination: &accessLog,
},
&cli.StringFlag{
Name: "admin-access-log",
Usage: "enable admin server access logging to specified file",
Usage: "enable admin server access logging to specified file, stdout, stderr, or - for stdout",
EnvVars: []string{"LOGFILE", "VGW_ADMIN_ACCESS_LOG"},
Destination: &adminLogFile,
},
+4 -2
View File
@@ -347,14 +347,16 @@ type Config struct {
// are independent and can be enabled simultaneously in any combination.
// All are optional; omit or leave empty to disable that output.
// AccessLog is the file path for S3 request access logs in the AWS S3
// AccessLog is the file path or stream name (stdout, stderr, or - for
// stdout) for S3 request access logs in the AWS S3
// access log format. Use absolute paths; relative paths may break if the
// server changes its working directory. Empty disables file logging.
AccessLog string
// LogWebhookURL is an HTTP(S) URL that receives S3 access log entries as
// JSON-encoded POST requests. Can be set alongside AccessLog.
LogWebhookURL string
// AdminLogFile is the file path for admin API request logs.
// AdminLogFile is the file path or stream name (stdout, stderr, or - for
// stdout) for admin API request logs.
AdminLogFile string
// Metrics
+8 -8
View File
@@ -196,18 +196,18 @@ ROOT_SECRET_ACCESS_KEY=
# Access Logs #
###############
# The VGW_ACCESS_LOG option when set will specify the file to log all S3
# server requests to. This option is optional, and defaults to not logging.
# It is suggested to use absolute paths for the server log file because the
# server may chdir into the backend root directory and change locations for
# relative paths.
# The VGW_ACCESS_LOG option when set will specify where to log all S3
# server requests. Set it to a file path, stdout, stderr, or - for stdout.
# This option is optional, and defaults to not logging. When using a file,
# it is suggested to use an absolute path because the server may chdir into
# the backend root directory and change locations for relative paths.
# The log file format follows the AWS S3 access log format documented in
# https://docs.aws.amazon.com/AmazonS3/latest/userguide/LogFormat.html.
#VGW_ACCESS_LOG=
# The VGW_ADMIN_ACCESS_LOG option when set will specify the file to log all
# admin server requests to. When not set, admin requests are logged to the
# same file as the S3 server (VGW_ACCESS_LOG) if that is configured.
# The VGW_ADMIN_ACCESS_LOG option when set will specify where to log all
# admin server requests. Set it to a file path, stdout, stderr, or - for
# stdout. This option is optional, and defaults to not logging admin requests.
#VGW_ADMIN_ACCESS_LOG=
# The VGW_LOG_WEBHOOK_URL option when set will specify the URL to send the
+28 -6
View File
@@ -35,24 +35,37 @@ const (
// FileLogger is a local file audit log
type FileLogger struct {
logfile string
f *os.File
gotErr bool
mu sync.Mutex
logfile string
f *os.File
standardStream bool
gotErr bool
mu sync.Mutex
}
var _ AuditLogger = &FileLogger{}
// InitFileLogger initializes audit logs to local file
func InitFileLogger(logname string) (AuditLogger, error) {
f, err := os.OpenFile(logname, os.O_APPEND|os.O_CREATE|os.O_WRONLY, logFileMode)
f, standardStream, err := openLogDestination(logname)
if err != nil {
return nil, fmt.Errorf("open log: %w", err)
}
fmt.Fprintf(f, "log starts %v\n", time.Now())
return &FileLogger{logfile: logname, f: f}, nil
return &FileLogger{logfile: logname, f: f, standardStream: standardStream}, nil
}
func openLogDestination(logname string) (*os.File, bool, error) {
switch strings.ToLower(logname) {
case "stdout", "-":
return os.Stdout, true, nil
case "stderr":
return os.Stderr, true, nil
default:
f, err := os.OpenFile(logname, os.O_APPEND|os.O_CREATE|os.O_WRONLY, logFileMode)
return f, false, err
}
}
// Log sends log message to file logger
@@ -222,6 +235,11 @@ func (f *FileLogger) writeLog(lf LogFields) {
// HangUp closes current logfile handle and opens a new one
// typically needed for log rotations
func (f *FileLogger) HangUp() error {
if f.standardStream {
f.f.WriteString(fmt.Sprintf("log starts %v\n", time.Now()))
return nil
}
err := f.f.Close()
if err != nil {
return fmt.Errorf("close log: %w", err)
@@ -239,5 +257,9 @@ func (f *FileLogger) HangUp() error {
// Shutdown closes logfile handle
func (f *FileLogger) Shutdown() error {
if f.standardStream {
return nil
}
return f.f.Close()
}
+2 -2
View File
@@ -34,14 +34,14 @@ var _ AuditLogger = &AdminFileLogger{}
// InitFileLogger initializes audit logs to local file
func InitAdminFileLogger(logname string) (AuditLogger, error) {
f, err := os.OpenFile(logname, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
f, standardStream, err := openLogDestination(logname)
if err != nil {
return nil, fmt.Errorf("open log: %w", err)
}
f.WriteString(fmt.Sprintf("log starts %v\n", time.Now()))
return &AdminFileLogger{FileLogger: FileLogger{logfile: logname, f: f}}, nil
return &AdminFileLogger{FileLogger: FileLogger{logfile: logname, f: f, standardStream: standardStream}}, nil
}
// Log sends log message to file logger