Repository: kubernetes/kubernetes
File: staging/src/k8s.io/apiserver/pkg/server/options/audit.go (Go)

Code before:
	}

	return allErrors
}

// Check whether the log backend is enabled based on the options.
func (o *AuditLogOptions) enabled() bool {
	return o != nil && o.Path != ""
}

func (o *AuditLogOptions) getWriter() (io.Writer, error) {
	if !o.enabled() {
		return nil, nil
	}

	if o.Path == "-" {
		return os.Stdout, nil
	}

	if err := o.ensureLogFile(); err != nil {
		return nil, fmt.Errorf("ensureLogFile: %w", err)
	}

	maxSize := o.MaxSize
	if maxSize == 0 {
		maxSize = math.MaxInt32
	}

	return &lumberjack.Logger{
		Filename:   o.Path,
		MaxAge:     o.MaxAge,
		MaxBackups: o.MaxBackups,
		MaxSize:    maxSize,
		Compress:   o.Compress,
	}, nil
}

func (o *AuditLogOptions) ensureLogFile() error {
	if err := os.MkdirAll(filepath.Dir(o.Path), 0700); err != nil {
		return err
	}
	mode := os.FileMode(0600)
	f, err := os.OpenFile(o.Path, os.O_CREATE|os.O_APPEND|os.O_RDWR, mode)
	if err != nil {
		return err
	}
	return f.Close()
}

func (o *AuditLogOptions) newBackend(w io.Writer) audit.Backend {
	groupVersion, _ := schema.ParseGroupVersion(o.GroupVersionString)

Review comment (performance):
This is trying to effectively disable rotation. Rotation is the only thing the lumberjack library is doing for us ... if we're not rotating, I'm not sure why we wouldn't simply return an io.Writer that writes directly to the specified file, like this:

```diff
diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/audit.go b/staging/src/k8s.io/apiserver/pkg/server/options/audit.go
index af5b06a5bd7..c404627641d 100644
--- a/staging/src/k8s.io/apiserver/pkg/server/options/audit.go
+++ b/staging/src/k8s.io/apiserver/pkg/server/options/audit.go
@@ -154,6 +154,11 @@ func NewAuditOptions() *AuditOptions {
 			GroupVersionString: "audit.k8s.io/v1",
 		},
 		LogOptions: AuditLogOptions{
+			// defaults
+			MaxSize:    100, // rotate at 100MB (matches lumberjack default)
+			MaxAge:     366, // prune history after a year
+			MaxBackups: 100, // prune history after 100*100MB = ~10GB
+
 			Format: pluginlog.FormatJson,
 			BatchOptions: AuditBatchOptions{
 				Mode:        ModeBlocking,
@@ -436,11 +441,11 @@ func (o *AuditLogOptions) AddFlags(fs *pflag.FlagSet) {
 	fs.StringVar(&o.Path, "audit-log-path", o.Path,
 		"If set, all requests coming to the apiserver will be logged to this file.  '-' means standard out.")
 	fs.IntVar(&o.MaxAge, "audit-log-maxage", o.MaxAge,
-		"The maximum number of days to retain old audit log files based on the timestamp encoded in their filename.")
+		"The maximum number of days to retain old audit log files based on the timestamp encoded in their filename. Setting a value of 0 means old audit log files are not removed based on age.")
 	fs.IntVar(&o.MaxBackups, "audit-log-maxbackup", o.MaxBackups,
 		"The maximum number of old audit log files to retain. Setting a value of 0 will mean there's no restriction on the number of files.")
 	fs.IntVar(&o.MaxSize, "audit-log-maxsize", o.MaxSize,
-		"The maximum size in megabytes of the audit log file before it gets rotated.")
+		"The maximum size in megabytes of the audit log file before it gets rotated. Setting to 0 disables rotation (not recommended).")
 	fs.StringVar(&o.Format, "audit-log-format", o.Format,
 		"Format of saved audits. \"legacy\" indicates 1-line text format for each event."+
 			" \"json\" indicates structured json format. Known formats are "+
@@ -506,6 +511,11 @@ func (o *AuditLogOptions) getWriter() (io.Writer, error) {
 		return nil, fmt.Errorf("ensureLogFile: %w", err)
 	}
 
+	if o.MaxSize == 0 {
+		// MaxSize of 0 disables rotation
+		return os.OpenFile(o.Path, os.O_APPEND|os.O_WRONLY, 0644)
+	}
+
 	return &lumberjack.Logger{
 		Filename:   o.Path,
 		MaxAge:     o.MaxAge,
```

I also think we should improve the default retention settings to prune old logs eventually ... not doing that is a time-bomb for admins

Code after:
	}
	if o.MaxSize < 0 {
		allErrors = append(allErrors, fmt.Errorf("--audit-log-maxsize %v can't be a negative number", o.MaxSize))
	}

	return allErrors
}

// Check whether the log backend is enabled based on the options.
func (o *AuditLogOptions) enabled() bool {
	return o != nil && o.Path != ""
}

func (o *AuditLogOptions) getWriter() (io.Writer, error) {
	if !o.enabled() {
		return nil, nil
	}

	if o.Path == "-" {
		return os.Stdout, nil
	}

	if err := o.ensureLogFile(); err != nil {
		return nil, fmt.Errorf("ensureLogFile: %w", err)
	}

	if o.MaxSize == 0 {
		return os.OpenFile(o.Path, os.O_APPEND|os.O_WRONLY, 0644)
	}

	return &lumberjack.Logger{
		Filename:   o.Path,
		MaxAge:     o.MaxAge,
		MaxBackups: o.MaxBackups,
		MaxSize:    o.MaxSize,
		Compress:   o.Compress,
	}, nil
}

func (o *AuditLogOptions) ensureLogFile() error {
	if err := os.MkdirAll(filepath.Dir(o.Path), 0700); err != nil {
		return err
	}
	mode := os.FileMode(0600)
	f, err := os.OpenFile(o.Path, os.O_CREATE|os.O_APPEND|os.O_RDWR, mode)
	if err != nil {
		return err
	}
	return f.Close()
}