@@ -36,8 +36,8 @@ type handlerData struct {
36
36
log * logger.Logger // Logger for logging messages
37
37
}
38
38
39
- func onError (w http.ResponseWriter , log * slog.Logger , errMsg string , details any , jobID string , statusCode int ) {
40
- prometheus .WebhookErrorsTotal .Inc ()
39
+ func onError (repoName string , w http.ResponseWriter , log * slog.Logger , errMsg string , details any , jobID string , statusCode int ) {
40
+ prometheus .WebhookErrorsTotal .WithLabelValues ( repoName ). Inc ()
41
41
log .Error (errMsg )
42
42
JSONError (w ,
43
43
errMsg ,
@@ -82,7 +82,7 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
82
82
jobLog .Debug ("authenticating to private repository" )
83
83
84
84
if appConfig .GitAccessToken == "" {
85
- onError (w , jobLog , "missing access token for private repository" , "" , jobID , http .StatusInternalServerError )
85
+ onError (repoName , w , jobLog , "missing access token for private repository" , "" , jobID , http .StatusInternalServerError )
86
86
87
87
return
88
88
}
@@ -95,21 +95,21 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
95
95
96
96
// Validate payload.FullName to prevent directory traversal
97
97
if strings .Contains (payload .FullName , ".." ) {
98
- onError (w , jobLog .With (slog .String ("repository" , payload .FullName )), "invalid repository name" , "" , jobID , http .StatusBadRequest )
98
+ onError (repoName , w , jobLog .With (slog .String ("repository" , payload .FullName )), "invalid repository name" , "" , jobID , http .StatusBadRequest )
99
99
100
100
return
101
101
}
102
102
103
103
internalRepoPath , err := utils .VerifyAndSanitizePath (filepath .Join (dataMountPoint .Destination , repoName ), dataMountPoint .Destination ) // Path inside the container
104
104
if err != nil {
105
- onError (w , jobLog .With (logger .ErrAttr (err )), "failed to verify and sanitize internal filesystem path" , err .Error (), jobID , http .StatusBadRequest )
105
+ onError (repoName , w , jobLog .With (logger .ErrAttr (err )), "failed to verify and sanitize internal filesystem path" , err .Error (), jobID , http .StatusBadRequest )
106
106
107
107
return
108
108
}
109
109
110
110
externalRepoPath , err := utils .VerifyAndSanitizePath (filepath .Join (dataMountPoint .Destination , repoName ), dataMountPoint .Destination ) // Path on the host
111
111
if err != nil {
112
- onError (w , jobLog .With (logger .ErrAttr (err )), "failed to verify and sanitize external filesystem path" , err .Error (), jobID , http .StatusBadRequest )
112
+ onError (repoName , w , jobLog .With (logger .ErrAttr (err )), "failed to verify and sanitize external filesystem path" , err .Error (), jobID , http .StatusBadRequest )
113
113
114
114
return
115
115
}
@@ -123,12 +123,12 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
123
123
124
124
_ , err = git .UpdateRepository (internalRepoPath , payload .Ref , appConfig .SkipTLSVerification , appConfig .HttpProxy )
125
125
if err != nil {
126
- onError (w , jobLog .With (logger .ErrAttr (err )), "failed to checkout repository" , err .Error (), jobID , http .StatusInternalServerError )
126
+ onError (repoName , w , jobLog .With (logger .ErrAttr (err )), "failed to checkout repository" , err .Error (), jobID , http .StatusInternalServerError )
127
127
128
128
return
129
129
}
130
130
} else {
131
- onError (w , jobLog .With (logger .ErrAttr (err )), "failed to clone repository" , err .Error (), jobID , http .StatusInternalServerError )
131
+ onError (repoName , w , jobLog .With (logger .ErrAttr (err )), "failed to clone repository" , err .Error (), jobID , http .StatusInternalServerError )
132
132
133
133
return
134
134
}
@@ -144,7 +144,7 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
144
144
if errors .Is (err , config .ErrDeprecatedConfig ) {
145
145
jobLog .Warn (err .Error ())
146
146
} else {
147
- onError (w , jobLog .With (logger .ErrAttr (err )), "failed to get deploy configuration" , err .Error (), jobID , http .StatusInternalServerError )
147
+ onError (repoName , w , jobLog .With (logger .ErrAttr (err )), "failed to get deploy configuration" , err .Error (), jobID , http .StatusInternalServerError )
148
148
149
149
return
150
150
}
@@ -160,14 +160,14 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
160
160
161
161
internalRepoPath , err = utils .VerifyAndSanitizePath (filepath .Join (dataMountPoint .Destination , repoName ), dataMountPoint .Destination ) // Path inside the container
162
162
if err != nil {
163
- onError (w , subJobLog .With (logger .ErrAttr (err )), "invalid repository name" , err .Error (), jobID , http .StatusBadRequest )
163
+ onError (repoName , w , subJobLog .With (logger .ErrAttr (err )), "invalid repository name" , err .Error (), jobID , http .StatusBadRequest )
164
164
165
165
return
166
166
}
167
167
168
168
externalRepoPath , err = utils .VerifyAndSanitizePath (filepath .Join (dataMountPoint .Source , repoName ), dataMountPoint .Source ) // Path on the host
169
169
if err != nil {
170
- onError (w , subJobLog .With (logger .ErrAttr (err )), "invalid repository name" , err .Error (), jobID , http .StatusBadRequest )
170
+ onError (repoName , w , subJobLog .With (logger .ErrAttr (err )), "invalid repository name" , err .Error (), jobID , http .StatusBadRequest )
171
171
172
172
return
173
173
}
@@ -190,7 +190,7 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
190
190
// Try to clone the remote repository
191
191
_ , err = git .CloneRepository (internalRepoPath , cloneUrl , deployConfig .Reference , appConfig .SkipTLSVerification , appConfig .HttpProxy )
192
192
if err != nil && ! errors .Is (err , git .ErrRepositoryAlreadyExists ) {
193
- onError (w , subJobLog .With (logger .ErrAttr (err )), "failed to clone remote repository" , err .Error (), jobID , http .StatusInternalServerError )
193
+ onError (repoName , w , subJobLog .With (logger .ErrAttr (err )), "failed to clone remote repository" , err .Error (), jobID , http .StatusInternalServerError )
194
194
195
195
return
196
196
}
@@ -202,14 +202,14 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
202
202
203
203
repo , err := git .UpdateRepository (internalRepoPath , deployConfig .Reference , appConfig .SkipTLSVerification , appConfig .HttpProxy )
204
204
if err != nil {
205
- onError (w , subJobLog .With (logger .ErrAttr (err )), "failed to checkout repository" , err .Error (), jobID , http .StatusInternalServerError )
205
+ onError (repoName , w , subJobLog .With (logger .ErrAttr (err )), "failed to checkout repository" , err .Error (), jobID , http .StatusInternalServerError )
206
206
207
207
return
208
208
}
209
209
210
210
latestCommit , err := git .GetLatestCommit (repo , deployConfig .Reference )
211
211
if err != nil {
212
- onError (w , subJobLog .With (logger .ErrAttr (err )), "failed to get latest commit" , err .Error (), jobID , http .StatusInternalServerError )
212
+ onError (repoName , w , subJobLog .With (logger .ErrAttr (err )), "failed to get latest commit" , err .Error (), jobID , http .StatusInternalServerError )
213
213
214
214
return
215
215
}
@@ -220,7 +220,7 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
220
220
// Check if doco-cd manages the project before destroying the stack
221
221
containers , err := docker .GetLabeledContainers (ctx , dockerClient , api .ProjectLabel , deployConfig .Name )
222
222
if err != nil {
223
- onError (w , subJobLog .With (logger .ErrAttr (err )), "failed to retrieve containers" , err .Error (), jobID , http .StatusInternalServerError )
223
+ onError (repoName , w , subJobLog .With (logger .ErrAttr (err )), "failed to retrieve containers" , err .Error (), jobID , http .StatusInternalServerError )
224
224
225
225
return
226
226
}
@@ -249,22 +249,22 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
249
249
}
250
250
251
251
if ! managed {
252
- onError (w , subJobLog , fmt .Errorf ("%w: %s: aborting destruction" , ErrNotManagedByDocoCD , deployConfig .Name ).Error (),
252
+ onError (repoName , w , subJobLog , fmt .Errorf ("%w: %s: aborting destruction" , ErrNotManagedByDocoCD , deployConfig .Name ).Error (),
253
253
"" , jobID , http .StatusInternalServerError )
254
254
255
255
return
256
256
}
257
257
258
258
if ! correctRepo {
259
- onError (w , subJobLog , fmt .Errorf ("%w: %s: aborting destruction" , ErrDeploymentConflict , deployConfig .Name ).Error (),
259
+ onError (repoName , w , subJobLog , fmt .Errorf ("%w: %s: aborting destruction" , ErrDeploymentConflict , deployConfig .Name ).Error (),
260
260
map [string ]string {"stack" : deployConfig .Name }, jobID , http .StatusInternalServerError )
261
261
262
262
return
263
263
}
264
264
265
265
err = docker .DestroyStack (subJobLog , & ctx , & dockerCli , deployConfig )
266
266
if err != nil {
267
- onError (w , subJobLog .With (logger .ErrAttr (err )), "failed to destroy stack" , err .Error (), jobID , http .StatusInternalServerError )
267
+ onError (repoName , w , subJobLog .With (logger .ErrAttr (err )), "failed to destroy stack" , err .Error (), jobID , http .StatusInternalServerError )
268
268
269
269
return
270
270
}
@@ -277,7 +277,7 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
277
277
278
278
subDirs , err := os .ReadDir (parentDir )
279
279
if err != nil {
280
- onError (w , subJobLog .With (logger .ErrAttr (err )), "failed to read parent directory" , err .Error (), jobID , http .StatusInternalServerError )
280
+ onError (repoName , w , subJobLog .With (logger .ErrAttr (err )), "failed to read parent directory" , err .Error (), jobID , http .StatusInternalServerError )
281
281
282
282
return
283
283
}
@@ -289,15 +289,15 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
289
289
// Remove only the repository directory
290
290
err = os .RemoveAll (internalRepoPath )
291
291
if err != nil {
292
- onError (w , subJobLog .With (logger .ErrAttr (err )), "failed to remove deployment directory" , err .Error (), jobID , http .StatusInternalServerError )
292
+ onError (repoName , w , subJobLog .With (logger .ErrAttr (err )), "failed to remove deployment directory" , err .Error (), jobID , http .StatusInternalServerError )
293
293
294
294
return
295
295
}
296
296
} else {
297
297
// Remove the parent directory if it has only one subdirectory
298
298
err = os .RemoveAll (parentDir )
299
299
if err != nil {
300
- onError (w , subJobLog .With (logger .ErrAttr (err )), "failed to remove deployment directory" , err .Error (), jobID , http .StatusInternalServerError )
300
+ onError (repoName , w , subJobLog .With (logger .ErrAttr (err )), "failed to remove deployment directory" , err .Error (), jobID , http .StatusInternalServerError )
301
301
302
302
return
303
303
}
@@ -309,7 +309,7 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
309
309
// Skip deployment if another project with the same name already exists
310
310
containers , err := docker .GetLabeledContainers (ctx , dockerClient , api .ProjectLabel , deployConfig .Name )
311
311
if err != nil {
312
- onError (w , subJobLog .With (logger .ErrAttr (err )), "failed to retrieve containers" , err .Error (), jobID , http .StatusInternalServerError )
312
+ onError (repoName , w , subJobLog .With (logger .ErrAttr (err )), "failed to retrieve containers" , err .Error (), jobID , http .StatusInternalServerError )
313
313
314
314
return
315
315
}
@@ -330,7 +330,7 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
330
330
}
331
331
332
332
if ! correctRepo {
333
- onError (w , subJobLog , fmt .Errorf ("%w: %s: skipping deployment" , ErrDeploymentConflict , deployConfig .Name ).Error (),
333
+ onError (repoName , w , subJobLog , fmt .Errorf ("%w: %s: skipping deployment" , ErrDeploymentConflict , deployConfig .Name ).Error (),
334
334
map [string ]string {"stack" : deployConfig .Name }, jobID , http .StatusInternalServerError )
335
335
336
336
return
@@ -339,7 +339,7 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
339
339
if deployedCommit != "" {
340
340
changed , err := git .CompareCommitsInSubdir (repo , plumbing .NewHash (deployedCommit ), plumbing .NewHash (latestCommit ), deployConfig .WorkingDirectory )
341
341
if err != nil {
342
- onError (w , subJobLog , fmt .Errorf ("failed to compare commits in subdirectory: %w" , err ).Error (),
342
+ onError (repoName , w , subJobLog , fmt .Errorf ("failed to compare commits in subdirectory: %w" , err ).Error (),
343
343
map [string ]string {"stack" : deployConfig .Name }, jobID , http .StatusInternalServerError )
344
344
345
345
return
@@ -362,7 +362,7 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
362
362
363
363
err = docker .DeployStack (subJobLog , internalRepoPath , externalRepoPath , & ctx , & dockerCli , & payload , deployConfig , latestCommit , Version , false )
364
364
if err != nil {
365
- onError (w , subJobLog .With (logger .ErrAttr (err )), "deployment failed" , err .Error (), jobID , http .StatusInternalServerError )
365
+ onError (repoName , w , subJobLog .With (logger .ErrAttr (err )), "deployment failed" , err .Error (), jobID , http .StatusInternalServerError )
366
366
367
367
return
368
368
}
@@ -374,8 +374,8 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
374
374
jobLog .Info (msg , slog .String ("elapsed_time" , elapsedTime .Truncate (time .Millisecond ).String ()))
375
375
JSONResponse (w , msg , jobID , http .StatusCreated )
376
376
377
- prometheus .WebhookRequestsTotal .Inc ()
378
- prometheus .WebhookDuration .Observe (elapsedTime .Seconds ())
377
+ prometheus .WebhookRequestsTotal .WithLabelValues ( repoName ). Inc ()
378
+ prometheus .WebhookDuration .WithLabelValues ( repoName ). Observe (elapsedTime .Seconds ())
379
379
}
380
380
381
381
func (h * handlerData ) WebhookHandler (w http.ResponseWriter , r * http.Request ) {
@@ -417,7 +417,7 @@ func (h *handlerData) WebhookHandler(w http.ResponseWriter, r *http.Request) {
417
417
statusCode = http .StatusInternalServerError
418
418
}
419
419
420
- onError (w , jobLog .With (slog .String ("ip" , r .RemoteAddr ), logger .ErrAttr (err )), errMsg , err .Error (), jobID , statusCode )
420
+ onError (getRepoName ( payload . CloneURL ), w , jobLog .With (slog .String ("ip" , r .RemoteAddr ), logger .ErrAttr (err )), errMsg , err .Error (), jobID , statusCode )
421
421
422
422
return
423
423
}
@@ -428,7 +428,7 @@ func (h *handlerData) WebhookHandler(w http.ResponseWriter, r *http.Request) {
428
428
func (h * handlerData ) HealthCheckHandler (w http.ResponseWriter , _ * http.Request ) {
429
429
err := docker .VerifySocketConnection ()
430
430
if err != nil {
431
- onError (w , h .log .With (logger .ErrAttr (err )), docker .ErrDockerSocketConnectionFailed .Error (), err .Error (), "" , http .StatusServiceUnavailable )
431
+ onError ("healthcheck" , w , h .log .With (logger .ErrAttr (err )), docker .ErrDockerSocketConnectionFailed .Error (), err .Error (), "" , http .StatusServiceUnavailable )
432
432
433
433
return
434
434
}
0 commit comments