summaryrefslogtreecommitdiff
path: root/modules/logging
diff options
context:
space:
mode:
authorKévin Dunglas <dunglas@gmail.com>2021-11-23 18:00:20 +0100
committerGitHub <noreply@github.com>2021-11-23 10:00:20 -0700
commit789efa5deef53071b57479d37e4022bf372c4eef (patch)
tree6fd09f809735e2d47dfc361a2617008950630508 /modules/logging
parent8887adb027982e844965b4707b8595cee5845d54 (diff)
logging: add a regexp filter (#4426)
Diffstat (limited to 'modules/logging')
-rw-r--r--modules/logging/filters.go57
-rw-r--r--modules/logging/filters_test.go11
2 files changed, 68 insertions, 0 deletions
diff --git a/modules/logging/filters.go b/modules/logging/filters.go
index cf3b5cc..ded08ac 100644
--- a/modules/logging/filters.go
+++ b/modules/logging/filters.go
@@ -19,6 +19,7 @@ import (
"net"
"net/http"
"net/url"
+ "regexp"
"strconv"
"github.com/caddyserver/caddy/v2"
@@ -32,6 +33,7 @@ func init() {
caddy.RegisterModule(IPMaskFilter{})
caddy.RegisterModule(QueryFilter{})
caddy.RegisterModule(CookieFilter{})
+ caddy.RegisterModule(RegexpFilter{})
}
// LogFieldFilter can filter (or manipulate)
@@ -426,6 +428,58 @@ OUTER:
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
var (
_ LogFieldFilter = (*DeleteFilter)(nil)
@@ -433,14 +487,17 @@ var (
_ LogFieldFilter = (*IPMaskFilter)(nil)
_ LogFieldFilter = (*QueryFilter)(nil)
_ LogFieldFilter = (*CookieFilter)(nil)
+ _ LogFieldFilter = (*RegexpFilter)(nil)
_ caddyfile.Unmarshaler = (*DeleteFilter)(nil)
_ caddyfile.Unmarshaler = (*ReplaceFilter)(nil)
_ caddyfile.Unmarshaler = (*IPMaskFilter)(nil)
_ caddyfile.Unmarshaler = (*QueryFilter)(nil)
_ caddyfile.Unmarshaler = (*CookieFilter)(nil)
+ _ caddyfile.Unmarshaler = (*RegexpFilter)(nil)
_ caddy.Provisioner = (*IPMaskFilter)(nil)
+ _ caddy.Provisioner = (*RegexpFilter)(nil)
_ caddy.Validator = (*QueryFilter)(nil)
)
diff --git a/modules/logging/filters_test.go b/modules/logging/filters_test.go
index 6871bea..99289c3 100644
--- a/modules/logging/filters_test.go
+++ b/modules/logging/filters_test.go
@@ -3,6 +3,7 @@ package logging
import (
"testing"
+ "github.com/caddyserver/caddy/v2"
"go.uber.org/zap/zapcore"
)
@@ -67,3 +68,13 @@ func TestValidateCookieFilter(t *testing.T) {
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)
+ }
+}