Skip to content

Add in-flight and richer duration Prometheus metrics on all Porch API operations - #1198

Open
JamesMcDermott wants to merge 14 commits into
kptdev:mainfrom
Nordix:feature-porch-operation-metrics
Open

JamesMcDermott wants to merge 14 commits into
kptdev:mainfrom
Nordix:feature-porch-operation-metrics

Conversation

@JamesMcDermott

@JamesMcDermott JamesMcDermott commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

Description

  • What changed:
    • enhance the existing API-call-duration histogram (porch_api_call_duration_seconds) into a Porch-API-operation-duration metric
      • adding new labels
        • operation
        • operation_outcome
        • lifecycle_after
        • package-revision key labels:
          • namespace
          • repository
          • package
          • workspace_name
    • add a new porch_in_flight_api_operations gauge (an Int64UpDownCounter) to track
      currently-in-progress Porch operations
      • wired into both porch-server (v1alpha1 REST) flows and v1alpha2 controller reconcile loop
    • new E2E tests in the v1alpha1 (api) suite and counterparts in the v1alpha2 (crd) suiterefactoring
  • Why it’s needed:
    • improves insight into Porch API behaviour, allowing more detailed breakdown of operations according to
      per-operation/outcome/lifecycle
    • improves visibility into in-progress operations.
    • making it easier to observe latency per operation, spot error rates, or detect stuck/leaked
      operations
  • How it works:
    • operation instrumentation:
      • records duration and outcome via improved RecordAPIOperationDuration/RecordControllerOperation
      • brackets each operation with new TrackInFlightOperation/TrackInFlightControllerOperation, which increments the in-flight gauge at start and decrements it via a deferred closure on completion (including error paths).

Type of Change

  • Bug fix
  • New feature
  • Enhancement
  • Documentation
  • Tests
  • Other: ________

Checklist

  • Code follows project style guidelines
  • Self-reviewed changes
  • Tests added/updated
  • Documentation added/updated (will raise separate PR)
  • All tests and gating checks pass

Testing Instructions (Optional)

  1. Run the unit tests: make test
  2. Deploy Porch with all components in-cluster and run the appropriate E2E suite:
  3. with v1alpha1
    1. make setup-dev-env run-in-kind-db-cache test-e2e
  4. with v1alpha2
    1. make setup-dev-env run-in-kind-v1alpha2 test-e2e-crd
  5. Scrape a porch-server / porch-controllers pod's /metrics endpoint and confirm the presence of
    porch_api_call_duration_seconds_{bucket,count,sum} with the new labels and
    porch_in_flight_api_operations settling to 0 once operations complete.

Additional Notes (Optional)

  • Known issues:
    • The porch_in_flight_api_operations in-flight proof (the spammer/scraper approach) is only exercised in the v1alpha1 (API) suite; the v1alpha2 (CRD) suite asserts steady-state and per-operation presence but not mid-flight increment, because controller operations are driven by asynchronous reconciliation rather than synchronous, re-runnable REST calls.
    • The e2e metrics tests currently require an all-in-cluster deployment and are skipped otherwise.
  • Review notes:
    • source_test.go asserts the selected source action via fmt.Sprintf("%#v", ...) function-value
      comparison; this is intentional but relies on stable function formatting.

AI Disclosure

  • I have used AI in the creation of this PR.

If so, please describe how:

  • Kiro/Amazon Q to:
    • analyse changes and draft this pull request description
    • help design and generate the e2e metrics tests
    • refactor the E2E tests' metrics collection/assertion helpers to share between API and CRD suites
    • extract lifecycle resolution routines out into common functions

@JamesMcDermott
JamesMcDermott requested review from a team and a lite review from Copilot September 21, 2026 16:45
@netlify

netlify Bot commented Sep 21, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for kpt-porch canceled.

Built without sensitive environment variables

Name Link
🔨 Latest commit 63caa82
🔍 Latest deploy log https://app.netlify.com/projects/kpt-porch/deploys/6af4dcf2048f923b5db70325

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Unresolved critical and moderate findings affect metric correctness, test reliability, and existing performance dashboards.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 3 High severity · 12 Medium severity · 2 Low severity

Open (17)
What changed in this PR

Adds richer Porch API duration metrics and in-flight operation tracking across REST and controller paths, with expanded E2E coverage and monitoring fixes.

Changes:

  • Adds operation, outcome, lifecycle, and package-revision labels.
  • Instruments REST and controller operations with in-flight gauges.
  • Updates telemetry helpers, tests, and monitoring paths.
