file

package module
v0.1.13 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 12, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package file provides a file-based audit.Output implementation with automatic size-based rotation, backup retention, age-based cleanup, and optional gzip compression.

Construction

Create a file output with New:

out, err := file.New(&file.Config{
    Path:       "/var/log/audit/events.log",
    MaxSizeMB:  100,
    MaxBackups: 5,
    MaxAgeDays: 30,
})

The parent directory of [Config.Path] must exist before calling New; the file itself is created if it does not exist. Default permissions are 0600.

To observe rotation events, wire an audit.OutputMetrics value via WithOutputMetrics at construction. If the value also implements RotationRecorder its RecordRotation method is called on every rotation (structural typing — no explicit registration needed).

Rotation

When the active log file exceeds [Config.MaxSizeMB], it is renamed with a timestamp suffix and a new file is opened. Old backups are pruned by count ([Config.MaxBackups]) and age ([Config.MaxAgeDays]). Compressed backups use gzip (enabled by default).

Recommended import alias:

import auditfile "github.com/axonops/audit/file"

Index

Examples

Constants

View Source
const (
	// MaxSizeMB is the maximum allowed value for [Config.MaxSizeMB].
	// Values above this limit cause [New] to return an error
	// wrapping [audit.ErrConfigInvalid].
	MaxSizeMB = 10_240 // 10 GB

	// MaxBackups is the maximum allowed value for [Config.MaxBackups].
	// Values above this limit cause [New] to return an error
	// wrapping [audit.ErrConfigInvalid].
	MaxBackups = 100

	// MaxAgeDays is the maximum allowed value for [Config.MaxAgeDays].
	// Values above this limit cause [New] to return an error
	// wrapping [audit.ErrConfigInvalid].
	MaxAgeDays = 365

	// DefaultBufferSize is the default async buffer capacity for the
	// file output. Matches the default for webhook and loki outputs
	// to provide consistent behaviour across all async outputs.
	DefaultBufferSize = 10_000

	// MaxOutputBufferSize is the maximum allowed per-output async
	// buffer capacity. Values above this limit cause [New] to return
	// an error wrapping [audit.ErrConfigInvalid].
	MaxOutputBufferSize = 100_000
)

Variables

This section is empty.

Functions

func NewFactory

func NewFactory(factory audit.OutputMetricsFactory) audit.OutputFactory

NewFactory returns an audit.OutputFactory that creates file outputs from YAML configuration and wires per-output metrics via the supplied audit.OutputMetricsFactory. When factory is non-nil, the returned audit.Output receives its per-output audit.OutputMetrics via WithOutputMetrics at construction time; if the returned metrics also implement RotationRecorder, rotation telemetry is wired in automatically. Pass nil to disable per-output metrics (equivalent to the init()-registered default factory).

Signature is identical to the other output modules' `NewFactory` (syslog, webhook, loki) for consistency (#581).

Types

type Config

type Config struct {
	// Path is the filesystem path for the audit log file. REQUIRED.
	// Relative paths are resolved to absolute at construction time.
	// The parent directory must exist when [New] is called.
	Path string

	// GroupReadable, when false (the default), creates files readable
	// only by the owning user (mode 0o600) — the recommended setting
	// for audit logs. Set true to also allow read access by the file's
	// group (mode 0o640), used when a SIEM forwarder (Filebeat,
	// Promtail, Fluentd) runs as a separate user in the file's group.
	//
	// No other modes are supported. World-readable or group-writable
	// audit logs are a security defect: audit data may contain PII,
	// credentials, or operational details, and the trail must be
	// append-only from a single writer to preserve tamper-detection.
	// SOX, HIPAA, and GDPR all require this constraint. Operators
	// needing finer-grained access should use ACLs at the OS level,
	// not relax the library's mode.
	//
	// At construction, if an existing audit log file's permissions are
	// broader than the configured target, [New] wraps
	// [audit.ErrConfigInvalid]; setuid/setgid/sticky bits or a
	// hardlink count above 1 are also rejected as tamper indicators.
	GroupReadable bool

	// MaxSizeMB is the maximum size in megabytes of a single log file
	// before rotation. Zero defaults to 100. Values above [MaxSizeMB]
	// (10,240 = 10 GB) cause [New] to return an error wrapping
	// [audit.ErrConfigInvalid].
	MaxSizeMB int

	// MaxBackups is the maximum number of rotated backup files to
	// retain. Zero defaults to 5. Values above [MaxBackups] (100)
	// cause [New] to return an error wrapping [audit.ErrConfigInvalid].
	MaxBackups int

	// MaxAgeDays is the maximum age in days of rotated backup files
	// before deletion. Zero defaults to 30. Values above [MaxAgeDays]
	// (365) cause [New] to return an error wrapping
	// [audit.ErrConfigInvalid].
	MaxAgeDays int

	// Compress enables gzip compression of rotated backup files.
	// When nil, defaults to true.
	Compress *bool

	// BufferSize is the internal async buffer capacity. When full,
	// new events are dropped and [audit.OutputMetrics.RecordDrop] is
	// called. Zero defaults to [DefaultBufferSize] (10,000). Values
	// above [MaxOutputBufferSize] (100,000) cause [New] to return an
	// error wrapping [audit.ErrConfigInvalid].
	BufferSize int
}

Config holds configuration for Output.

type Option added in v0.1.11

type Option func(*options)

Option configures a file Output at construction time. Options are passed as variadic arguments to New and applied in order before any configuration validation or warning emission.

func WithDiagnosticLogger added in v0.1.11

func WithDiagnosticLogger(l *slog.Logger) Option

