mirror of
https://github.com/coredns/coredns.git
synced 2025-11-01 18:53:43 -04:00
recover from panic log including stacktrace to help finding the origin (#5392)
This commit is contained in:
@@ -22,10 +22,13 @@ Extra knobs are available with an expanded syntax:
|
||||
|
||||
~~~
|
||||
errors {
|
||||
stacktrace
|
||||
consolidate DURATION REGEXP [LEVEL]
|
||||
}
|
||||
~~~
|
||||
|
||||
Option `stacktrace` will log a stacktrace during panic recovery.
|
||||
|
||||
Option `consolidate` allows collecting several error messages matching the regular expression **REGEXP** during **DURATION**. After the **DURATION** since receiving the first such message, the consolidated message will be printed to standard output with
|
||||
log level, which is configurable by optional option **LEVEL**. Supported options for **LEVEL** option are `warning`,`error`,`info` and `debug`.
|
||||
~~~
|
||||
|
||||
@@ -52,38 +52,41 @@ func errorsParse(c *caddy.Controller) (*errorHandler, error) {
|
||||
}
|
||||
|
||||
for c.NextBlock() {
|
||||
if err := parseBlock(c, handler); err != nil {
|
||||
return nil, err
|
||||
switch c.Val() {
|
||||
case "stacktrace":
|
||||
dnsserver.GetConfig(c).Stacktrace = true
|
||||
case "consolidate":
|
||||
pattern, err := parseConsolidate(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
handler.patterns = append(handler.patterns, pattern)
|
||||
default:
|
||||
return handler, c.SyntaxErr("Unknown field " + c.Val())
|
||||
}
|
||||
}
|
||||
}
|
||||
return handler, nil
|
||||
}
|
||||
|
||||
func parseBlock(c *caddy.Controller, h *errorHandler) error {
|
||||
if c.Val() != "consolidate" {
|
||||
return c.SyntaxErr("consolidate")
|
||||
}
|
||||
|
||||
func parseConsolidate(c *caddy.Controller) (*pattern, error) {
|
||||
args := c.RemainingArgs()
|
||||
if len(args) < 2 || len(args) > 3 {
|
||||
return c.ArgErr()
|
||||
return nil, c.ArgErr()
|
||||
}
|
||||
p, err := time.ParseDuration(args[0])
|
||||
if err != nil {
|
||||
return c.Err(err.Error())
|
||||
return nil, c.Err(err.Error())
|
||||
}
|
||||
re, err := regexp.Compile(args[1])
|
||||
if err != nil {
|
||||
return c.Err(err.Error())
|
||||
return nil, c.Err(err.Error())
|
||||
}
|
||||
lc, err := parseLogLevel(c, args)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
h.patterns = append(h.patterns, &pattern{period: p, pattern: re, logCallback: lc})
|
||||
|
||||
return nil
|
||||
return &pattern{period: p, pattern: re, logCallback: lc}, nil
|
||||
}
|
||||
|
||||
func parseLogLevel(c *caddy.Controller, args []string) (func(format string, v ...interface{}), error) {
|
||||
|
||||
@@ -7,55 +7,64 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/coredns/caddy"
|
||||
"github.com/coredns/coredns/core/dnsserver"
|
||||
clog "github.com/coredns/coredns/plugin/pkg/log"
|
||||
)
|
||||
|
||||
func TestErrorsParse(t *testing.T) {
|
||||
tests := []struct {
|
||||
inputErrorsRules string
|
||||
shouldErr bool
|
||||
optCount int
|
||||
inputErrorsRules string
|
||||
shouldErr bool
|
||||
optCount int
|
||||
stacktrace bool
|
||||
}{
|
||||
{`errors`, false, 0},
|
||||
{`errors stdout`, false, 0},
|
||||
{`errors errors.txt`, true, 0},
|
||||
{`errors visible`, true, 0},
|
||||
{`errors { log visible }`, true, 0},
|
||||
{`errors`, false, 0, false},
|
||||
{`errors stdout`, false, 0, false},
|
||||
{`errors errors.txt`, true, 0, false},
|
||||
{`errors visible`, true, 0, false},
|
||||
{`errors { log visible }`, true, 0, false},
|
||||
{`errors
|
||||
errors `, true, 0},
|
||||
{`errors a b`, true, 0},
|
||||
errors `, true, 0, false},
|
||||
{`errors a b`, true, 0, false},
|
||||
|
||||
{`errors {
|
||||
consolidate
|
||||
}`, true, 0},
|
||||
}`, true, 0, false},
|
||||
{`errors {
|
||||
consolidate 1m
|
||||
}`, true, 0},
|
||||
}`, true, 0, false},
|
||||
{`errors {
|
||||
consolidate 1m .* extra
|
||||
}`, true, 0},
|
||||
}`, true, 0, false},
|
||||
{`errors {
|
||||
consolidate abc .*
|
||||
}`, true, 0},
|
||||
}`, true, 0, false},
|
||||
{`errors {
|
||||
consolidate 1 .*
|
||||
}`, true, 0},
|
||||
}`, true, 0, false},
|
||||
{`errors {
|
||||
consolidate 1m ())
|
||||
}`, true, 0},
|
||||
}`, true, 0, false},
|
||||
{`errors {
|
||||
stacktrace
|
||||
}`, false, 0, true},
|
||||
{`errors {
|
||||
stacktrace
|
||||
consolidate 1m ^exact$
|
||||
}`, false, 1, true},
|
||||
{`errors {
|
||||
consolidate 1m ^exact$
|
||||
}`, false, 1},
|
||||
}`, false, 1, false},
|
||||
{`errors {
|
||||
consolidate 1m error
|
||||
}`, false, 1},
|
||||
}`, false, 1, false},
|
||||
{`errors {
|
||||
consolidate 1m "format error"
|
||||
}`, false, 1},
|
||||
}`, false, 1, false},
|
||||
{`errors {
|
||||
consolidate 1m error1
|
||||
consolidate 5s error2
|
||||
}`, false, 2},
|
||||
}`, false, 2, false},
|
||||
}
|
||||
for i, test := range tests {
|
||||
c := caddy.NewTestController("dns", test.inputErrorsRules)
|
||||
@@ -69,6 +78,10 @@ func TestErrorsParse(t *testing.T) {
|
||||
t.Errorf("Test %d: pattern count mismatch, expected %d, got %d",
|
||||
i, test.optCount, len(h.patterns))
|
||||
}
|
||||
if dnsserver.GetConfig(c).Stacktrace != test.stacktrace {
|
||||
t.Errorf("Test %d: stacktrace, expected %t, got %t",
|
||||
i, test.stacktrace, dnsserver.GetConfig(c).Stacktrace)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user