From d1e1d6cd852ab6e654e7424e45a2616cb584a378 Mon Sep 17 00:00:00 2001 From: Eric Pickard Date: Fri, 10 Apr 2026 16:50:56 -0400 Subject: [PATCH 1/4] control log level via env var Signed-off-by: Eric Pickard --- README.md | 1 + cmd/deployment-tracker/main.go | 23 ++++++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9f134ba..b323d8a 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,7 @@ Two modes of authentication are supported: | Variable | Description | Default | |------------------------|--------------------------------------------|------------------------------------------------------| +| `LOG_LEVEL` | log level: DEBUG, INFO, WARN, ERROR | `INFO` | | `ORG` | GitHub organization name | (required) | | `BASE_URL` | API base URL | `api.github.com` | | `DN_TEMPLATE` | Deployment name template | `{{namespace}}/{{deploymentName}}/{{containerName}}` | diff --git a/cmd/deployment-tracker/main.go b/cmd/deployment-tracker/main.go index c38481a..f6dd3bc 100644 --- a/cmd/deployment-tracker/main.go +++ b/cmd/deployment-tracker/main.go @@ -10,6 +10,7 @@ import ( "net/http" "os" "os/signal" + "strings" "syscall" "time" @@ -65,8 +66,13 @@ func main() { // init logging log.SetFlags(log.LstdFlags | log.Lshortfile | log.LUTC) - opts := slog.HandlerOptions{Level: slog.LevelInfo} + logLevelStr := getEnvOrDefault("LOG_LEVEL", "INFO") + level, msg := parseLogLevel(logLevelStr) + opts := slog.HandlerOptions{Level: level} slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stdout, &opts))) + if msg != "" { + slog.Warn(msg) + } var ghAppPrivateKey []byte if b64Key := os.Getenv("GH_APP_PRIVATE_KEY"); b64Key != "" { @@ -220,3 +226,18 @@ func createK8sConfig(kubeconfig string) (*rest.Config, error) { } return clientcmd.BuildConfigFromFlags("", homeDir+"/.kube/config") } + +func parseLogLevel(logLevel string) (slog.Level, string) { + switch strings.ToUpper(logLevel) { + case "DEBUG": + return slog.LevelDebug, "" + case "INFO": + return slog.LevelInfo, "" + case "WARN": + return slog.LevelWarn, "" + case "ERROR": + return slog.LevelError, "" + default: + return slog.LevelInfo, fmt.Sprintf("%s is an unsupported log level (DEBUG, WARN, INFO, ERROR), using INFO...", logLevel) + } +} From fc6301a1f912c068fec3dc27702f713ea9c9c48e Mon Sep 17 00:00:00 2001 From: Eric Pickard Date: Fri, 10 Apr 2026 16:58:03 -0400 Subject: [PATCH 2/4] rename deptracker_post_record_no_attestation to deptracker_post_record_unknown_artifact Signed-off-by: Eric Pickard --- README.md | 2 +- pkg/deploymentrecord/client.go | 2 +- pkg/deploymentrecord/client_test.go | 40 ++++++++++++++--------------- pkg/dtmetrics/prom.go | 4 +-- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index b323d8a..173c70b 100644 --- a/README.md +++ b/README.md @@ -193,7 +193,7 @@ The metrics exposed beyond the default Prometheus metrics are: record uploads. * `deptracker_post_record_rate_limited`: the number of post attempts that were rate limited. -* `deptracker_post_record_no_attestation`: the number of attempts +* `deptracker_post_record_unknown_artifact`: the number of attempts that resulted in no matching attestation for the container digest (404 "no artifacts found" responses). * `deptracker_post_record_soft_fail`: the number of recoverable failed diff --git a/pkg/deploymentrecord/client.go b/pkg/deploymentrecord/client.go index e4e71c1..05915f0 100644 --- a/pkg/deploymentrecord/client.go +++ b/pkg/deploymentrecord/client.go @@ -265,7 +265,7 @@ func (c *Client) PostOne(ctx context.Context, record *DeploymentRecord) error { switch { case resp.StatusCode == 404: // No artifact found - do not retry - dtmetrics.PostDeploymentRecordNoAttestation.Inc() + dtmetrics.PostDeploymentRecordUnknownArtifact.Inc() slog.Debug("no artifact attestation found, no record created", "attempt", attempt, "status_code", resp.StatusCode, diff --git a/pkg/deploymentrecord/client_test.go b/pkg/deploymentrecord/client_test.go index 7a7f861..9a2efb1 100644 --- a/pkg/deploymentrecord/client_test.go +++ b/pkg/deploymentrecord/client_test.go @@ -298,7 +298,7 @@ func testRecord() *DeploymentRecord { func allCounters() []prometheus.Counter { return []prometheus.Counter{ dtmetrics.PostDeploymentRecordOk, - dtmetrics.PostDeploymentRecordNoAttestation, + dtmetrics.PostDeploymentRecordUnknownArtifact, dtmetrics.PostDeploymentRecordRateLimited, dtmetrics.PostDeploymentRecordSoftFail, dtmetrics.PostDeploymentRecordHardFail, @@ -308,19 +308,19 @@ func allCounters() []prometheus.Counter { func TestPostOne(t *testing.T) { tests := []struct { - name string - record *DeploymentRecord - retries int - handler http.HandlerFunc - wantErr bool - errType any // expected error type for errors.As - errContain string - wantOk float64 - wantNoAttestation float64 - wantRateLimited float64 - wantSoftFail float64 - wantHardFail float64 - wantClientError float64 + name string + record *DeploymentRecord + retries int + handler http.HandlerFunc + wantErr bool + errType any // expected error type for errors.As + errContain string + wantOk float64 + wantUnknownArtifact float64 + wantRateLimited float64 + wantSoftFail float64 + wantHardFail float64 + wantClientError float64 }{ { name: "success on 200", @@ -354,10 +354,10 @@ func TestPostOne(t *testing.T) { w.WriteHeader(http.StatusNotFound) _, _ = w.Write([]byte(`{"message":"no artifacts found"}`)) }, - wantErr: true, - errType: &NoArtifactError{}, - errContain: "sha256:abc123", - wantNoAttestation: 1, + wantErr: true, + errType: &NoArtifactError{}, + errContain: "sha256:abc123", + wantUnknownArtifact: 1, }, { name: "400 returns ClientError", @@ -555,7 +555,7 @@ func TestPostOne(t *testing.T) { // Assert all metric deltas wantDeltas := []float64{ tt.wantOk, - tt.wantNoAttestation, + tt.wantUnknownArtifact, tt.wantRateLimited, tt.wantSoftFail, tt.wantHardFail, @@ -563,7 +563,7 @@ func TestPostOne(t *testing.T) { } names := []string{ "PostDeploymentRecordOk", - "PostDeploymentRecordNoAttestation", + "PostDeploymentRecordUnknownArtifact", "PostDeploymentRecordRateLimited", "PostDeploymentRecordSoftFail", "PostDeploymentRecordHardFail", diff --git a/pkg/dtmetrics/prom.go b/pkg/dtmetrics/prom.go index 2143bd9..3eae17c 100644 --- a/pkg/dtmetrics/prom.go +++ b/pkg/dtmetrics/prom.go @@ -50,9 +50,9 @@ var ( ) //nolint: revive - PostDeploymentRecordNoAttestation = promauto.NewCounter( + PostDeploymentRecordUnknownArtifact = promauto.NewCounter( prometheus.CounterOpts{ - Name: "deptracker_post_record_no_attestation", + Name: "deptracker_post_record_unknown_artifact", Help: "The total number of post attempts that resulted in no matching attestation for the container digest (404 'no artifacts found' responses)", }, ) From e307d6ec6dca43338ae9312e20e8b03a3f5c62f5 Mon Sep 17 00:00:00 2001 From: Eric Pickard Date: Mon, 13 Apr 2026 15:30:44 -0400 Subject: [PATCH 3/4] add docs for deptracker_post_record_unknown_artifact_cache_hit Signed-off-by: Eric Pickard --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 173c70b..9c8c49c 100644 --- a/README.md +++ b/README.md @@ -195,7 +195,10 @@ The metrics exposed beyond the default Prometheus metrics are: that were rate limited. * `deptracker_post_record_unknown_artifact`: the number of attempts that resulted in no matching attestation for the container digest - (404 "no artifacts found" responses). + (404 "no artifacts found" responses) and an entry in the unknown + artifact cache. +* `deptracker_post_record_unknown_artifact_cache_hit`: the number of + attempts to create new records prevented by the unknown artifact cache. * `deptracker_post_record_soft_fail`: the number of recoverable failed attempts to upload the deployment record. * `deptracker_post_record_hard_fail`: the number of failures to From 9c2bcee90ecf47026d7f51665228b1da0378adca Mon Sep 17 00:00:00 2001 From: Eric Pickard Date: Mon, 27 Apr 2026 15:43:10 -0400 Subject: [PATCH 4/4] remove trailing space Signed-off-by: Eric Pickard --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9c8c49c..de7f6c0 100644 --- a/README.md +++ b/README.md @@ -197,7 +197,7 @@ The metrics exposed beyond the default Prometheus metrics are: that resulted in no matching attestation for the container digest (404 "no artifacts found" responses) and an entry in the unknown artifact cache. -* `deptracker_post_record_unknown_artifact_cache_hit`: the number of +* `deptracker_post_record_unknown_artifact_cache_hit`: the number of attempts to create new records prevented by the unknown artifact cache. * `deptracker_post_record_soft_fail`: the number of recoverable failed attempts to upload the deployment record.