File Description
test/​performance/​metrics_utils.go Routes performance durations through telemetry.
test/​e2e/​suiteutils/​suite.go Adds logging-oriented client helpers.
test/​e2e/​suiteutils/​suite_utils.go Refactors metrics collection and parsing.
test/​e2e/​crd/​suite_test.go Initializes the Kubernetes client.
test/​e2e/​crd/​metrics_test.go Adds controller metrics tests.
test/​e2e/​crd/​helpers_test.go Adds deletion polling support.
test/​e2e/​api/​metrics_test.go Adds API metrics and in-flight tests.
scripts/​monitoring/​deploy-monitoring.sh Fixes monitoring resource paths.
pkg/​registry/​porch/​packagerevisionresources.go Instruments resource operations.
pkg/​registry/​porch/​packagerevisionresources_update_test.go Updates resource-operation mocks.
pkg/​registry/​porch/​packagerevisionresources_test.go Updates lifecycle mocks.
pkg/​registry/​porch/​packagerevision.go Instruments PackageRevision operations.
pkg/​registry/​porch/​packagerevision_test.go Updates revision-operation mocks.
pkg/​registry/​porch/​packagerevision_approval.go Instruments approval operations.
pkg/​registry/​porch/​packagerevision_approval_test.go Updates approval-operation mocks.
pkg/​registry/​porch/​packagecommon.go Returns typed updated revisions.
internal/​telemetry/​metrics.go Defines enriched metrics.
internal/​telemetry/​metrics_test.go Updates telemetry tests.
controllers/​packagerevisions/​pkg/​controllers/​packagerevision/​source.go Refactors source action selection.
controllers/​packagerevisions/​pkg/​controllers/​packagerevision/​source_test.go Tests source action selection.
controllers/​packagerevisions/​pkg/​controllers/​packagerevision/​render.go Instruments render operations.
controllers/​packagerevisions/​pkg/​controllers/​packagerevision/​packagerevision_controller.go Instruments reconciliation.
controllers/​packagerevisions/​pkg/​controllers/​packagerevision/​ownership.go Instruments deletion cleanup.
controllers/​packagerevisions/​pkg/​controllers/​packagerevision/​metadata.go Instruments metadata updates.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread test/e2e/crd/helpers_test.go Resolved
Comment thread test/e2e/suiteutils/suite_utils.go Resolved
Comment thread test/e2e/crd/metrics_test.go Resolved
Comment thread test/e2e/suiteutils/suite.go Resolved
Comment thread test/performance/metrics_utils.go Resolved
Comment thread pkg/registry/porch/packagerevision.go Resolved
@JamesMcDermott
JamesMcDermott force-pushed the feature-porch-operation-metrics branch from 31ccc38 to d4d35c0 Compare September 21, 2026 16:53
@JamesMcDermott JamesMcDermott changed the title Add in-flight and richer duration Prometheus metrics on all Porch API operations Add in-flight and richer duration Prometheus metrics on all Porch API operations Sep 23, 2026
Comment thread pkg/registry/porch/packagerevision.go Resolved
Comment thread pkg/registry/porch/packagerevision.go Resolved
efiacor

This comment was marked as resolved.

Comment thread pkg/registry/porch/packagerevision.go Resolved
Comment thread internal/telemetry/metrics.go Resolved
Comment thread pkg/registry/porch/packagerevision.go Resolved
Comment thread pkg/registry/porch/packagerevision.go Resolved
Comment thread pkg/registry/porch/packagerevision.go Resolved
Comment thread pkg/registry/porch/packagerevision.go Resolved
Comment thread internal/telemetry/metrics.go Resolved
Comment thread internal/telemetry/metrics.go Resolved
Comment thread internal/telemetry/metrics.go Resolved
telemetry.RecordRequestCount(ctx, prrTelemetryName, op.AllCaps, telemetry.APIVersionV1Alpha1)

name, resourceSelector, err := selector.ParsePRRGet(rawName)
parsedName, resourceSelector, err := selector.ParsePRRGet(pkgRevK8sName)

@liamfallon liamfallon Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have a lot of changes like this which, while improving the readability of the PR, are not related tot he actual telemetry changes. They make the PR much bigger and harder to review.

return false, err
}

saveErr := func(loseableErr error) error { err = loseableErr; return err }

@liamfallon liamfallon Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line can be deleted

telemetry.RecordControllerOperation(ctx, prrTelemetryName, op.AllCaps, op.TitleCase+prrTelemetryName, time.Since(start), err, pr.Spec.Lifecycle, &key)
}()

// Create draft and write updated resources.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add this line here:

	var draft repository.PackageRevisionDraftSlim

}()

// Create draft and write updated resources.
draft, err := r.ContentCache.CreateDraftFromExisting(ctx, repoKey, pr.Spec.PackageName, pr.Spec.WorkspaceName)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
draft, err := r.ContentCache.CreateDraftFromExisting(ctx, repoKey, pr.Spec.PackageName, pr.Spec.WorkspaceName)
draft, err = r.ContentCache.CreateDraftFromExisting(ctx, repoKey, pr.Spec.PackageName, pr.Spec.WorkspaceName)

