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

Commit3e61440

Browse files
committed
feat: extend request logs with auth & DB info (#17304)
Closes#16903
1 parent08abd9d commit3e61440

File tree

18 files changed

+330
-33
lines changed

18 files changed

+330
-33
lines changed

‎Makefile

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@ GEN_FILES := \
564564
examples/examples.gen.json\
565565
$(TAILNETTEST_MOCKS)\
566566
coderd/database/pubsub/psmock/psmock.go\
567-
coderd/httpmw/loggermock/loggermock.go
567+
coderd/httpmw/loggermw/loggermock/loggermock.go
568568

569569
# all gen targets should be added here and to gen/mark-fresh
570570
gen: gen/db$(GEN_FILES)
@@ -598,7 +598,7 @@ gen/mark-fresh:
598598
examples/examples.gen.json\
599599
$(TAILNETTEST_MOCKS)\
600600
coderd/database/pubsub/psmock/psmock.go\
601-
coderd/httpmw/loggermock/loggermock.go\
601+
coderd/httpmw/loggermw/loggermock/loggermock.go\
602602
"
603603

604604
for file in $$files; do
@@ -630,9 +630,8 @@ coderd/database/dbmock/dbmock.go: coderd/database/db.go coderd/database/querier.
630630
coderd/database/pubsub/psmock/psmock.go: coderd/database/pubsub/pubsub.go
631631
go generate ./coderd/database/pubsub/psmock
632632

633-
coderd/httpmw/loggermock/loggermock.go: coderd/httpmw/logger.go
634-
go generate ./coderd/httpmw/loggermock/
635-
touch"$@"
633+
coderd/httpmw/loggermw/loggermock/loggermock.go: coderd/httpmw/loggermw/logger.go
634+
go generate ./coderd/httpmw/loggermw/loggermock/
636635

637636
$(TAILNETTEST_MOCKS): tailnet/coordinator.go tailnet/service.go
638637
go generate ./tailnet/tailnettest/

‎coderd/coderd.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ import (
6363
"github.com/coder/coder/v2/coderd/healthcheck/derphealth"
6464
"github.com/coder/coder/v2/coderd/httpapi"
6565
"github.com/coder/coder/v2/coderd/httpmw"
66+
"github.com/coder/coder/v2/coderd/httpmw/loggermw"
6667
"github.com/coder/coder/v2/coderd/metricscache"
6768
"github.com/coder/coder/v2/coderd/notifications"
6869
"github.com/coder/coder/v2/coderd/portsharing"
@@ -787,7 +788,7 @@ func New(options *Options) *API {
787788
tracing.Middleware(api.TracerProvider),
788789
httpmw.AttachRequestID,
789790
httpmw.ExtractRealIP(api.RealIPConfig),
790-
httpmw.Logger(api.Logger),
791+
loggermw.Logger(api.Logger),
791792
rolestore.CustomRoleMW,
792793
prometheusMW,
793794
// Build-Version is helpful for debugging.

‎coderd/database/dbauthz/dbauthz.go

Lines changed: 20 additions & 8 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{
@@ -193,6 +195,7 @@ var (
193195
}.WithCachedASTValue()
194196

195197
subjectAutostart= rbac.Subject{
198+
Type:rbac.SubjectTypeAutostart,
196199
FriendlyName:"Autostart",
197200
ID:uuid.Nil.String(),
198201
Roles:rbac.Roles([]rbac.Role{
@@ -216,6 +219,7 @@ var (
216219

217220
// See unhanger package.
218221
subjectHangDetector= rbac.Subject{
222+
Type:rbac.SubjectTypeHangDetector,
219223
FriendlyName:"Hang Detector",
220224
ID:uuid.Nil.String(),
221225
Roles:rbac.Roles([]rbac.Role{
@@ -236,6 +240,7 @@ var (
236240

237241
// See cryptokeys package.
238242
subjectCryptoKeyRotator= rbac.Subject{
243+
Type:rbac.SubjectTypeCryptoKeyRotator,
239244
FriendlyName:"Crypto Key Rotator",
240245
ID:uuid.Nil.String(),
241246
Roles:rbac.Roles([]rbac.Role{
@@ -254,6 +259,7 @@ var (
254259

255260
// See cryptokeys package.
256261
subjectCryptoKeyReader= rbac.Subject{
262+
Type:rbac.SubjectTypeCryptoKeyReader,
257263
FriendlyName:"Crypto Key Reader",
258264
ID:uuid.Nil.String(),
259265
Roles:rbac.Roles([]rbac.Role{
@@ -271,6 +277,7 @@ var (
271277
}.WithCachedASTValue()
272278

273279
subjectNotifier= rbac.Subject{
280+
Type:rbac.SubjectTypeNotifier,
274281
FriendlyName:"Notifier",
275282
ID:uuid.Nil.String(),
276283
Roles:rbac.Roles([]rbac.Role{
@@ -288,6 +295,7 @@ var (
288295
}.WithCachedASTValue()
289296

290297
subjectSystemRestricted= rbac.Subject{
298+
Type:rbac.SubjectTypeSystemRestricted,
291299
FriendlyName:"System",
292300
ID:uuid.Nil.String(),
293301
Roles:rbac.Roles([]rbac.Role{
@@ -323,6 +331,7 @@ var (
323331
}.WithCachedASTValue()
324332

325333
subjectSystemReadProvisionerDaemons= rbac.Subject{
334+
Type:rbac.SubjectTypeSystemReadProvisionerDaemons,
326335
FriendlyName:"Provisioner Daemons Reader",
327336
ID:uuid.Nil.String(),
328337
Roles:rbac.Roles([]rbac.Role{
@@ -343,47 +352,47 @@ var (
343352
// AsProvisionerd returns a context with an actor that has permissions required
344353
// for provisionerd to function.
345354
funcAsProvisionerd(ctx context.Context) context.Context {
346-
returncontext.WithValue(ctx,authContextKey{},subjectProvisionerd)
355+
returnAs(ctx,subjectProvisionerd)
347356
}
348357

349358
// AsAutostart returns a context with an actor that has permissions required
350359
// for autostart to function.
351360
funcAsAutostart(ctx context.Context) context.Context {
352-
returncontext.WithValue(ctx,authContextKey{},subjectAutostart)
361+
returnAs(ctx,subjectAutostart)
353362
}
354363

355364
// AsHangDetector returns a context with an actor that has permissions required
356365
// for unhanger.Detector to function.
357366
funcAsHangDetector(ctx context.Context) context.Context {
358-
returncontext.WithValue(ctx,authContextKey{},subjectHangDetector)
367+
returnAs(ctx,subjectHangDetector)
359368
}
360369

361370
// AsKeyRotator returns a context with an actor that has permissions required for rotating crypto keys.
362371
funcAsKeyRotator(ctx context.Context) context.Context {
363-
returncontext.WithValue(ctx,authContextKey{},subjectCryptoKeyRotator)
372+
returnAs(ctx,subjectCryptoKeyRotator)
364373
}
365374

366375
// AsKeyReader returns a context with an actor that has permissions required for reading crypto keys.
367376
funcAsKeyReader(ctx context.Context) context.Context {
368-
returncontext.WithValue(ctx,authContextKey{},subjectCryptoKeyReader)
377+
returnAs(ctx,subjectCryptoKeyReader)
369378
}
370379

371380
// AsNotifier returns a context with an actor that has permissions required for
372381
// creating/reading/updating/deleting notifications.
373382
funcAsNotifier(ctx context.Context) context.Context {
374-
returncontext.WithValue(ctx,authContextKey{},subjectNotifier)
383+
returnAs(ctx,subjectNotifier)
375384
}
376385

377386
// AsSystemRestricted returns a context with an actor that has permissions
378387
// required for various system operations (login, logout, metrics cache).
379388
funcAsSystemRestricted(ctx context.Context) context.Context {
380-
returncontext.WithValue(ctx,authContextKey{},subjectSystemRestricted)
389+
returnAs(ctx,subjectSystemRestricted)
381390
}
382391

383392
// AsSystemReadProvisionerDaemons returns a context with an actor that has permissions
384393
// to read provisioner daemons.
385394
funcAsSystemReadProvisionerDaemons(ctx context.Context) context.Context {
386-
returncontext.WithValue(ctx,authContextKey{},subjectSystemReadProvisionerDaemons)
395+
returnAs(ctx,subjectSystemReadProvisionerDaemons)
387396
}
388397

389398
varAsRemoveActor= rbac.Subject{
@@ -401,6 +410,9 @@ func As(ctx context.Context, actor rbac.Subject) context.Context {
401410
// should be removed from the context.
402411
returncontext.WithValue(ctx,authContextKey{},nil)
403412
}
413+
ifrlogger:=loggermw.RequestLoggerFromContext(ctx);rlogger!=nil {
414+
rlogger.WithAuthContext(actor)
415+
}
404416
returncontext.WithValue(ctx,authContextKey{},actor)
405417
}
406418

‎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
@@ -244,10 +244,10 @@ WHERE
244244
-- This function returns roles for authorization purposes. Implied member roles
245245
-- are included.
246246
SELECT
247-
-- usernameis returned just to help for logging purposes
247+
-- usernameand email are returned just to help for logging purposes
248248
-- status is used to enforce 'suspended' users, as all roles are ignored
249249
--when suspended.
250-
id, username, status,
250+
id, username, status, email,
251251
-- All user roles, including their org roles.
252252
array_cat(
253253
-- 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