Skip to content

Commit 966aea8

Browse files
committed
refactor client error logging, change not_saved metric to no_attestation, add rate_limited metric
1 parent 6299c2e commit 966aea8

File tree

5 files changed

+376
-19
lines changed

5 files changed

+376
-19
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,10 @@ The metrics exposed beyond the default Prometheus metrics are:
184184
outgoing HTTP POST to upload the deployment record.
185185
* `deptracker_post_record_ok`: the number of successful deployment
186186
record uploads.
187+
* `deptracker_post_record_rate_limited`: the number of post attempts
188+
that were rate limited.
189+
* `deptracker_post_record_no_attestation`: the number of successful
190+
posts for container digest with no matching attestation for the org.
187191
* `deptracker_post_record_soft_fail`: the number of recoverable failed
188192
attempts to upload the deployment record.
189193
* `deptracker_post_record_hard_fail`: the number of failures to

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ require (
3232
github.com/google/uuid v1.6.0 // indirect
3333
github.com/josharian/intern v1.0.0 // indirect
3434
github.com/json-iterator/go v1.1.12 // indirect
35+
github.com/kylelemons/godebug v1.1.0 // indirect
3536
github.com/mailru/easyjson v0.7.7 // indirect
3637
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
3738
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect

pkg/deploymentrecord/client.go

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,10 @@ type NoArtifactError struct {
166166
}
167167

168168
func (n *NoArtifactError) Error() string {
169-
return fmt.Sprintf("client_error: %s", n.err.Error())
169+
if n.err == nil {
170+
return "no artifact found"
171+
}
172+
return fmt.Sprintf("no artifact found: %s", n.err.Error())
170173
}
171174

172175
func (n *NoArtifactError) Unwrap() error {
@@ -262,35 +265,39 @@ func (c *Client) PostOne(ctx context.Context, record *DeploymentRecord) error {
262265
}
263266

264267
// Drain and close response body to enable connection reuse by reading body for error logging
265-
body, _ := io.ReadAll(io.LimitReader(resp.Body, 4096))
268+
respBody, _ := io.ReadAll(io.LimitReader(resp.Body, 4096))
266269
_, _ = io.Copy(io.Discard, resp.Body)
267270
_ = resp.Body.Close()
268271

269272
switch {
270-
case resp.StatusCode == 429:
271-
// Retry with backoff
272-
dtmetrics.PostDeploymentRecordSoftFail.Inc()
273-
slog.Debug("rate limited, retrying",
274-
"attempt", attempt,
275-
"status_code", resp.StatusCode,
276-
)
277-
lastErr = fmt.Errorf("rate limited, attempt %d", attempt)
278-
continue
279-
case resp.StatusCode == 404:
273+
case resp.StatusCode == 404 && bytes.Contains(respBody, []byte("no artifacts found")):
280274
// No artifact found
281-
dtmetrics.PostDeploymentRecordNotSaved.Inc()
275+
dtmetrics.PostDeploymentRecordNoAttestation.Inc()
282276
slog.Debug("no artifact attestation found, no record created",
283277
"attempt", attempt,
284278
"status_code", resp.StatusCode,
285279
)
286-
return &NoArtifactError{err: fmt.Errorf("no artifact found")}
280+
return &NoArtifactError{}
287281
case resp.StatusCode >= 400 && resp.StatusCode < 500:
282+
if resp.Header.Get("retry-after") != "" || resp.Header.Get("x-ratelimit-remaining") == "0" {
283+
// rate limited — retry with backoff
284+
// Could be 403 or 429
285+
dtmetrics.PostDeploymentRecordRateLimited.Inc()
286+
slog.Warn("rate limited, retrying",
287+
"attempt", attempt,
288+
"status_code", resp.StatusCode,
289+
"retry_after", resp.Header.Get("Retry-After"),
290+
"resp_msg", string(respBody),
291+
)
292+
lastErr = fmt.Errorf("rate limited, attempt %d", attempt)
293+
continue
294+
}
288295
// Don't retry non rate limiting client errors
289296
dtmetrics.PostDeploymentRecordClientError.Inc()
290297
slog.Warn("client error, aborting",
291298
"attempt", attempt,
292299
"status_code", resp.StatusCode,
293-
"resp_msg", string(body),
300+
"resp_msg", string(respBody),
294301
)
295302
return &ClientError{err: fmt.Errorf("unexpected client err with status code %d", resp.StatusCode)}
296303
default:
@@ -299,7 +306,7 @@ func (c *Client) PostOne(ctx context.Context, record *DeploymentRecord) error {
299306
slog.Debug("retriable error",
300307
"attempt", attempt,
301308
"status_code", resp.StatusCode,
302-
"resp_msg", string(body),
309+
"resp_msg", string(respBody),
303310
)
304311
lastErr = fmt.Errorf("server error, attempt %d", attempt)
305312
}

0 commit comments

Comments
 (0)