// UpdateResources is a full replace — include all files to avoid data loss.
resources["Kptfile"] = string(updatedKfBytes)
log.Info("metadata sync writing resources", "resourceCount", len(resources))
if err := draft.UpdateResources(ctx, resources, "metadata-sync"); err != nil {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if err := draft.UpdateResources(ctx, resources, "metadata-sync"); err != nil {
if err = draft.UpdateResources(ctx, resources, "metadata-sync"); err != nil {

if err != nil {
log.Error(err, "failed to create draft")
return false, err
return false, saveErr(err)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return false, saveErr(err)
return false, err

if err := draft.UpdateResources(ctx, resources, "metadata-sync"); err != nil {
log.Error(err, "failed to write resources")
return false, err
return false, saveErr(err)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return false, saveErr(err)
return false, err

if err := r.ContentCache.CloseDraft(ctx, repoKey, draft, 0); err != nil {
log.Error(err, "failed to close draft")
return false, err
return false, saveErr(err)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return false, saveErr(err)
return false, err

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check other places where this saveErr pattern is used and change the code to not use local block err variables.

saveErr := func(loseableErr error) error { err = loseableErr; return err }
op := telemetry.Operations.Update
start := time.Now()
key := telemetry.ParsePkgRevK8sName2Key(pr.Namespace, pr.Name)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this function do that key.PkgRevK8sName2Key does not do?

defer telemetry.TrackInFlightControllerOperation(ctx, prrTelemetryName, op.AllCaps, op.TitleCase+prrTelemetryName, pr.Spec.Lifecycle, &key)()
defer func() {
telemetry.RecordControllerOperation(ctx, prrTelemetryName, op.AllCaps, op.TitleCase+prrTelemetryName, time.Since(start), err, pr.Spec.Lifecycle, &key)
}()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd really like to boil this down to two function calls.

- enhance existing API-call-duration histogram to include more information
  from Porch perspective
  - making it a Porch-API-operation-duration metric
- add new metric to track in-flight (currently-in-progress) Porch
  operations

Signed-off-by: James McDermott <james.j.mcdermott@ericsson.com>
- wire porch_in_flight_api_operations gauge into v1alpha2 controller
  reconciler operations
  - track lifecycle, source, metadata-sync, render, and delete
    reconcile paths
    - Published lifecycle transitions recorded under PackageRevisionApproval.
- refactor applySource into selectPackageSourceAction + execution so the
  operation type (init/clone/copy/upgrade) is known for telemetry; update
  source_test.go accordingly.
- new E2E tests TestAPIOperationDurationMetricExists, TestAPIOperationDurationLabels,
  and TestInFlightOperationsMetric in v1alpha1 suite
  - counterparts in v1alpha2 suite testing against PorchControllerMetrics.
- small fix in deploy-monitoring.sh config paths

Signed-off-by: James McDermott <james.j.mcdermott@ericsson.com>
in case of errors

- fix unit tests to account for extra calls to GetPackageRevision(),
  Lifecycle(), etc.

Signed-off-by: James McDermott <james.j.mcdermott@ericsson.com>
- cover cases where error occurs but is hidden from telemetry calls
  - prevent recording errored operations as success
- revisits lifecycle acquisition for telemetry calls - make it as accurate as
  possible without extra queries to Git or database
- changes to packagecommon.updatePackageRevision() to include existing lifecycle in returns
  - only way to get it back into higher-level Update() methods to include in telemetry

Signed-off-by: James McDermott <james.j.mcdermott@ericsson.com>
- also fix build

Signed-off-by: James McDermott <james.j.mcdermott@ericsson.com>
Signed-off-by: James McDermott <james.j.mcdermott@ericsson.com>
Signed-off-by: James McDermott <james.j.mcdermott@ericsson.com>
…hods

- as per SonarQube duplication report

Signed-off-by: James McDermott <james.j.mcdermott@ericsson.com>
Signed-off-by: James McDermott <james.j.mcdermott@ericsson.com>
- wire contexts into metric recording functions
- add explicit saveErr calls into API methods' early returns
- ensure packageRevisions.Create() has in-flight recording
  for earliest possible return
- ensure controller's reconcileLifecycle doesn't leak in-flight
  counter for ContentCache.Get()
- when recording in case package revision key is nil, at least
  get namespace from context and record that
- for LIST PackageRevision, pluralise telemetry name to get
  "ListPackageRevisions" operation

Signed-off-by: James McDermott <james.j.mcdermott@ericsson.com>
Signed-off-by: James McDermott <james.j.mcdermott@ericsson.com>
- also add dedicated function for name-to-key parsing to
  get PackageRevisionKeys for metrics

Signed-off-by: James McDermott <james.j.mcdermott@ericsson.com>
Signed-off-by: James McDermott <james.j.mcdermott@ericsson.com>
Signed-off-by: James McDermott <james.j.mcdermott@ericsson.com>
@JamesMcDermott
JamesMcDermott force-pushed the feature-porch-operation-metrics branch from 490f9f5 to 63caa82 Compare November 11, 2026 21:23
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
79.0% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants