caddy/caddyhttp/httpserver/roller.go
Matthew Holt 930ca1cc1b main,log,errors: Option to disable log rotation ("rolling")
For log and errors directive, as well as process log.
2019-01-28 10:28:22 -07:00

146 lines
4.0 KiB
Go

// Copyright 2015 Light Code Labs, LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package httpserver
import (
"errors"
"io"
"path/filepath"
"strconv"
lumberjack "gopkg.in/natefinch/lumberjack.v2"
)
// LogRoller implements a type that provides a rolling logger.
type LogRoller struct {
Disabled bool
Filename string
MaxSize int
MaxAge int
MaxBackups int
Compress bool
LocalTime bool
}
// GetLogWriter returns an io.Writer that writes to a rolling logger.
// This should be called only from the main goroutine (like during
// server setup) because this method is not thread-safe; it is careful
// to create only one log writer per log file, even if the log file
// is shared by different sites or middlewares. This ensures that
// rolling is synchronized, since a process (or multiple processes)
// should not create more than one roller on the same file at the
// same time. See issue #1363.
func (l LogRoller) GetLogWriter() io.Writer {
absPath, err := filepath.Abs(l.Filename)
if err != nil {
absPath = l.Filename // oh well, hopefully they're consistent in how they specify the filename
}
lj, has := lumberjacks[absPath]
if !has {
lj = &lumberjack.Logger{
Filename: l.Filename,
MaxSize: l.MaxSize,
MaxAge: l.MaxAge,
MaxBackups: l.MaxBackups,
Compress: l.Compress,
LocalTime: l.LocalTime,
}
lumberjacks[absPath] = lj
}
return lj
}
// IsLogRollerSubdirective is true if the subdirective is for the log roller.
func IsLogRollerSubdirective(subdir string) bool {
return subdir == directiveRotateSize ||
subdir == directiveRotateAge ||
subdir == directiveRotateKeep ||
subdir == directiveRotateCompress ||
subdir == directiveRotateDisable
}
var errInvalidRollParameter = errors.New("invalid roller parameter")
// ParseRoller parses roller contents out of c.
func ParseRoller(l *LogRoller, what string, where ...string) error {
if l == nil {
l = DefaultLogRoller()
}
// rotate_compress doesn't accept any parameters.
// others only accept one parameter
if ((what == directiveRotateCompress || what == directiveRotateDisable) && len(where) != 0) ||
((what != directiveRotateCompress && what != directiveRotateDisable) && len(where) != 1) {
return errInvalidRollParameter
}
var (
value int
err error
)
if what != directiveRotateCompress && what != directiveRotateDisable {
value, err = strconv.Atoi(where[0])
if err != nil {
return err
}
}
switch what {
case directiveRotateDisable:
l.Disabled = true
case directiveRotateSize:
l.MaxSize = value
case directiveRotateAge:
l.MaxAge = value
case directiveRotateKeep:
l.MaxBackups = value
case directiveRotateCompress:
l.Compress = true
}
return nil
}
// DefaultLogRoller will roll logs by default.
func DefaultLogRoller() *LogRoller {
return &LogRoller{
MaxSize: defaultRotateSize,
MaxAge: defaultRotateAge,
MaxBackups: defaultRotateKeep,
Compress: false,
LocalTime: true,
}
}
const (
// defaultRotateSize is 100 MB.
defaultRotateSize = 100
// defaultRotateAge is 14 days.
defaultRotateAge = 14
// defaultRotateKeep is 10 files.
defaultRotateKeep = 10
directiveRotateDisable = "rotate_disable"
directiveRotateSize = "rotate_size"
directiveRotateAge = "rotate_age"
directiveRotateKeep = "rotate_keep"
directiveRotateCompress = "rotate_compress"
)
// lumberjacks maps log filenames to the logger
// that is being used to keep them rolled/maintained;
// if rolling is disabled, it's just a regular
// *os.File, not a lumberjack
var lumberjacks = make(map[string]io.Writer)