mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-23 22:27:38 -05:00
Roll all logs by default (#1379)
* Use new subdirectives and flatten rolling config * Set default rotate config * Set default rolling config (hopefully) errwhere * Make private * Flatten errors directive and remove c.IncrNest() * Don't skip first error log roller subdirective we see * Remove hadBlock * Try lumberjack import * Unname import
This commit is contained in:
parent
f32eed1912
commit
ce7d3db1be
6 changed files with 207 additions and 156 deletions
|
@ -120,12 +120,6 @@ func (d *Dispenser) NextBlock() bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// IncrNest adds a level of nesting to the dispenser.
|
||||
func (d *Dispenser) IncrNest() {
|
||||
d.nesting++
|
||||
return
|
||||
}
|
||||
|
||||
// Val gets the text of the current token. If there is no token
|
||||
// loaded, it returns empty string.
|
||||
func (d *Dispenser) Val() string {
|
||||
|
|
|
@ -40,33 +40,20 @@ func errorsParse(c *caddy.Controller) (*ErrorHandler, error) {
|
|||
|
||||
cfg := httpserver.GetConfig(c)
|
||||
|
||||
optionalBlock := func() (bool, error) {
|
||||
var hadBlock bool
|
||||
|
||||
optionalBlock := func() error {
|
||||
for c.NextBlock() {
|
||||
hadBlock = true
|
||||
|
||||
what := c.Val()
|
||||
if !c.NextArg() {
|
||||
return hadBlock, c.ArgErr()
|
||||
return c.ArgErr()
|
||||
}
|
||||
where := c.Val()
|
||||
|
||||
if what == "log" {
|
||||
if where == "visible" {
|
||||
handler.Debug = true
|
||||
} else {
|
||||
handler.Log.Output = where
|
||||
if c.NextArg() {
|
||||
if c.Val() == "{" {
|
||||
c.IncrNest()
|
||||
logRoller, err := httpserver.ParseRoller(c)
|
||||
if httpserver.IsLogRollerSubdirective(what) {
|
||||
var err error
|
||||
err = httpserver.ParseRoller(handler.Log.Roller, what, where)
|
||||
if err != nil {
|
||||
return hadBlock, err
|
||||
}
|
||||
handler.Log.Roller = logRoller
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// Error page; ensure it exists
|
||||
|
@ -82,24 +69,24 @@ func errorsParse(c *caddy.Controller) (*ErrorHandler, error) {
|
|||
|
||||
if what == "*" {
|
||||
if handler.GenericErrorPage != "" {
|
||||
return hadBlock, c.Errf("Duplicate status code entry: %s", what)
|
||||
return c.Errf("Duplicate status code entry: %s", what)
|
||||
}
|
||||
handler.GenericErrorPage = where
|
||||
} else {
|
||||
whatInt, err := strconv.Atoi(what)
|
||||
if err != nil {
|
||||
return hadBlock, c.Err("Expecting a numeric status code or '*', got '" + what + "'")
|
||||
return c.Err("Expecting a numeric status code or '*', got '" + what + "'")
|
||||
}
|
||||
|
||||
if _, exists := handler.ErrorPages[whatInt]; exists {
|
||||
return hadBlock, c.Errf("Duplicate status code entry: %s", what)
|
||||
return c.Errf("Duplicate status code entry: %s", what)
|
||||
}
|
||||
|
||||
handler.ErrorPages[whatInt] = where
|
||||
}
|
||||
}
|
||||
}
|
||||
return hadBlock, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
for c.Next() {
|
||||
|
@ -107,21 +94,23 @@ func errorsParse(c *caddy.Controller) (*ErrorHandler, error) {
|
|||
if c.Val() == "}" {
|
||||
continue
|
||||
}
|
||||
// Configuration may be in a block
|
||||
hadBlock, err := optionalBlock()
|
||||
if err != nil {
|
||||
return handler, err
|
||||
|
||||
args := c.RemainingArgs()
|
||||
|
||||
if len(args) == 1 {
|
||||
switch args[0] {
|
||||
case "visible":
|
||||
handler.Debug = true
|
||||
default:
|
||||
handler.Log.Output = args[0]
|
||||
handler.Log.Roller = httpserver.DefaultLogRoller()
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, the only argument would be an error log file name or 'visible'
|
||||
if !hadBlock {
|
||||
if c.NextArg() {
|
||||
if c.Val() == "visible" {
|
||||
handler.Debug = true
|
||||
} else {
|
||||
handler.Log.Output = c.Val()
|
||||
}
|
||||
}
|
||||
// Configuration may be in a block
|
||||
err := optionalBlock()
|
||||
if err != nil {
|
||||
return handler, err
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -62,19 +62,17 @@ func TestErrorsParse(t *testing.T) {
|
|||
}},
|
||||
{`errors errors.txt`, false, ErrorHandler{
|
||||
ErrorPages: map[int]string{},
|
||||
Log: &httpserver.Logger{Output: "errors.txt"},
|
||||
Log: &httpserver.Logger{
|
||||
Output: "errors.txt",
|
||||
Roller: httpserver.DefaultLogRoller(),
|
||||
},
|
||||
}},
|
||||
{`errors visible`, false, ErrorHandler{
|
||||
ErrorPages: map[int]string{},
|
||||
Debug: true,
|
||||
Log: &httpserver.Logger{},
|
||||
}},
|
||||
{`errors { log visible }`, false, ErrorHandler{
|
||||
ErrorPages: map[int]string{},
|
||||
Debug: true,
|
||||
Log: &httpserver.Logger{},
|
||||
}},
|
||||
{`errors { log errors.txt
|
||||
{`errors errors.txt {
|
||||
404 404.html
|
||||
500 500.html
|
||||
}`, false, ErrorHandler{
|
||||
|
@ -82,22 +80,26 @@ func TestErrorsParse(t *testing.T) {
|
|||
404: "404.html",
|
||||
500: "500.html",
|
||||
},
|
||||
Log: &httpserver.Logger{Output: "errors.txt"},
|
||||
Log: &httpserver.Logger{
|
||||
Output: "errors.txt",
|
||||
Roller: httpserver.DefaultLogRoller(),
|
||||
},
|
||||
}},
|
||||
{`errors { log errors.txt { size 2 age 10 keep 3 } }`, false, ErrorHandler{
|
||||
{`errors errors.txt { rotate_size 2 rotate_age 10 rotate_keep 3 }`, false, ErrorHandler{
|
||||
ErrorPages: map[int]string{},
|
||||
Log: &httpserver.Logger{Output: "errors.txt", Roller: &httpserver.LogRoller{
|
||||
Log: &httpserver.Logger{
|
||||
Output: "errors.txt", Roller: &httpserver.LogRoller{
|
||||
MaxSize: 2,
|
||||
MaxAge: 10,
|
||||
MaxBackups: 3,
|
||||
LocalTime: true,
|
||||
}}},
|
||||
},
|
||||
{`errors { log errors.txt {
|
||||
size 3
|
||||
age 11
|
||||
keep 5
|
||||
}
|
||||
},
|
||||
}},
|
||||
{`errors errors.txt {
|
||||
rotate_size 3
|
||||
rotate_age 11
|
||||
rotate_keep 5
|
||||
404 404.html
|
||||
503 503.html
|
||||
}`, false, ErrorHandler{
|
||||
|
@ -105,19 +107,25 @@ func TestErrorsParse(t *testing.T) {
|
|||
404: "404.html",
|
||||
503: "503.html",
|
||||
},
|
||||
Log: &httpserver.Logger{Output: "errors.txt", Roller: &httpserver.LogRoller{
|
||||
Log: &httpserver.Logger{
|
||||
Output: "errors.txt",
|
||||
Roller: &httpserver.LogRoller{
|
||||
MaxSize: 3,
|
||||
MaxAge: 11,
|
||||
MaxBackups: 5,
|
||||
LocalTime: true,
|
||||
},
|
||||
}}},
|
||||
{`errors { log errors.txt
|
||||
},
|
||||
}},
|
||||
{`errors errors.txt {
|
||||
* generic_error.html
|
||||
404 404.html
|
||||
503 503.html
|
||||
}`, false, ErrorHandler{
|
||||
Log: &httpserver.Logger{Output: "errors.txt"},
|
||||
Log: &httpserver.Logger{
|
||||
Output: "errors.txt",
|
||||
Roller: httpserver.DefaultLogRoller(),
|
||||
},
|
||||
GenericErrorPage: "generic_error.html",
|
||||
ErrorPages: map[int]string{
|
||||
404: "404.html",
|
||||
|
@ -158,7 +166,7 @@ func TestErrorsParse(t *testing.T) {
|
|||
}
|
||||
if !reflect.DeepEqual(actualErrorsRule, &test.expectedErrorHandler) {
|
||||
t.Errorf("Test %d expect %v, but got %v", i,
|
||||
actualErrorsRule, test.expectedErrorHandler)
|
||||
test.expectedErrorHandler, actualErrorsRule)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,6 @@ import (
|
|||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
"github.com/mholt/caddy"
|
||||
|
||||
"gopkg.in/natefinch/lumberjack.v2"
|
||||
)
|
||||
|
||||
|
@ -46,39 +44,56 @@ func (l LogRoller) GetLogWriter() io.Writer {
|
|||
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
|
||||
}
|
||||
|
||||
// ParseRoller parses roller contents out of c.
|
||||
func ParseRoller(c *caddy.Controller) (*LogRoller, error) {
|
||||
var size, age, keep int
|
||||
// This is kind of a hack to support nested blocks:
|
||||
// As we are already in a block: either log or errors,
|
||||
// c.nesting > 0 but, as soon as c meets a }, it thinks
|
||||
// the block is over and return false for c.NextBlock.
|
||||
for c.NextBlock() {
|
||||
what := c.Val()
|
||||
if !c.NextArg() {
|
||||
return nil, c.ArgErr()
|
||||
func ParseRoller(l *LogRoller, what string, where string) error {
|
||||
if l == nil {
|
||||
l = DefaultLogRoller()
|
||||
}
|
||||
value := c.Val()
|
||||
var value int
|
||||
var err error
|
||||
switch what {
|
||||
case "size":
|
||||
size, err = strconv.Atoi(value)
|
||||
case "age":
|
||||
age, err = strconv.Atoi(value)
|
||||
case "keep":
|
||||
keep, err = strconv.Atoi(value)
|
||||
}
|
||||
value, err = strconv.Atoi(where)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
switch what {
|
||||
case directiveRotateSize:
|
||||
l.MaxSize = value
|
||||
case directiveRotateAge:
|
||||
l.MaxAge = value
|
||||
case directiveRotateKeep:
|
||||
l.MaxBackups = value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DefaultLogRoller will roll logs by default.
|
||||
func DefaultLogRoller() *LogRoller {
|
||||
return &LogRoller{
|
||||
MaxSize: size,
|
||||
MaxAge: age,
|
||||
MaxBackups: keep,
|
||||
MaxSize: defaultRotateSize,
|
||||
MaxAge: defaultRotateAge,
|
||||
MaxBackups: defaultRotateKeep,
|
||||
LocalTime: true,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
// defaultRotateSize is 100 MB.
|
||||
defaultRotateSize = 100
|
||||
// defaultRotateAge is 14 days.
|
||||
defaultRotateAge = 14
|
||||
// defaultRotateKeep is 10 files.
|
||||
defaultRotateKeep = 10
|
||||
directiveRotateSize = "rotate_size"
|
||||
directiveRotateAge = "rotate_age"
|
||||
directiveRotateKeep = "rotate_keep"
|
||||
)
|
||||
|
||||
// lumberjacks maps log filenames to the logger
|
||||
// that is being used to keep them rolled/maintained.
|
||||
|
|
|
@ -32,25 +32,24 @@ func logParse(c *caddy.Controller) ([]*Rule, error) {
|
|||
args := c.RemainingArgs()
|
||||
|
||||
var logRoller *httpserver.LogRoller
|
||||
if c.NextBlock() {
|
||||
if c.Val() == "rotate" {
|
||||
if c.NextArg() {
|
||||
if c.Val() == "{" {
|
||||
logRoller = httpserver.DefaultLogRoller()
|
||||
|
||||
for c.NextBlock() {
|
||||
what := c.Val()
|
||||
if !c.NextArg() {
|
||||
return nil, c.ArgErr()
|
||||
}
|
||||
where := c.Val()
|
||||
|
||||
if httpserver.IsLogRollerSubdirective(what) {
|
||||
var err error
|
||||
logRoller, err = httpserver.ParseRoller(c)
|
||||
err = httpserver.ParseRoller(logRoller, what, where)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// This part doesn't allow having something after the rotate block
|
||||
if c.Next() {
|
||||
if c.Val() != "}" {
|
||||
return nil, c.ArgErr()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
// Nothing specified; use defaults
|
||||
rules = appendEntry(rules, "/", &Entry{
|
||||
|
|
|
@ -32,7 +32,10 @@ func TestSetup(t *testing.T) {
|
|||
t.Errorf("Expected / as the default PathScope")
|
||||
}
|
||||
|
||||
expectedLogger := &httpserver.Logger{Output: DefaultLogFilename}
|
||||
expectedLogger := &httpserver.Logger{
|
||||
Output: DefaultLogFilename,
|
||||
Roller: httpserver.DefaultLogRoller(),
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(myHandler.Rules[0].Entries[0].Log, expectedLogger) {
|
||||
t.Errorf("Expected %v as the default Log, got: %v", expectedLogger, myHandler.Rules[0].Entries[0].Log)
|
||||
|
@ -40,7 +43,6 @@ func TestSetup(t *testing.T) {
|
|||
if myHandler.Rules[0].Entries[0].Format != DefaultLogFormat {
|
||||
t.Errorf("Expected %s as the default Log Format", DefaultLogFormat)
|
||||
}
|
||||
|
||||
if !httpserver.SameNext(myHandler.Next, httpserver.EmptyNext) {
|
||||
t.Error("'Next' field of handler was not set properly")
|
||||
}
|
||||
|
@ -55,56 +57,80 @@ func TestLogParse(t *testing.T) {
|
|||
{`log`, false, []Rule{{
|
||||
PathScope: "/",
|
||||
Entries: []*Entry{{
|
||||
Log: &httpserver.Logger{Output: DefaultLogFilename},
|
||||
Log: &httpserver.Logger{
|
||||
Output: DefaultLogFilename,
|
||||
Roller: httpserver.DefaultLogRoller(),
|
||||
},
|
||||
Format: DefaultLogFormat,
|
||||
}},
|
||||
}}},
|
||||
{`log log.txt`, false, []Rule{{
|
||||
PathScope: "/",
|
||||
Entries: []*Entry{{
|
||||
Log: &httpserver.Logger{Output: "log.txt"},
|
||||
Log: &httpserver.Logger{
|
||||
Output: "log.txt",
|
||||
Roller: httpserver.DefaultLogRoller(),
|
||||
},
|
||||
Format: DefaultLogFormat,
|
||||
}},
|
||||
}}},
|
||||
{`log syslog://127.0.0.1:5000`, false, []Rule{{
|
||||
PathScope: "/",
|
||||
Entries: []*Entry{{
|
||||
Log: &httpserver.Logger{Output: "syslog://127.0.0.1:5000"},
|
||||
Log: &httpserver.Logger{
|
||||
Output: "syslog://127.0.0.1:5000",
|
||||
Roller: httpserver.DefaultLogRoller(),
|
||||
},
|
||||
Format: DefaultLogFormat,
|
||||
}},
|
||||
}}},
|
||||
{`log syslog+tcp://127.0.0.1:5000`, false, []Rule{{
|
||||
PathScope: "/",
|
||||
Entries: []*Entry{{
|
||||
Log: &httpserver.Logger{Output: "syslog+tcp://127.0.0.1:5000"},
|
||||
Log: &httpserver.Logger{
|
||||
Output: "syslog+tcp://127.0.0.1:5000",
|
||||
Roller: httpserver.DefaultLogRoller(),
|
||||
},
|
||||
Format: DefaultLogFormat,
|
||||
}},
|
||||
}}},
|
||||
{`log /api log.txt`, false, []Rule{{
|
||||
PathScope: "/api",
|
||||
Entries: []*Entry{{
|
||||
Log: &httpserver.Logger{Output: "log.txt"},
|
||||
Log: &httpserver.Logger{
|
||||
Output: "log.txt",
|
||||
Roller: httpserver.DefaultLogRoller(),
|
||||
},
|
||||
Format: DefaultLogFormat,
|
||||
}},
|
||||
}}},
|
||||
{`log /serve stdout`, false, []Rule{{
|
||||
PathScope: "/serve",
|
||||
Entries: []*Entry{{
|
||||
Log: &httpserver.Logger{Output: "stdout"},
|
||||
Log: &httpserver.Logger{
|
||||
Output: "stdout",
|
||||
Roller: httpserver.DefaultLogRoller(),
|
||||
},
|
||||
Format: DefaultLogFormat,
|
||||
}},
|
||||
}}},
|
||||
{`log /myapi log.txt {common}`, false, []Rule{{
|
||||
PathScope: "/myapi",
|
||||
Entries: []*Entry{{
|
||||
Log: &httpserver.Logger{Output: "log.txt"},
|
||||
Log: &httpserver.Logger{
|
||||
Output: "log.txt",
|
||||
Roller: httpserver.DefaultLogRoller(),
|
||||
},
|
||||
Format: CommonLogFormat,
|
||||
}},
|
||||
}}},
|
||||
{`log /test accesslog.txt {combined}`, false, []Rule{{
|
||||
PathScope: "/test",
|
||||
Entries: []*Entry{{
|
||||
Log: &httpserver.Logger{Output: "accesslog.txt"},
|
||||
Log: &httpserver.Logger{
|
||||
Output: "accesslog.txt",
|
||||
Roller: httpserver.DefaultLogRoller(),
|
||||
},
|
||||
Format: CombinedLogFormat,
|
||||
}},
|
||||
}}},
|
||||
|
@ -112,13 +138,19 @@ func TestLogParse(t *testing.T) {
|
|||
log /api2 accesslog.txt {combined}`, false, []Rule{{
|
||||
PathScope: "/api1",
|
||||
Entries: []*Entry{{
|
||||
Log: &httpserver.Logger{Output: "log.txt"},
|
||||
Log: &httpserver.Logger{
|
||||
Output: "log.txt",
|
||||
Roller: httpserver.DefaultLogRoller(),
|
||||
},
|
||||
Format: DefaultLogFormat,
|
||||
}},
|
||||
}, {
|
||||
PathScope: "/api2",
|
||||
Entries: []*Entry{{
|
||||
Log: &httpserver.Logger{Output: "accesslog.txt"},
|
||||
Log: &httpserver.Logger{
|
||||
Output: "accesslog.txt",
|
||||
Roller: httpserver.DefaultLogRoller(),
|
||||
},
|
||||
Format: CombinedLogFormat,
|
||||
}},
|
||||
}}},
|
||||
|
@ -126,20 +158,28 @@ func TestLogParse(t *testing.T) {
|
|||
log /api4 log.txt {when}`, false, []Rule{{
|
||||
PathScope: "/api3",
|
||||
Entries: []*Entry{{
|
||||
Log: &httpserver.Logger{Output: "stdout"},
|
||||
Log: &httpserver.Logger{
|
||||
Output: "stdout",
|
||||
Roller: httpserver.DefaultLogRoller(),
|
||||
},
|
||||
Format: "{host}",
|
||||
}},
|
||||
}, {
|
||||
PathScope: "/api4",
|
||||
Entries: []*Entry{{
|
||||
Log: &httpserver.Logger{Output: "log.txt"},
|
||||
Log: &httpserver.Logger{
|
||||
Output: "log.txt",
|
||||
Roller: httpserver.DefaultLogRoller(),
|
||||
},
|
||||
Format: "{when}",
|
||||
}},
|
||||
}}},
|
||||
{`log access.log { rotate { size 2 age 10 keep 3 } }`, false, []Rule{{
|
||||
{`log access.log { rotate_size 2 rotate_age 10 rotate_keep 3 }`, false, []Rule{{
|
||||
PathScope: "/",
|
||||
Entries: []*Entry{{
|
||||
Log: &httpserver.Logger{Output: "access.log", Roller: &httpserver.LogRoller{
|
||||
Log: &httpserver.Logger{
|
||||
Output: "access.log",
|
||||
Roller: &httpserver.LogRoller{
|
||||
MaxSize: 2,
|
||||
MaxAge: 10,
|
||||
MaxBackups: 3,
|
||||
|
@ -152,10 +192,16 @@ func TestLogParse(t *testing.T) {
|
|||
log / log.txt {when}`, false, []Rule{{
|
||||
PathScope: "/",
|
||||
Entries: []*Entry{{
|
||||
Log: &httpserver.Logger{Output: "stdout"},
|
||||
Log: &httpserver.Logger{
|
||||
Output: "stdout",
|
||||
Roller: httpserver.DefaultLogRoller(),
|
||||
},
|
||||
Format: "{host}",
|
||||
}, {
|
||||
Log: &httpserver.Logger{Output: "log.txt"},
|
||||
Log: &httpserver.Logger{
|
||||
Output: "log.txt",
|
||||
Roller: httpserver.DefaultLogRoller(),
|
||||
},
|
||||
Format: "{when}",
|
||||
}},
|
||||
}}},
|
||||
|
|
Loading…
Reference in a new issue