Skip to content

Commit

Permalink
feat(access-logging): Improve access logging module (#91)
Browse files Browse the repository at this point in the history
Co-authored-by: ldebruijn <[email protected]>
  • Loading branch information
ldebruijn and ldebruijn authored Jun 4, 2024
1 parent 76a9bb2 commit 4b02211
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 28 deletions.
46 changes: 28 additions & 18 deletions internal/business/rules/accesslogging/accesslogging.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,56 +4,66 @@ import (
"github.com/ldebruijn/graphql-protect/internal/business/gql"
"log/slog"
"net/http"
"slices"
)

type Config struct {
Enable bool `config:"default:true" yaml:"enabled"`
Enabled bool `config:"default:true" yaml:"enabled"`
IncludedHeaders []string `yaml:"included_headers"`
IncludeOperationName bool `config:"default:true" yaml:"include_operation_name"`
IncludeVariables bool `config:"default:true" yaml:"include_variables"`
IncludePayload bool `config:"default:false" yaml:"include_payload"`
}

type AccessLogging struct {
log *slog.Logger
cfg Config
log *slog.Logger
enabled bool
includeHeaders map[string]bool
includeOperationName bool
includeVariables bool
includePayload bool
}

func NewAccessLogging(cfg Config, log *slog.Logger) *AccessLogging {
headers := map[string]bool{}
for _, header := range cfg.IncludedHeaders {
headers[header] = true
}

return &AccessLogging{
log: log.WithGroup("access-logging"),
cfg: cfg,
log: log.WithGroup("access-logging"),
enabled: cfg.Enabled,
includeHeaders: headers,
includeOperationName: cfg.IncludeOperationName,
includeVariables: cfg.IncludeVariables,
includePayload: cfg.IncludePayload,
}
}

func (a *AccessLogging) Log(payloads []gql.RequestData, headers http.Header) {
if !a.cfg.Enable {
if !a.enabled {
return
}

toLog := map[string]interface{}{}

logHeaders := map[string]interface{}{}
for key := range a.includeHeaders {
logHeaders[key] = headers.Values(key)
}

for _, req := range payloads {
if a.cfg.IncludeOperationName {
if a.includeOperationName {
toLog["operationName"] = req.OperationName
}
if a.cfg.IncludeVariables {
if a.includeVariables {
toLog["variables"] = req.Variables
}
if a.cfg.IncludePayload {
if a.includePayload {
toLog["payload"] = req.Query
}

logHeaders := map[string]interface{}{}
for name, values := range headers {
if slices.Contains(a.cfg.IncludedHeaders, name) {
logHeaders[name] = values
}
}

toLog["headers"] = logHeaders

a.log.Info("access-logging", "payload", toLog)
a.log.Info("record", "payload", toLog)
}
}
19 changes: 9 additions & 10 deletions internal/business/rules/accesslogging/accesslogging_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ func TestAccessLogging_Log(t *testing.T) {
name: "logs expected fields when enabled",
args: args{
cfg: Config{
Enable: true,
IncludedHeaders: []string{"Authorization"},
Enabled: true,
IncludedHeaders: []string{"Authorization", "not-case-sensitive"},
IncludeOperationName: true,
IncludeVariables: true,
IncludePayload: true,
Expand All @@ -60,8 +60,9 @@ func TestAccessLogging_Log(t *testing.T) {
},
},
headers: map[string][]string{
"Authorization": {"bearer hello"},
"Content-Type": {"application/json"},
"Authorization": {"bearer hello"},
"Content-Type": {"application/json"},
"Not-Case-Sensitive": {"yes"},
},
count: 1,
},
Expand All @@ -76,7 +77,8 @@ func TestAccessLogging_Log(t *testing.T) {
"foo": "bar",
}, val["variables"])
assert.Equal(t, map[string]interface{}{
"Authorization": []string{"bearer hello"},
"Authorization": []string{"bearer hello"},
"not-case-sensitive": []string{"yes"},
}, val["headers"])

return true
Expand All @@ -89,7 +91,7 @@ func TestAccessLogging_Log(t *testing.T) {
name: "logs nothing when disabled",
args: args{
cfg: Config{
Enable: false,
Enabled: false,
IncludedHeaders: []string{"Authorization"},
IncludeOperationName: true,
IncludeVariables: true,
Expand Down Expand Up @@ -121,10 +123,7 @@ func TestAccessLogging_Log(t *testing.T) {
handler := &testLogHandler{assert: tt.want}
log := slog.New(handler)

a := &AccessLogging{
log: log,
cfg: tt.args.cfg,
}
a := NewAccessLogging(tt.args.cfg, log)
a.Log(tt.args.payloads, tt.args.headers)

assert.Equal(t, tt.args.count, a.log.Handler().(*testLogHandler).count)
Expand Down

0 comments on commit 4b02211

Please sign in to comment.