aboutsummaryrefslogtreecommitdiff
path: root/plugin/errors
diff options
context:
space:
mode:
authorGravatar Radim Hatlapatka <hata.radim@gmail.com> 2022-05-24 14:36:36 +0200
committerGravatar GitHub <noreply@github.com> 2022-05-24 14:36:36 +0200
commit91bcbc2e3ada7c034e0cca022a717871684dd5ca (patch)
treedca40addd6e613bba2cef090455fa08ca1330e4b /plugin/errors
parentb7e4f05f08e761fc71d7e7d2c85afd3ee6ef3542 (diff)
downloadcoredns-91bcbc2e3ada7c034e0cca022a717871684dd5ca.tar.gz
coredns-91bcbc2e3ada7c034e0cca022a717871684dd5ca.tar.zst
coredns-91bcbc2e3ada7c034e0cca022a717871684dd5ca.zip
recover from panic log including stacktrace to help finding the origin (#5392)
Diffstat (limited to 'plugin/errors')
-rw-r--r--plugin/errors/README.md3
-rw-r--r--plugin/errors/setup.go31
-rw-r--r--plugin/errors/setup_test.go53
3 files changed, 53 insertions, 34 deletions
diff --git a/plugin/errors/README.md b/plugin/errors/README.md
index 0cb0b375d..27ba1058a 100644
--- a/plugin/errors/README.md
+++ b/plugin/errors/README.md
@@ -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`.
~~~
diff --git a/plugin/errors/setup.go b/plugin/errors/setup.go
index 67a9fe653..c040e102f 100644
--- a/plugin/errors/setup.go
+++ b/plugin/errors/setup.go
@@ -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) {
diff --git a/plugin/errors/setup_test.go b/plugin/errors/setup_test.go
index 72fdbcd0a..6af6aea57 100644
--- a/plugin/errors/setup_test.go
+++ b/plugin/errors/setup_test.go
@@ -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},
+ }`, false, 1, true},
+ {`errors {
+ consolidate 1m ^exact$
+ }`, 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)
+ }
}
}