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

Commitf8d3fbf

Browse files
authored
feat: extend request logs with auth & DB info (#17497)
Closes#16903
1 parent991d38c commitf8d3fbf

File tree

19 files changed

+334
-34
lines changed

19 files changed

+334
-34
lines changed

‎Makefile

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,7 @@ GEN_FILES := \
582582
coderd/database/pubsub/psmock/psmock.go\
583583
agent/agentcontainers/acmock/acmock.go\
584584
agent/agentcontainers/dcspec/dcspec_gen.go\
585-
coderd/httpmw/loggermock/loggermock.go
585+
coderd/httpmw/loggermw/loggermock/loggermock.go
586586

587587
# all gen targets should be added here and to gen/mark-fresh
588588
gen: gen/db gen/golden-files$(GEN_FILES)
@@ -631,7 +631,7 @@ gen/mark-fresh:
631631
coderd/database/pubsub/psmock/psmock.go\
632632
agent/agentcontainers/acmock/acmock.go\
633633
agent/agentcontainers/dcspec/dcspec_gen.go\
634-
coderd/httpmw/loggermock/loggermock.go\
634+
coderd/httpmw/loggermw/loggermock/loggermock.go\
635635
"
636636

637637
for file in $$files; do
@@ -671,8 +671,8 @@ agent/agentcontainers/acmock/acmock.go: agent/agentcontainers/containers.go
671671
go generate ./agent/agentcontainers/acmock/
672672
touch"$@"
673673

674-
coderd/httpmw/loggermock/loggermock.go: coderd/httpmw/logger.go
675-
go generate ./coderd/httpmw/loggermock/
674+
coderd/httpmw/loggermw/loggermock/loggermock.go: coderd/httpmw/loggermw/logger.go
675+
go generate ./coderd/httpmw/loggermw/loggermock/
676676
touch"$@"
677677

678678
agent/agentcontainers/dcspec/dcspec_gen.go:\

‎coderd/coderd.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ import (
6464
"github.com/coder/coder/v2/coderd/healthcheck/derphealth"
6565
"github.com/coder/coder/v2/coderd/httpapi"
6666
"github.com/coder/coder/v2/coderd/httpmw"
67+
"github.com/coder/coder/v2/coderd/httpmw/loggermw"
6768
"github.com/coder/coder/v2/coderd/metricscache"
6869
"github.com/coder/coder/v2/coderd/notifications"
6970
"github.com/coder/coder/v2/coderd/portsharing"
@@ -801,7 +802,7 @@ func New(options *Options) *API {
801802
tracing.Middleware(api.TracerProvider),
802803
httpmw.AttachRequestID,
803804
httpmw.ExtractRealIP(api.RealIPConfig),
804-
httpmw.Logger(api.Logger),
805+
loggermw.Logger(api.Logger),
805806
singleSlashMW,
806807
rolestore.CustomRoleMW,
807808
prometheusMW,

‎coderd/database/dbauthz/dbauthz.go

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/coder/coder/v2/coderd/database"
2525
"github.com/coder/coder/v2/coderd/database/dbtime"
2626
"github.com/coder/coder/v2/coderd/httpapi/httpapiconstraints"
27+
"github.com/coder/coder/v2/coderd/httpmw/loggermw"
2728
"github.com/coder/coder/v2/coderd/rbac"
2829
"github.com/coder/coder/v2/coderd/util/slice"
2930
"github.com/coder/coder/v2/provisionersdk"
@@ -162,6 +163,7 @@ func ActorFromContext(ctx context.Context) (rbac.Subject, bool) {
162163

163164
var (
164165
subjectProvisionerd= rbac.Subject{
166+
Type:rbac.SubjectTypeProvisionerd,
165167
FriendlyName:"Provisioner Daemon",
166168
ID:uuid.Nil.String(),
167169
Roles:rbac.Roles([]rbac.Role{
@@ -196,6 +198,7 @@ var (
196198
}.WithCachedASTValue()
197199

198200
subjectAutostart= rbac.Subject{
201+
Type:rbac.SubjectTypeAutostart,
199202
FriendlyName:"Autostart",
200203
ID:uuid.Nil.String(),
201204
Roles:rbac.Roles([]rbac.Role{
@@ -219,6 +222,7 @@ var (
219222

220223
// See unhanger package.
221224
subjectHangDetector= rbac.Subject{
225+
Type:rbac.SubjectTypeHangDetector,
222226
FriendlyName:"Hang Detector",
223227
ID:uuid.Nil.String(),
224228
Roles:rbac.Roles([]rbac.Role{
@@ -239,6 +243,7 @@ var (
239243

240244
// See cryptokeys package.
241245
subjectCryptoKeyRotator= rbac.Subject{
246+
Type:rbac.SubjectTypeCryptoKeyRotator,
242247
FriendlyName:"Crypto Key Rotator",
243248
ID:uuid.Nil.String(),
244249
Roles:rbac.Roles([]rbac.Role{
@@ -257,6 +262,7 @@ var (
257262

258263
// See cryptokeys package.
259264
subjectCryptoKeyReader= rbac.Subject{
265+
Type:rbac.SubjectTypeCryptoKeyReader,
260266
FriendlyName:"Crypto Key Reader",
261267
ID:uuid.Nil.String(),
262268
Roles:rbac.Roles([]rbac.Role{
@@ -274,6 +280,7 @@ var (
274280
}.WithCachedASTValue()
275281

276282
subjectNotifier= rbac.Subject{
283+
Type:rbac.SubjectTypeNotifier,
277284
FriendlyName:"Notifier",
278285
ID:uuid.Nil.String(),
279286
Roles:rbac.Roles([]rbac.Role{
@@ -294,6 +301,7 @@ var (
294301
}.WithCachedASTValue()
295302

296303
subjectResourceMonitor= rbac.Subject{
304+
Type:rbac.SubjectTypeResourceMonitor,
297305
FriendlyName:"Resource Monitor",
298306
ID:uuid.Nil.String(),
299307
Roles:rbac.Roles([]rbac.Role{
@@ -312,6 +320,7 @@ var (
312320
}.WithCachedASTValue()
313321

314322
subjectSystemRestricted= rbac.Subject{
323+
Type:rbac.SubjectTypeSystemRestricted,
315324
FriendlyName:"System",
316325
ID:uuid.Nil.String(),
317326
Roles:rbac.Roles([]rbac.Role{
@@ -346,6 +355,7 @@ var (
346355
}.WithCachedASTValue()
347356

348357
subjectSystemReadProvisionerDaemons= rbac.Subject{
358+
Type:rbac.SubjectTypeSystemReadProvisionerDaemons,
349359
FriendlyName:"Provisioner Daemons Reader",
350360
ID:uuid.Nil.String(),
351361
Roles:rbac.Roles([]rbac.Role{
@@ -366,53 +376,53 @@ var (
366376
// AsProvisionerd returns a context with an actor that has permissions required
367377
// for provisionerd to function.
368378
funcAsProvisionerd(ctx context.Context) context.Context {
369-
returncontext.WithValue(ctx,authContextKey{},subjectProvisionerd)
379+
returnAs(ctx,subjectProvisionerd)
370380
}
371381

372382
// AsAutostart returns a context with an actor that has permissions required
373383
// for autostart to function.
374384
funcAsAutostart(ctx context.Context) context.Context {
375-
returncontext.WithValue(ctx,authContextKey{},subjectAutostart)
385+
returnAs(ctx,subjectAutostart)
376386
}
377387

378388
// AsHangDetector returns a context with an actor that has permissions required
379389
// for unhanger.Detector to function.
380390
funcAsHangDetector(ctx context.Context) context.Context {
381-
returncontext.WithValue(ctx,authContextKey{},subjectHangDetector)
391+
returnAs(ctx,subjectHangDetector)
382392
}
383393

384394
// AsKeyRotator returns a context with an actor that has permissions required for rotating crypto keys.
385395
funcAsKeyRotator(ctx context.Context) context.Context {
386-
returncontext.WithValue(ctx,authContextKey{},subjectCryptoKeyRotator)
396+
returnAs(ctx,subjectCryptoKeyRotator)
387397
}
388398

389399
// AsKeyReader returns a context with an actor that has permissions required for reading crypto keys.
390400
funcAsKeyReader(ctx context.Context) context.Context {
391-
returncontext.WithValue(ctx,authContextKey{},subjectCryptoKeyReader)
401+
returnAs(ctx,subjectCryptoKeyReader)
392402
}
393403

394404
// AsNotifier returns a context with an actor that has permissions required for
395405
// creating/reading/updating/deleting notifications.
396406
funcAsNotifier(ctx context.Context) context.Context {
397-
returncontext.WithValue(ctx,authContextKey{},subjectNotifier)
407+
returnAs(ctx,subjectNotifier)
398408
}
399409

400410
// AsResourceMonitor returns a context with an actor that has permissions required for
401411
// updating resource monitors.
402412
funcAsResourceMonitor(ctx context.Context) context.Context {
403-
returncontext.WithValue(ctx,authContextKey{},subjectResourceMonitor)
413+
returnAs(ctx,subjectResourceMonitor)
404414
}
405415

406416
// AsSystemRestricted returns a context with an actor that has permissions
407417
// required for various system operations (login, logout, metrics cache).
408418
funcAsSystemRestricted(ctx context.Context) context.Context {
409-
returncontext.WithValue(ctx,authContextKey{},subjectSystemRestricted)
419+
returnAs(ctx,subjectSystemRestricted)
410420
}
411421

412422
// AsSystemReadProvisionerDaemons returns a context with an actor that has permissions
413423
// to read provisioner daemons.
414424
funcAsSystemReadProvisionerDaemons(ctx context.Context) context.Context {
415-
returncontext.WithValue(ctx,authContextKey{},subjectSystemReadProvisionerDaemons)
425+
returnAs(ctx,subjectSystemReadProvisionerDaemons)
416426
}
417427

418428
varAsRemoveActor= rbac.Subject{
@@ -430,6 +440,9 @@ func As(ctx context.Context, actor rbac.Subject) context.Context {
430440
// should be removed from the context.
431441
returncontext.WithValue(ctx,authContextKey{},nil)
432442
}
443+
ifrlogger:=loggermw.RequestLoggerFromContext(ctx);rlogger!=nil {
444+
rlogger.WithAuthContext(actor)
445+
}
433446
returncontext.WithValue(ctx,authContextKey{},actor)
434447
}
435448

‎coderd/database/queries.sql.go

Lines changed: 4 additions & 2 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/queries/users.sql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,10 +271,10 @@ WHERE
271271
-- This function returns roles for authorization purposes. Implied member roles
272272
-- are included.
273273
SELECT
274-
-- usernameis returned just to help for logging purposes
274+
-- usernameand email are returned just to help for logging purposes
275275
-- status is used to enforce 'suspended' users, as all roles are ignored
276276
--when suspended.
277-
id, username, status,
277+
id, username, status, email,
278278
-- All user roles, including their org roles.
279279
array_cat(
280280
-- All users are members

‎coderd/httpmw/apikey.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,9 @@ func UserRBACSubject(ctx context.Context, db database.Store, userID uuid.UUID, s
465465
}
466466

467467
actor:= rbac.Subject{
468+
Type:rbac.SubjectTypeUser,
468469
FriendlyName:roles.Username,
470+
Email:roles.Email,
469471
ID:userID.String(),
470472
Roles:rbacRoles,
471473
Groups:roles.Groups,

‎coderd/httpmw/logger.gorenamed to‎coderd/httpmw/loggermw/logger.go

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1-
packagehttpmw
1+
packageloggermw
22

33
import (
44
"context"
55
"fmt"
66
"net/http"
7+
"sync"
78
"time"
89

10+
"github.com/go-chi/chi/v5"
11+
912
"cdr.dev/slog"
1013
"github.com/coder/coder/v2/coderd/httpapi"
14+
"github.com/coder/coder/v2/coderd/rbac"
1115
"github.com/coder/coder/v2/coderd/tracing"
1216
)
1317

@@ -62,13 +66,17 @@ func Logger(log slog.Logger) func(next http.Handler) http.Handler {
6266
typeRequestLoggerinterface {
6367
WithFields(fields...slog.Field)
6468
WriteLog(ctx context.Context,statusint)
69+
WithAuthContext(actor rbac.Subject)
6570
}
6671

6772
typeSlogRequestLoggerstruct {
6873
log slog.Logger
6974
writtenbool
7075
messagestring
7176
start time.Time
77+
// Protects actors map for concurrent writes.
78+
mu sync.RWMutex
79+
actorsmap[rbac.SubjectType]rbac.Subject
7280
}
7381

7482
var_RequestLogger=&SlogRequestLogger{}
@@ -79,25 +87,93 @@ func NewRequestLogger(log slog.Logger, message string, start time.Time) RequestL
7987
written:false,
8088
message:message,
8189
start:start,
90+
actors:make(map[rbac.SubjectType]rbac.Subject),
8291
}
8392
}
8493

8594
func (c*SlogRequestLogger)WithFields(fields...slog.Field) {
8695
c.log=c.log.With(fields...)
8796
}
8897

98+
func (c*SlogRequestLogger)WithAuthContext(actor rbac.Subject) {
99+
c.mu.Lock()
100+
deferc.mu.Unlock()
101+
c.actors[actor.Type]=actor
102+
}
103+
104+
func (c*SlogRequestLogger)addAuthContextFields() {
105+
c.mu.RLock()
106+
deferc.mu.RUnlock()
107+
108+
usr,ok:=c.actors[rbac.SubjectTypeUser]
109+
ifok {
110+
c.log=c.log.With(
111+
slog.F("requestor_id",usr.ID),
112+
slog.F("requestor_name",usr.FriendlyName),
113+
slog.F("requestor_email",usr.Email),
114+
)
115+
}else {
116+
// If there is no user, we log the requestor name for the first
117+
// actor in a defined order.
118+
for_,v:=rangeactorLogOrder {
119+
subj,ok:=c.actors[v]
120+
if!ok {
121+
continue
122+
}
123+
c.log=c.log.With(
124+
slog.F("requestor_name",subj.FriendlyName),
125+
)
126+
break
127+
}
128+
}
129+
}
130+
131+
varactorLogOrder= []rbac.SubjectType{
132+
rbac.SubjectTypeAutostart,
133+
rbac.SubjectTypeCryptoKeyReader,
134+
rbac.SubjectTypeCryptoKeyRotator,
135+
rbac.SubjectTypeHangDetector,
136+
rbac.SubjectTypeNotifier,
137+
rbac.SubjectTypePrebuildsOrchestrator,
138+
rbac.SubjectTypeProvisionerd,
139+
rbac.SubjectTypeResourceMonitor,
140+
rbac.SubjectTypeSystemReadProvisionerDaemons,
141+
rbac.SubjectTypeSystemRestricted,
142+
}
143+
89144
func (c*SlogRequestLogger)WriteLog(ctx context.Context,statusint) {
90145
ifc.written {
91146
return
92147
}
93148
c.written=true
94149
end:=time.Now()
95150

151+
// Right before we write the log, we try to find the user in the actors
152+
// and add the fields to the log.
153+
c.addAuthContextFields()
154+
96155
logger:=c.log.With(
97156
slog.F("took",end.Sub(c.start)),
98157
slog.F("status_code",status),
99158
slog.F("latency_ms",float64(end.Sub(c.start)/time.Millisecond)),
100159
)
160+
161+
// If the request is routed, add the route parameters to the log.
162+
ifchiCtx:=chi.RouteContext(ctx);chiCtx!=nil {
163+
urlParams:=chiCtx.URLParams
164+
routeParamsFields:=make([]slog.Field,0,len(urlParams.Keys))
165+
166+
fork,v:=rangeurlParams.Keys {
167+
ifurlParams.Values[k]!="" {
168+
routeParamsFields=append(routeParamsFields,slog.F("params_"+v,urlParams.Values[k]))
169+
}
170+
}
171+
172+
iflen(routeParamsFields)>0 {
173+
logger=logger.With(routeParamsFields...)
174+
}
175+
}
176+
101177
// We already capture most of this information in the span (minus
102178
// the response body which we don't want to capture anyways).
103179
tracing.RunWithoutSpan(ctx,func(ctx context.Context) {

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp