Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitf0cf0ad

Browse files
authored
feat: log additional known non-sensitive query param fields in the httpmw logger (#19532)
Blink helped here but it's suggestion was to have a set map of sensitivefields based on predefined constants in various files, such as the apitoken string names. For now we'll add additional query param logging for fields we know are safe/that we want to log, such as query pagination/limit fields and ID list counts which may help identify P99 DB query latencies.---------Signed-off-by: Callum Styan <callumstyan@gmail.com>
1 parentd274f83 commitf0cf0ad

File tree

2 files changed

+132
-0
lines changed

2 files changed

+132
-0
lines changed

‎coderd/httpmw/loggermw/logger.go‎

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ import (
44
"context"
55
"fmt"
66
"net/http"
7+
"net/url"
8+
"strconv"
9+
"strings"
710
"sync"
811
"time"
912

@@ -15,6 +18,59 @@ import (
1518
"github.com/coder/coder/v2/coderd/tracing"
1619
)
1720

21+
var (
22+
safeParams= []string{"page","limit","offset"}
23+
countParams= []string{"ids","template_ids"}
24+
)
25+
26+
funcsafeQueryParams(params url.Values) []slog.Field {
27+
iflen(params)==0 {
28+
returnnil
29+
}
30+
31+
fields:=make([]slog.Field,0,len(params))
32+
forkey,values:=rangeparams {
33+
// Check if this parameter should be included
34+
for_,pattern:=rangesafeParams {
35+
ifstrings.EqualFold(key,pattern) {
36+
// Prepend query parameters in the log line to ensure we don't have issues with collisions
37+
// in case any other internal logging fields already log fields with similar names
38+
fieldName:="query_"+key
39+
40+
// Log the actual values for non-sensitive parameters
41+
iflen(values)==1 {
42+
fields=append(fields,slog.F(fieldName,values[0]))
43+
continue
44+
}
45+
fields=append(fields,slog.F(fieldName,values))
46+
}
47+
}
48+
// Some query params we just want to log the count of the params length
49+
for_,pattern:=rangecountParams {
50+
if!strings.EqualFold(key,pattern) {
51+
continue
52+
}
53+
count:=0
54+
55+
// Prepend query parameters in the log line to ensure we don't have issues with collisions
56+
// in case any other internal logging fields already log fields with similar names
57+
fieldName:="query_"+key
58+
59+
// Count comma-separated values for CSV format
60+
for_,v:=rangevalues {
61+
ifstrings.Contains(v,",") {
62+
count+=len(strings.Split(v,","))
63+
continue
64+
}
65+
count++
66+
}
67+
// For logging we always want strings
68+
fields=append(fields,slog.F(fieldName+"_count",strconv.Itoa(count)))
69+
}
70+
}
71+
returnfields
72+
}
73+
1874
funcLogger(log slog.Logger)func(next http.Handler) http.Handler {
1975
returnfunc(next http.Handler) http.Handler {
2076
returnhttp.HandlerFunc(func(rw http.ResponseWriter,r*http.Request) {
@@ -39,6 +95,11 @@ func Logger(log slog.Logger) func(next http.Handler) http.Handler {
3995
slog.F("start",start),
4096
)
4197

98+
// Add safe query parameters to the log
99+
ifqueryFields:=safeQueryParams(r.URL.Query());len(queryFields)>0 {
100+
httplog=httplog.With(queryFields...)
101+
}
102+
42103
logContext:=NewRequestLogger(httplog,r.Method,start)
43104

44105
ctx:=WithRequestLogger(r.Context(),logContext)

‎coderd/httpmw/loggermw/logger_internal_test.go‎

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"net/http"
66
"net/http/httptest"
7+
"net/url"
78
"slices"
89
"strings"
910
"sync"
@@ -292,6 +293,76 @@ func TestRequestLogger_RouteParamsLogging(t *testing.T) {
292293
}
293294
}
294295

296+
funcTestSafeQueryParams(t*testing.T) {
297+
t.Parallel()
298+
299+
tests:= []struct {
300+
namestring
301+
params url.Values
302+
expectedmap[string]interface{}
303+
}{
304+
{
305+
name:"safe parameters",
306+
params: url.Values{
307+
"page": []string{"1"},
308+
"limit": []string{"10"},
309+
"filter": []string{"active"},
310+
"sort": []string{"name"},
311+
"offset": []string{"2"},
312+
"ids": []string{"some-id,another-id","second-param"},
313+
"template_ids": []string{"some-id,another-id","second-param"},
314+
},
315+
expected:map[string]interface{}{
316+
"query_page":"1",
317+
"query_limit":"10",
318+
"query_offset":"2",
319+
"query_ids_count":"3",
320+
"query_template_ids_count":"3",
321+
},
322+
},
323+
{
324+
name:"unknown/sensitive parameters",
325+
params: url.Values{
326+
"token": []string{"secret-token"},
327+
"api_key": []string{"secret-key"},
328+
"coder_signed_app_token": []string{"jwt-token"},
329+
"coder_application_connect_api_key": []string{"encrypted-key"},
330+
"client_secret": []string{"oauth-secret"},
331+
"code": []string{"auth-code"},
332+
},
333+
expected:map[string]interface{}{},
334+
},
335+
{
336+
name:"mixed parameters",
337+
params: url.Values{
338+
"page": []string{"1"},
339+
"token": []string{"secret"},
340+
"filter": []string{"active"},
341+
},
342+
expected:map[string]interface{}{
343+
"query_page":"1",
344+
},
345+
},
346+
}
347+
348+
for_,tt:=rangetests {
349+
tt:=tt
350+
t.Run(tt.name,func(t*testing.T) {
351+
t.Parallel()
352+
353+
fields:=safeQueryParams(tt.params)
354+
355+
// Convert fields to map for easier comparison
356+
result:=make(map[string]interface{})
357+
for_,field:=rangefields {
358+
result[field.Name]=field.Value
359+
}
360+
361+
require.Equal(t,tt.expected,result)
362+
})
363+
}
364+
}
365+
295366
typefakeSinkstruct {
296367
entries []slog.SinkEntry
297368
newEntrieschan slog.SinkEntry

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp