8
8
9
9
"cdr.dev/slog"
10
10
"github.com/coder/coder/v2/coderd/httpapi"
11
+ "github.com/coder/coder/v2/coderd/rbac"
11
12
"github.com/coder/coder/v2/coderd/tracing"
12
13
)
13
14
@@ -62,48 +63,60 @@ func Logger(log slog.Logger) func(next http.Handler) http.Handler {
62
63
type RequestLogger interface {
63
64
WithFields (fields ... slog.Field )
64
65
WriteLog (ctx context.Context , status int )
65
- WithAuthContext (id string , name string , email string )
66
+ WithAuthContext (id string , name string , email string , subjectType rbac. SubjectType )
66
67
}
67
68
68
69
type SlogRequestLogger struct {
69
- log slog.Logger
70
- written bool
71
- message string
72
- authCtxPresent bool
73
- start time.Time
70
+ log slog.Logger
71
+ written bool
72
+ message string
73
+ start time.Time
74
+ authCtx map [rbac.SubjectType ]authContext
75
+ }
76
+
77
+ type authContext struct {
78
+ id string
79
+ name string
80
+ email string
81
+ subjectType rbac.SubjectType
74
82
}
75
83
76
84
var _ RequestLogger = & SlogRequestLogger {}
77
85
78
86
func NewRequestLogger (log slog.Logger , message string , start time.Time ) RequestLogger {
79
87
return & SlogRequestLogger {
80
- log : log ,
81
- written : false ,
82
- message : message ,
83
- start : start ,
84
- authCtxPresent : false ,
88
+ log : log ,
89
+ written : false ,
90
+ message : message ,
91
+ start : start ,
92
+ authCtx : make ( map [rbac. SubjectType ] authContext ) ,
85
93
}
86
94
}
87
95
88
96
func (c * SlogRequestLogger ) WithFields (fields ... slog.Field ) {
89
97
c .log = c .log .With (fields ... )
90
98
}
91
99
92
- func (c * SlogRequestLogger ) WithAuthContext (id string , name string , email string ) {
93
- // If the email is empty, we don't want to log the requestor context,
94
- // because it's an elevated privilege.
95
- if email == "" || id == "" {
96
- return
97
- }
98
- if c .authCtxPresent {
99
- return
100
+ func (c * SlogRequestLogger ) WithAuthContext (id string , name string , email string , subjectType rbac.SubjectType ) {
101
+ c .authCtx [subjectType ] = authContext {id , name , email , subjectType }
102
+ }
103
+
104
+ func (c * SlogRequestLogger ) addAuthContextFields () {
105
+ usr , ok := c .authCtx [rbac .SubjectTypeUser ]
106
+ if ok {
107
+ c .log = c .log .With (
108
+ slog .F ("requestor_id" , usr .id ),
109
+ slog .F ("requestor_name" , usr .name ),
110
+ slog .F ("requestor_email" , usr .email ),
111
+ )
112
+ } else if len (c .authCtx ) > 0 {
113
+ for _ , v := range c .authCtx {
114
+ c .log = c .log .With (
115
+ slog .F ("requestor_name" , v .name ),
116
+ )
117
+ break
118
+ }
100
119
}
101
- c .authCtxPresent = true
102
- c .log = c .log .With (
103
- slog .F ("requestor_id" , id ),
104
- slog .F ("requestor_name" , name ),
105
- slog .F ("requestor_email" , email ),
106
- )
107
120
}
108
121
109
122
func (c * SlogRequestLogger ) WriteLog (ctx context.Context , status int ) {
@@ -113,11 +126,16 @@ func (c *SlogRequestLogger) WriteLog(ctx context.Context, status int) {
113
126
c .written = true
114
127
end := time .Now ()
115
128
129
+ // Right before we write the log, we try to find the user in the authCtx
130
+ // and add the fields to the log.
131
+ c .addAuthContextFields ()
132
+
116
133
logger := c .log .With (
117
134
slog .F ("took" , end .Sub (c .start )),
118
135
slog .F ("status_code" , status ),
119
136
slog .F ("latency_ms" , float64 (end .Sub (c .start )/ time .Millisecond )),
120
137
)
138
+
121
139
// We already capture most of this information in the span (minus
122
140
// the response body which we don't want to capture anyways).
123
141
tracing .RunWithoutSpan (ctx , func (ctx context.Context ) {
0 commit comments