WithDiagnosticLogger routes construction-time and runtime warnings (permission-mode warnings, rotation notices, delivery failures) to the given logger. When nil or not supplied, warnings go to slog.Default.

Consumers normally do not call this directly when using github.com/axonops/audit/outputconfig.Load — outputconfig plumbs the auditor's diagnostic logger into every output it constructs. Use this option when constructing a file output programmatically and you want its warnings to match your application's log handler.

The option mirrors github.com/axonops/audit.WithDiagnosticLogger at the auditor level; the same logger may be passed to both for consistent routing.

func WithOutputMetrics added in v0.1.12

func WithOutputMetrics(m audit.OutputMetrics) Option

WithOutputMetrics sets the audit.OutputMetrics sink for this output. When omitted or nil, metrics calls become no-ops via audit.NoOpOutputMetrics. Mirrors WithDiagnosticLogger in usage and zero-value semantics.

If the supplied value also implements RotationRecorder, rotation telemetry is wired in automatically (structural typing — see net/http.Flusher precedent).

Consumers normally do not call this directly when using github.com/axonops/audit/outputconfig.Load — outputconfig wires per-output metrics through the audit.OutputMetricsFactory supplied via outputconfig.WithOutputMetricsFactory.

type Output

type Output struct {
	// contains filtered or unexported fields
}

Output writes serialised audit events to a file with automatic size-based rotation. It supports backup retention, age-based cleanup, and optional gzip compression.

Write enqueues events into an internal buffered channel and returns immediately. A background goroutine reads from the channel and performs the actual file I/O. If the channel is full, the event is dropped and metrics are recorded.

Output is safe for concurrent use, including concurrent calls to Output.Write and Output.Close.

func New

func New(cfg *Config, opts ...Option) (*Output, error)

New creates a new Output from the given config. It validates the path, permissions, and parent directory existence, then starts a background goroutine for async event delivery.

Per-output metrics may be supplied at construction via WithOutputMetrics. When omitted, telemetry calls become no-ops.

Callers MUST NOT mutate cfg.Compress via the pointer after New returns — the defensive copy is shallow, so caller and Output share the same *bool. Mutating other fields after New is safe; they are copied by value.

Example
package main

import (
	"fmt"
	"log"
	"os"
	"path/filepath"

	"github.com/axonops/audit/file"
)

func main() {
	// Create a file output with rotation for production use.
	dir, err := os.MkdirTemp("", "audit-example-*")
	if err != nil {
		log.Fatal(err)
	}
	defer func() { _ = os.RemoveAll(dir) }()

	out, err := file.New(&file.Config{
		Path:       filepath.Join(dir, "audit.log"),
		MaxSizeMB:  100,
		MaxBackups: 5,
		MaxAgeDays: 30,
		// GroupReadable defaults to false (mode 0o600).
	})
	if err != nil {
		fmt.Println("create error:", err)
		return
	}
	defer func() { _ = out.Close() }()

	fmt.Println("file output created")
}
Output:
file output created

func (*Output) Close

func (f *Output) Close() error

Close signals the background goroutine to drain the buffer and flush remaining events, then closes the underlying file writer. Close is idempotent and safe for concurrent use with Output.Write.

func (*Output) DestinationKey

func (f *Output) DestinationKey() string

DestinationKey returns the absolute filesystem path, enabling duplicate destination detection via audit.DestinationKeyer.

func (*Output) LastDeliveryNanos added in v0.1.12

func (f *Output) LastDeliveryNanos() int64

LastDeliveryNanos returns the wall-clock UnixNano of the most recent successful disk flush, or 0 if no flush has yet succeeded. Implements audit.LastDeliveryReporter (#753).

func (*Output) Name

func (f *Output) Name() string

Name returns the human-readable identifier for this output.

func (*Output) ReportsDelivery added in v0.1.11

func (f *Output) ReportsDelivery() bool

ReportsDelivery returns true, indicating that Output reports its own delivery metrics from the background writeLoop after actual file I/O, not from the Write enqueue path.

func (*Output) Write

func (f *Output) Write(data []byte) error

Write enqueues a serialised audit event for async delivery to the file. The data is copied before enqueuing — the caller may reuse the backing array after Write returns. If the internal buffer is full, the event is dropped and audit.OutputMetrics.RecordDrop is called. Write never blocks the caller.

type RotationRecorder added in v0.1.12

type RotationRecorder interface {
	// RecordRotation records that the file output rotated its active
	// log file. path is the absolute filesystem path of the file that
	// was rotated. Implementations SHOULD NOT use path as an unbounded
	// metric label — it may expose infrastructure topology and cause
	// cardinality explosion.
	RecordRotation(path string)
}

RotationRecorder is an OPTIONAL extension interface for file-output rotation telemetry. A consumer's audit.OutputMetrics implementation MAY also implement RotationRecorder. When the file output receives per-output metrics via WithOutputMetrics (or factory wiring via outputconfig.WithOutputMetricsFactory), it type-asserts for RotationRecorder and invokes RecordRotation on every log-file rotation. Precedent: net/http.Flusher as an optional extension on [http.ResponseWriter].

Consumers who do not care about rotation telemetry need not implement this interface — the base audit.OutputMetrics contract is sufficient.

Directories

Path Synopsis
internal
rotate
Package rotate provides a symlink-safe, permission-enforcing file writer with size-based rotation, backup retention, age-based cleanup, and optional gzip compression.
Package rotate provides a symlink-safe, permission-enforcing file writer with size-based rotation, backup retention, age-based cleanup, and optional gzip compression.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL