mirror of https://github.com/caddyserver/caddy.git
logging: add a regexp filter (#4426)
This commit is contained in:
parent
8887adb027
commit
789efa5dee
|
@ -19,6 +19,7 @@ log {
|
||||||
ipv4 24
|
ipv4 24
|
||||||
ipv6 32
|
ipv6 32
|
||||||
}
|
}
|
||||||
|
request>headers>Regexp regexp secret REDACTED
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,6 +56,11 @@ log {
|
||||||
],
|
],
|
||||||
"filter": "cookie"
|
"filter": "cookie"
|
||||||
},
|
},
|
||||||
|
"request\u003eheaders\u003eRegexp": {
|
||||||
|
"filter": "regexp",
|
||||||
|
"regexp": "secret",
|
||||||
|
"value": "REDACTED"
|
||||||
|
},
|
||||||
"request\u003eheaders\u003eServer": {
|
"request\u003eheaders\u003eServer": {
|
||||||
"filter": "delete"
|
"filter": "delete"
|
||||||
},
|
},
|
||||||
|
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/caddyserver/caddy/v2"
|
"github.com/caddyserver/caddy/v2"
|
||||||
|
@ -32,6 +33,7 @@ func init() {
|
||||||
caddy.RegisterModule(IPMaskFilter{})
|
caddy.RegisterModule(IPMaskFilter{})
|
||||||
caddy.RegisterModule(QueryFilter{})
|
caddy.RegisterModule(QueryFilter{})
|
||||||
caddy.RegisterModule(CookieFilter{})
|
caddy.RegisterModule(CookieFilter{})
|
||||||
|
caddy.RegisterModule(RegexpFilter{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// LogFieldFilter can filter (or manipulate)
|
// LogFieldFilter can filter (or manipulate)
|
||||||
|
@ -426,6 +428,58 @@ OUTER:
|
||||||
return in
|
return in
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RegexpFilter is a Caddy log field filter that
|
||||||
|
// replaces the field matching the provided regexp with the indicated string.
|
||||||
|
type RegexpFilter struct {
|
||||||
|
// The regular expression pattern defining what to replace.
|
||||||
|
RawRegexp string `json:"regexp,omitempty"`
|
||||||
|
|
||||||
|
// The value to use as replacement
|
||||||
|
Value string `json:"value,omitempty"`
|
||||||
|
|
||||||
|
regexp *regexp.Regexp
|
||||||
|
}
|
||||||
|
|
||||||
|
// CaddyModule returns the Caddy module information.
|
||||||
|
func (RegexpFilter) CaddyModule() caddy.ModuleInfo {
|
||||||
|
return caddy.ModuleInfo{
|
||||||
|
ID: "caddy.logging.encoders.filter.regexp",
|
||||||
|
New: func() caddy.Module { return new(RegexpFilter) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalCaddyfile sets up the module from Caddyfile tokens.
|
||||||
|
func (f *RegexpFilter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
|
||||||
|
for d.Next() {
|
||||||
|
if d.NextArg() {
|
||||||
|
f.RawRegexp = d.Val()
|
||||||
|
}
|
||||||
|
if d.NextArg() {
|
||||||
|
f.Value = d.Val()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provision compiles m's regexp.
|
||||||
|
func (m *RegexpFilter) Provision(ctx caddy.Context) error {
|
||||||
|
r, err := regexp.Compile(m.RawRegexp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
m.regexp = r
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter filters the input field with the replacement value if it matches the regexp.
|
||||||
|
func (f *RegexpFilter) Filter(in zapcore.Field) zapcore.Field {
|
||||||
|
in.String = f.regexp.ReplaceAllString(in.String, f.Value)
|
||||||
|
|
||||||
|
return in
|
||||||
|
}
|
||||||
|
|
||||||
// Interface guards
|
// Interface guards
|
||||||
var (
|
var (
|
||||||
_ LogFieldFilter = (*DeleteFilter)(nil)
|
_ LogFieldFilter = (*DeleteFilter)(nil)
|
||||||
|
@ -433,14 +487,17 @@ var (
|
||||||
_ LogFieldFilter = (*IPMaskFilter)(nil)
|
_ LogFieldFilter = (*IPMaskFilter)(nil)
|
||||||
_ LogFieldFilter = (*QueryFilter)(nil)
|
_ LogFieldFilter = (*QueryFilter)(nil)
|
||||||
_ LogFieldFilter = (*CookieFilter)(nil)
|
_ LogFieldFilter = (*CookieFilter)(nil)
|
||||||
|
_ LogFieldFilter = (*RegexpFilter)(nil)
|
||||||
|
|
||||||
_ caddyfile.Unmarshaler = (*DeleteFilter)(nil)
|
_ caddyfile.Unmarshaler = (*DeleteFilter)(nil)
|
||||||
_ caddyfile.Unmarshaler = (*ReplaceFilter)(nil)
|
_ caddyfile.Unmarshaler = (*ReplaceFilter)(nil)
|
||||||
_ caddyfile.Unmarshaler = (*IPMaskFilter)(nil)
|
_ caddyfile.Unmarshaler = (*IPMaskFilter)(nil)
|
||||||
_ caddyfile.Unmarshaler = (*QueryFilter)(nil)
|
_ caddyfile.Unmarshaler = (*QueryFilter)(nil)
|
||||||
_ caddyfile.Unmarshaler = (*CookieFilter)(nil)
|
_ caddyfile.Unmarshaler = (*CookieFilter)(nil)
|
||||||
|
_ caddyfile.Unmarshaler = (*RegexpFilter)(nil)
|
||||||
|
|
||||||
_ caddy.Provisioner = (*IPMaskFilter)(nil)
|
_ caddy.Provisioner = (*IPMaskFilter)(nil)
|
||||||
|
_ caddy.Provisioner = (*RegexpFilter)(nil)
|
||||||
|
|
||||||
_ caddy.Validator = (*QueryFilter)(nil)
|
_ caddy.Validator = (*QueryFilter)(nil)
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,6 +3,7 @@ package logging
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/caddyserver/caddy/v2"
|
||||||
"go.uber.org/zap/zapcore"
|
"go.uber.org/zap/zapcore"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -67,3 +68,13 @@ func TestValidateCookieFilter(t *testing.T) {
|
||||||
t.Fatalf("unknown action type must be invalid")
|
t.Fatalf("unknown action type must be invalid")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRegexpFilter(t *testing.T) {
|
||||||
|
f := RegexpFilter{RawRegexp: `secret`, Value: "REDACTED"}
|
||||||
|
f.Provision(caddy.Context{})
|
||||||
|
|
||||||
|
out := f.Filter(zapcore.Field{String: "foo-secret-bar"})
|
||||||
|
if out.String != "foo-REDACTED-bar" {
|
||||||
|
t.Fatalf("field has not been filtered: %s", out.String)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue