plugin/log: allow various combinations of classes of responses (#1664)
This allows to log responses of different classes, for example, denial and error.
This commit is contained in:
parent
a20b4fe2de
commit
ccfe691b95
4 changed files with 61 additions and 15 deletions
|
@ -54,7 +54,9 @@ func (l Logger) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
|
||||||
|
|
||||||
tpe, _ := response.Typify(rrw.Msg, time.Now().UTC())
|
tpe, _ := response.Typify(rrw.Msg, time.Now().UTC())
|
||||||
class := response.Classify(tpe)
|
class := response.Classify(tpe)
|
||||||
if rule.Class == response.All || rule.Class == class {
|
// If we don't set up a class in config, the default "all" will be added
|
||||||
|
// and we shouldn't have an empty rule.Class.
|
||||||
|
if rule.Class[response.All] || rule.Class[class] {
|
||||||
rep := replacer.New(r, rrw, CommonLogEmptyValue)
|
rep := replacer.New(r, rrw, CommonLogEmptyValue)
|
||||||
rule.Log.Println(rep.Replace(rule.Format))
|
rule.Log.Println(rep.Replace(rule.Format))
|
||||||
}
|
}
|
||||||
|
@ -71,7 +73,7 @@ func (l Logger) Name() string { return "log" }
|
||||||
// Rule configures the logging plugin.
|
// Rule configures the logging plugin.
|
||||||
type Rule struct {
|
type Rule struct {
|
||||||
NameScope string
|
NameScope string
|
||||||
Class response.Class
|
Class map[response.Class]bool
|
||||||
Format string
|
Format string
|
||||||
Log *log.Logger
|
Log *log.Logger
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ func TestLoggedStatus(t *testing.T) {
|
||||||
NameScope: ".",
|
NameScope: ".",
|
||||||
Format: DefaultLogFormat,
|
Format: DefaultLogFormat,
|
||||||
Log: log.New(&f, "", 0),
|
Log: log.New(&f, "", 0),
|
||||||
|
Class: map[response.Class]bool{response.All: true},
|
||||||
}
|
}
|
||||||
|
|
||||||
logger := Logger{
|
logger := Logger{
|
||||||
|
@ -50,7 +51,7 @@ func TestLoggedClassDenial(t *testing.T) {
|
||||||
NameScope: ".",
|
NameScope: ".",
|
||||||
Format: DefaultLogFormat,
|
Format: DefaultLogFormat,
|
||||||
Log: log.New(&f, "", 0),
|
Log: log.New(&f, "", 0),
|
||||||
Class: response.Denial,
|
Class: map[response.Class]bool{response.Denial: true},
|
||||||
}
|
}
|
||||||
|
|
||||||
logger := Logger{
|
logger := Logger{
|
||||||
|
@ -78,7 +79,7 @@ func TestLoggedClassError(t *testing.T) {
|
||||||
NameScope: ".",
|
NameScope: ".",
|
||||||
Format: DefaultLogFormat,
|
Format: DefaultLogFormat,
|
||||||
Log: log.New(&f, "", 0),
|
Log: log.New(&f, "", 0),
|
||||||
Class: response.Error,
|
Class: map[response.Class]bool{response.Error: true},
|
||||||
}
|
}
|
||||||
|
|
||||||
logger := Logger{
|
logger := Logger{
|
||||||
|
|
|
@ -52,11 +52,13 @@ func logParse(c *caddy.Controller) ([]Rule, error) {
|
||||||
rules = append(rules, Rule{
|
rules = append(rules, Rule{
|
||||||
NameScope: ".",
|
NameScope: ".",
|
||||||
Format: DefaultLogFormat,
|
Format: DefaultLogFormat,
|
||||||
|
Class: make(map[response.Class]bool),
|
||||||
})
|
})
|
||||||
} else if len(args) == 1 {
|
} else if len(args) == 1 {
|
||||||
rules = append(rules, Rule{
|
rules = append(rules, Rule{
|
||||||
NameScope: dns.Fqdn(args[0]),
|
NameScope: dns.Fqdn(args[0]),
|
||||||
Format: DefaultLogFormat,
|
Format: DefaultLogFormat,
|
||||||
|
Class: make(map[response.Class]bool),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// Name scope, and maybe a format specified
|
// Name scope, and maybe a format specified
|
||||||
|
@ -74,28 +76,33 @@ func logParse(c *caddy.Controller) ([]Rule, error) {
|
||||||
rules = append(rules, Rule{
|
rules = append(rules, Rule{
|
||||||
NameScope: dns.Fqdn(args[0]),
|
NameScope: dns.Fqdn(args[0]),
|
||||||
Format: format,
|
Format: format,
|
||||||
|
Class: make(map[response.Class]bool),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Class refinements in an extra block.
|
// Class refinements in an extra block.
|
||||||
for c.NextBlock() {
|
for c.NextBlock() {
|
||||||
switch c.Val() {
|
switch c.Val() {
|
||||||
// class followed by all, denial, error or success.
|
// class followed by combinations of all, denial, error and success.
|
||||||
case "class":
|
case "class":
|
||||||
classes := c.RemainingArgs()
|
classes := c.RemainingArgs()
|
||||||
if len(classes) == 0 {
|
if len(classes) == 0 {
|
||||||
return nil, c.ArgErr()
|
return nil, c.ArgErr()
|
||||||
}
|
}
|
||||||
cls, err := response.ClassFromString(classes[0])
|
for _, c := range classes {
|
||||||
if err != nil {
|
cls, err := response.ClassFromString(c)
|
||||||
return nil, err
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rules[len(rules)-1].Class[cls] = true
|
||||||
}
|
}
|
||||||
// update class and the last added Rule (bit icky)
|
|
||||||
rules[len(rules)-1].Class = cls
|
|
||||||
default:
|
default:
|
||||||
return nil, c.ArgErr()
|
return nil, c.ArgErr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(rules[len(rules)-1].Class) == 0 {
|
||||||
|
rules[len(rules)-1].Class[response.All] = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rules, nil
|
return rules, nil
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package log
|
package log
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/coredns/coredns/plugin/pkg/response"
|
"github.com/coredns/coredns/plugin/pkg/response"
|
||||||
|
@ -17,34 +18,42 @@ func TestLogParse(t *testing.T) {
|
||||||
{`log`, false, []Rule{{
|
{`log`, false, []Rule{{
|
||||||
NameScope: ".",
|
NameScope: ".",
|
||||||
Format: DefaultLogFormat,
|
Format: DefaultLogFormat,
|
||||||
|
Class: map[response.Class]bool{response.All: true},
|
||||||
}}},
|
}}},
|
||||||
{`log example.org`, false, []Rule{{
|
{`log example.org`, false, []Rule{{
|
||||||
NameScope: "example.org.",
|
NameScope: "example.org.",
|
||||||
Format: DefaultLogFormat,
|
Format: DefaultLogFormat,
|
||||||
|
Class: map[response.Class]bool{response.All: true},
|
||||||
}}},
|
}}},
|
||||||
{`log example.org. {common}`, false, []Rule{{
|
{`log example.org. {common}`, false, []Rule{{
|
||||||
NameScope: "example.org.",
|
NameScope: "example.org.",
|
||||||
Format: CommonLogFormat,
|
Format: CommonLogFormat,
|
||||||
|
Class: map[response.Class]bool{response.All: true},
|
||||||
}}},
|
}}},
|
||||||
{`log example.org {combined}`, false, []Rule{{
|
{`log example.org {combined}`, false, []Rule{{
|
||||||
NameScope: "example.org.",
|
NameScope: "example.org.",
|
||||||
Format: CombinedLogFormat,
|
Format: CombinedLogFormat,
|
||||||
|
Class: map[response.Class]bool{response.All: true},
|
||||||
}}},
|
}}},
|
||||||
{`log example.org.
|
{`log example.org.
|
||||||
log example.net {combined}`, false, []Rule{{
|
log example.net {combined}`, false, []Rule{{
|
||||||
NameScope: "example.org.",
|
NameScope: "example.org.",
|
||||||
Format: DefaultLogFormat,
|
Format: DefaultLogFormat,
|
||||||
|
Class: map[response.Class]bool{response.All: true},
|
||||||
}, {
|
}, {
|
||||||
NameScope: "example.net.",
|
NameScope: "example.net.",
|
||||||
Format: CombinedLogFormat,
|
Format: CombinedLogFormat,
|
||||||
|
Class: map[response.Class]bool{response.All: true},
|
||||||
}}},
|
}}},
|
||||||
{`log example.org {host}
|
{`log example.org {host}
|
||||||
log example.org {when}`, false, []Rule{{
|
log example.org {when}`, false, []Rule{{
|
||||||
NameScope: "example.org.",
|
NameScope: "example.org.",
|
||||||
Format: "{host}",
|
Format: "{host}",
|
||||||
|
Class: map[response.Class]bool{response.All: true},
|
||||||
}, {
|
}, {
|
||||||
NameScope: "example.org.",
|
NameScope: "example.org.",
|
||||||
Format: "{when}",
|
Format: "{when}",
|
||||||
|
Class: map[response.Class]bool{response.All: true},
|
||||||
}}},
|
}}},
|
||||||
|
|
||||||
{`log example.org {
|
{`log example.org {
|
||||||
|
@ -52,22 +61,49 @@ func TestLogParse(t *testing.T) {
|
||||||
}`, false, []Rule{{
|
}`, false, []Rule{{
|
||||||
NameScope: "example.org.",
|
NameScope: "example.org.",
|
||||||
Format: CommonLogFormat,
|
Format: CommonLogFormat,
|
||||||
Class: response.All,
|
Class: map[response.Class]bool{response.All: true},
|
||||||
}}},
|
}}},
|
||||||
{`log example.org {
|
{`log example.org {
|
||||||
class denial
|
class denial
|
||||||
}`, false, []Rule{{
|
}`, false, []Rule{{
|
||||||
NameScope: "example.org.",
|
NameScope: "example.org.",
|
||||||
Format: CommonLogFormat,
|
Format: CommonLogFormat,
|
||||||
Class: response.Denial,
|
Class: map[response.Class]bool{response.Denial: true},
|
||||||
}}},
|
}}},
|
||||||
{`log {
|
{`log {
|
||||||
class denial
|
class denial
|
||||||
}`, false, []Rule{{
|
}`, false, []Rule{{
|
||||||
NameScope: ".",
|
NameScope: ".",
|
||||||
Format: CommonLogFormat,
|
Format: CommonLogFormat,
|
||||||
Class: response.Denial,
|
Class: map[response.Class]bool{response.Denial: true},
|
||||||
}}},
|
}}},
|
||||||
|
{`log {
|
||||||
|
class denial error
|
||||||
|
}`, false, []Rule{{
|
||||||
|
NameScope: ".",
|
||||||
|
Format: CommonLogFormat,
|
||||||
|
Class: map[response.Class]bool{response.Denial: true, response.Error: true},
|
||||||
|
}}},
|
||||||
|
{`log {
|
||||||
|
class denial
|
||||||
|
class error
|
||||||
|
}`, false, []Rule{{
|
||||||
|
NameScope: ".",
|
||||||
|
Format: CommonLogFormat,
|
||||||
|
Class: map[response.Class]bool{response.Denial: true, response.Error: true},
|
||||||
|
}}},
|
||||||
|
{`log {
|
||||||
|
class abracadabra
|
||||||
|
}`, true, []Rule{
|
||||||
|
}},
|
||||||
|
{`log {
|
||||||
|
class
|
||||||
|
}`, true, []Rule{
|
||||||
|
}},
|
||||||
|
{`log {
|
||||||
|
unknown
|
||||||
|
}`, true, []Rule{
|
||||||
|
}},
|
||||||
}
|
}
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
c := caddy.NewTestController("dns", test.inputLogRules)
|
c := caddy.NewTestController("dns", test.inputLogRules)
|
||||||
|
@ -95,8 +131,8 @@ func TestLogParse(t *testing.T) {
|
||||||
i, j, test.inputLogRules, test.expectedLogRules[j].Format, actualLogRule.Format)
|
i, j, test.inputLogRules, test.expectedLogRules[j].Format, actualLogRule.Format)
|
||||||
}
|
}
|
||||||
|
|
||||||
if actualLogRule.Class != test.expectedLogRules[j].Class {
|
if !reflect.DeepEqual(actualLogRule.Class, test.expectedLogRules[j].Class) {
|
||||||
t.Errorf("Test %d expected %dth LogRule Class to be %s , but got %s",
|
t.Errorf("Test %d expected %dth LogRule Class to be %v , but got %v",
|
||||||
i, j, test.expectedLogRules[j].Class, actualLogRule.Class)
|
i, j, test.expectedLogRules[j].Class, actualLogRule.Class)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue