mirror of
https://github.com/yusing/godoxy.git
synced 2026-04-21 00:11:42 +02:00
refactor: move accesslog to logging/accesslog
This commit is contained in:
204
internal/logging/accesslog/fields.go
Normal file
204
internal/logging/accesslog/fields.go
Normal file
@@ -0,0 +1,204 @@
|
||||
package accesslog
|
||||
|
||||
import (
|
||||
"iter"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
type (
|
||||
FieldConfig struct {
|
||||
Default FieldMode `json:"default" validate:"oneof=keep drop redact"`
|
||||
Config map[string]FieldMode `json:"config" validate:"dive,oneof=keep drop redact"`
|
||||
}
|
||||
FieldMode string
|
||||
)
|
||||
|
||||
const (
|
||||
FieldModeKeep FieldMode = "keep"
|
||||
FieldModeDrop FieldMode = "drop"
|
||||
FieldModeRedact FieldMode = "redact"
|
||||
|
||||
RedactedValue = "REDACTED"
|
||||
)
|
||||
|
||||
type mapStringStringIter interface {
|
||||
Iter(yield func(k string, v []string) bool)
|
||||
MarshalZerologObject(e *zerolog.Event)
|
||||
}
|
||||
|
||||
type mapStringStringSlice struct {
|
||||
m map[string][]string
|
||||
}
|
||||
|
||||
func (m mapStringStringSlice) Iter(yield func(k string, v []string) bool) {
|
||||
for k, v := range m.m {
|
||||
if !yield(k, v) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m mapStringStringSlice) MarshalZerologObject(e *zerolog.Event) {
|
||||
for k, v := range m.m {
|
||||
e.Strs(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
type mapStringStringRedacted struct {
|
||||
m map[string][]string
|
||||
}
|
||||
|
||||
func (m mapStringStringRedacted) Iter(yield func(k string, v []string) bool) {
|
||||
for k := range m.m {
|
||||
if !yield(k, []string{RedactedValue}) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m mapStringStringRedacted) MarshalZerologObject(e *zerolog.Event) {
|
||||
for k, v := range m.Iter {
|
||||
e.Strs(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
type mapStringStringSliceWithConfig struct {
|
||||
m map[string][]string
|
||||
cfg *FieldConfig
|
||||
}
|
||||
|
||||
func (m mapStringStringSliceWithConfig) Iter(yield func(k string, v []string) bool) {
|
||||
var mode FieldMode
|
||||
var ok bool
|
||||
for k, v := range m.m {
|
||||
if mode, ok = m.cfg.Config[k]; !ok {
|
||||
mode = m.cfg.Default
|
||||
}
|
||||
switch mode {
|
||||
case FieldModeKeep:
|
||||
if !yield(k, v) {
|
||||
return
|
||||
}
|
||||
case FieldModeRedact:
|
||||
if !yield(k, []string{RedactedValue}) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m mapStringStringSliceWithConfig) MarshalZerologObject(e *zerolog.Event) {
|
||||
for k, v := range m.Iter {
|
||||
e.Strs(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
type mapStringStringDrop struct{}
|
||||
|
||||
func (m mapStringStringDrop) Iter(yield func(k string, v []string) bool) {}
|
||||
func (m mapStringStringDrop) MarshalZerologObject(e *zerolog.Event) {}
|
||||
|
||||
var mapStringStringDropIter mapStringStringIter = mapStringStringDrop{}
|
||||
|
||||
func mapIter[Map http.Header | url.Values](cfg *FieldConfig, m Map) mapStringStringIter {
|
||||
if len(cfg.Config) == 0 {
|
||||
switch cfg.Default {
|
||||
case FieldModeKeep:
|
||||
return mapStringStringSlice{m: m}
|
||||
case FieldModeDrop:
|
||||
return mapStringStringDropIter
|
||||
case FieldModeRedact:
|
||||
return mapStringStringRedacted{m: m}
|
||||
}
|
||||
}
|
||||
return mapStringStringSliceWithConfig{m: m, cfg: cfg}
|
||||
}
|
||||
|
||||
type slice[V any] struct {
|
||||
s []V
|
||||
getKey func(V) string
|
||||
getVal func(V) string
|
||||
cfg *FieldConfig
|
||||
}
|
||||
|
||||
type sliceIter interface {
|
||||
Iter(yield func(k string, v string) bool)
|
||||
MarshalZerologObject(e *zerolog.Event)
|
||||
}
|
||||
|
||||
func (s *slice[V]) Iter(yield func(k string, v string) bool) {
|
||||
for _, v := range s.s {
|
||||
k := s.getKey(v)
|
||||
var mode FieldMode
|
||||
var ok bool
|
||||
if mode, ok = s.cfg.Config[k]; !ok {
|
||||
mode = s.cfg.Default
|
||||
}
|
||||
switch mode {
|
||||
case FieldModeKeep:
|
||||
if !yield(k, s.getVal(v)) {
|
||||
return
|
||||
}
|
||||
case FieldModeRedact:
|
||||
if !yield(k, RedactedValue) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type sliceDrop struct{}
|
||||
|
||||
func (s sliceDrop) Iter(yield func(k string, v string) bool) {}
|
||||
func (s sliceDrop) MarshalZerologObject(e *zerolog.Event) {}
|
||||
|
||||
var sliceDropIter sliceIter = sliceDrop{}
|
||||
|
||||
func (s *slice[V]) MarshalZerologObject(e *zerolog.Event) {
|
||||
for k, v := range s.Iter {
|
||||
e.Str(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
func iterSlice[V any](cfg *FieldConfig, s []V, getKey func(V) string, getVal func(V) string) sliceIter {
|
||||
if len(s) == 0 ||
|
||||
len(cfg.Config) == 0 && cfg.Default == FieldModeDrop {
|
||||
return sliceDropIter
|
||||
}
|
||||
return &slice[V]{s: s, getKey: getKey, getVal: getVal, cfg: cfg}
|
||||
}
|
||||
|
||||
func (cfg *FieldConfig) IterHeaders(headers http.Header) iter.Seq2[string, []string] {
|
||||
return mapIter(cfg, headers).Iter
|
||||
}
|
||||
|
||||
func (cfg *FieldConfig) ZerologHeaders(headers http.Header) zerolog.LogObjectMarshaler {
|
||||
return mapIter(cfg, headers)
|
||||
}
|
||||
|
||||
func (cfg *FieldConfig) IterQuery(q url.Values) iter.Seq2[string, []string] {
|
||||
return mapIter(cfg, q).Iter
|
||||
}
|
||||
|
||||
func (cfg *FieldConfig) ZerologQuery(q url.Values) zerolog.LogObjectMarshaler {
|
||||
return mapIter(cfg, q)
|
||||
}
|
||||
|
||||
func cookieGetKey(c *http.Cookie) string {
|
||||
return c.Name
|
||||
}
|
||||
|
||||
func cookieGetValue(c *http.Cookie) string {
|
||||
return c.Value
|
||||
}
|
||||
|
||||
func (cfg *FieldConfig) IterCookies(cookies []*http.Cookie) iter.Seq2[string, string] {
|
||||
return iterSlice(cfg, cookies, cookieGetKey, cookieGetValue).Iter
|
||||
}
|
||||
|
||||
func (cfg *FieldConfig) ZerologCookies(cookies []*http.Cookie) zerolog.LogObjectMarshaler {
|
||||
return iterSlice(cfg, cookies, cookieGetKey, cookieGetValue)
|
||||
}
|
||||
Reference in New Issue
Block a user