rotating

package module
v0.0.0-...-7b76ede Latest Latest
Warning

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

Go to latest
Published: Jan 6, 2021 License: MIT Imports: 14 Imported by: 0

README

rotating

A representation of a file that knows how to rotate itself based on size/interval

Loosely based on Perl5's File::RotateLogs

CAVEAT EMPTOR

This software has not been tested in the wild yet (Jan 2020)

SYNOPSIS

f, err := rotating.NewFile(
	ctx,
	filepath.Join(dir, "%Y%m%d-%H%M%S.log"),
	rotating.WithClock(clock),
	rotating.WithMaxFileSize(1),
	rotating.WithMaxInterval(5*time.Second),
	rotating.WithCheckInterval(100*time.Millisecond),
	rotating.WithRotationCount(5),
)

// *rotating.File fulfills io.Writer, so you can use it anywehere
// io.Writer is accepted
fmt.Fprintf(f, ...)

CONTEXT

The first argument to rotation.NewFile is a context object. This context should be kept alive during the entire time you use the log. It is used to control certain (possibly) long-running operations inside the object.

PATTERN

The second argument to rotation.NewFile is the file name pattern to use to generate the backing files. Tha pettern is fed into github.com/lestrrat-go/strftime.

FILENAMES AND ROTATION

While you are free to configure your filenames as you please, when using rotating.WithRotateCount option, you should make sure to include all of the necessary components to figure out precisely when the files were generated.

This is because files to purge are determined by file name order. If you do not provide enough information in your file names to allow sorting in chronologicall order, we will not be able to figure out which files to purge.

For example, if you provided a file name pattern like %H%M%S.log, we will not be able to determine if files generated at the same time belong to today or yesterday, or ..., and hence we might delete the wrong file.

Why can't we use the modification timestamp? We could, but there are edge cases like a user updating a file manually, ore we sync the previous log after we start writing to the new log. And if the next rotation happens fast enough, the timestamps may not aligh properly as expected.

While in reality this edge case will not trigger unless a specific configuration is used, being able to explain that files are purged in the file name order is much simpler for everybody, so we use that rule.

TIMESTAMPS USED FOR FILENAMES

We use a "clock" to determine the time to switch log files, and not elapsed times (via, for example, a time.Ticker). This is because in reality system clocks can be changed during an execution of a long running process, and sometimes you need to rotate files based on those changes.

This also means that we need to be able to determine which files to write by the current wall clock time. Therefore we use the observed wall clock time and the maximum interval (via WithMaxInterval)

At a given time t, we truncate the time by the interval, and use that truncated time to generate the current file name that we think we should write to.

For example, given an interval of one hour, and a file name pattern of %H%M%S.log, the following rules apply:

time filename
2021-01-01 00:00:00 000000.log
2021-01-01 00:59:00 000000.log
2021-01-01 01:00:00 010000.log
2021-01-01 23:01:00 230100.log

BUFFERING

The underlying io.Writer for *rotating.File is a raw *os.File. Therefore to maximize efficiency you should wrap the object in a bufio.Writer

OPTIONS

WithMaxInterval(time.Duration)

Specifies the interval between switching log files.

WithMaxFileSize(int64)

Specifies the max file size before switching log files.

WithRotationCount(int)

Specifies the number of logs to retain. See the PATTERN for an explanation of how the files to retain are selected.

Creates a symlink to the current log file being written to.

WithClock(Clock)

Use to provide a Clock to the file. For example,

Filing Issues

Please do not file issues without code to show for it. Issues labeled with "needs reproduction" and without a minimal reproducible standalone Go test case may be closed without any warning.

Documentation

Overview

Package rotating provides tools to write to a "self-rotating" file. Unlike using an external service like logrotate, the File struct knows how to rotate itself when the conditions are met.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Clock

type Clock interface {
	Now() time.Time
}

func Local

func Local() Clock

func UTC

func UTC() Clock

type ClockFn

type ClockFn func() time.Time

func (ClockFn) Now

func (fn ClockFn) Now() time.Time

type File

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

func NewFile

func NewFile(ctx context.Context, p string, options ...Option) (*File, error)

func (*File) Close

func (f *File) Close() error

func (*File) Write

func (f *File) Write(p []byte) (int, error)

Write satisfies the io.Writer interface.

type Option

type Option = option.Interface

func WithCheckInterval

func WithCheckInterval(v time.Duration) Option

func WithClock

func WithClock(c Clock) Option

WithClock creates a new Option that sets a clock that the File object will use to determine the current time.

By default rotating.Local, which returns the current time in the local time zone, is used. If you/ would rather use UTC, use rotating.UTC as the argument to this option, and pass it to the constructor.

func WithMaxFileSize

func WithMaxFileSize(v int64) Option

func WithMaxInterval

func WithMaxInterval(v time.Duration) Option

WithMaxInterval specifies the time between creation of a new file

Please note that this option does not necessarily mean "files will be created after this amount of time" which is may be a bit surprising.

This flag specifies that we should partition the time in slots that are `v` duration each, and create a new file every time the time is divisible by `v`

For example, consider the following scenario: * `v` is `time.Hour` * we're starting to write at 00:05:00 Jan 1, 2021 * pattern for the file name is "%Y%m%d-%H%M%S.log"

In this scenario, we're in the hourly time slot starting at 00:00:00 Jan 1, 2021, so the file name will be `20210101-000000.log` When we reach the next time slot, we start writing to a file named `20210101-0100000.log` (also note that %M %S are always 0, because the resolution is "hour"). We would be writing to the same file even if we started writing at 00:59:59 Jan 1, 2021, only to switch to writing a new file (20210101-010000.log) soon after.

This behavior is mainly due to the fact that there is no portable way of finding out the creation time of a file across platforms, and we can only reliably switch target files based on the current time.

func WithRotationCount

func WithRotationCount(v int) Option
func WithSymlink(v string) Option

Jump to

Keyboard shortcuts

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