Skip to content

Improve config-load observability (#304) - #547

Open
lodyai[bot] wants to merge 4 commits into
mainfrom
issue-304-improve-observability-of-config-load-error-paths-structured-log-fields-metrics-by-phase
Open

Improve config-load observability (#304)#547
lodyai[bot] wants to merge 4 commits into
mainfrom
issue-304-improve-observability-of-config-load-error-paths-structured-log-fields-metrics-by-phase

Conversation

@lodyai

@lodyai lodyai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Summary

This branch instruments the two configuration-loading phases so operators can
identify failures, compare outcomes, and inspect startup latency without
unbounded telemetry labels.

Closes #304.

Review walkthrough

  • Start with src/observability.rs for the bounded metric vocabulary, error categorization, process recorder, and isolated recorder-backed tests.
  • Review src/main.rs for the configuration phase timing, outcome recording, and contextual error events at the CLI composition root.
  • Check src/main_tests.rs for the structured log-field contract, then docs/developers-guide.md for its maintenance contract.

Validation

  • make check-fmt: passed
  • make typecheck: passed
  • make lint: passed
  • make test: passed (1,913 nextest tests and doctests)
  • make markdownlint: passed
  • make nixie: passed
  • coderabbit review --agent: passed with zero findings after each milestone

References

Summary by Sourcery

Instrument configuration loading phases with bounded metrics, structured error logging, and a process-wide metrics recorder to improve observability of config-load behavior and failures.

New Features:

  • Add a process-level observability module that records configuration load outcomes and durations with bounded phase labels.
  • Emit a debug metrics snapshot at process shutdown when verbose CLI output is enabled.

Enhancements:

  • Augment configuration load error logging with operation and categorized error fields while preserving human-readable messages.
  • Wrap diagnostic-mode resolution and configuration merging in observability recording to track phase-level success and failure.
  • Ensure exit handling consistently routes through a common finish function that can emit observability snapshots.

Documentation:

  • Extend the developers guide with the configuration observability contract, including metric names, labels, and structured log field expectations.

Tests:

  • Add observability-focused tests verifying metric recording for each config load phase and structured log fields for configuration errors.

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: aec456e1-c813-413c-8afc-85f353db51a0

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai

sourcery-ai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Adds process-level observability around the two configuration-loading phases by introducing bounded metrics, error categorization, and structured logging, and wires this into the CLI composition root and developer documentation.

Sequence diagram for configuration-load observability and metrics snapshot

sequenceDiagram
    participant Main
    participant Observability
    participant MetricsRecorder
    participant Tracing

    Main->>Tracing: init_tracing
    Main->>Observability: init_metrics
    Observability->>MetricsRecorder: DebuggingRecorder::install

    Main->>Observability: record_config_load(DIAG_MODE_PHASE)
    Observability->>MetricsRecorder: counter!(CONFIG_LOAD_COUNTER)
    Observability->>MetricsRecorder: histogram!(CONFIG_LOAD_DURATION)

    Main->>Observability: record_config_load(MERGE_PHASE)
    Observability->>MetricsRecorder: counter!(CONFIG_LOAD_COUNTER)
    Observability->>MetricsRecorder: histogram!(CONFIG_LOAD_DURATION)

    Main->>Observability: classify_error
    Main->>Tracing: tracing::error

    Main->>Observability: emit_metrics_snapshot
    Observability->>MetricsRecorder: Snapshotter::snapshot
Loading

File-Level Changes

Change Details Files
Introduce a dedicated observability module for configuration loading with bounded metrics, error classification, and recorder-backed tests.
  • Define stable metric names and phase/operation constants for configuration-load observability.
  • Install a process-wide DebuggingRecorder and snapshotter, and expose init_metrics/emit_metrics_snapshot helpers.
  • Implement record_config_load to wrap each configuration phase, timing it and recording success/failure counters and durations.
  • Implement classify_error to map OrthoError variants into low-cardinality error categories without exposing paths or messages.
  • Add unit tests validating error classification and the recorded metric shapes and labels using a local DebuggingRecorder.
src/observability.rs
Wire configuration observability into the CLI startup and config-loading paths, and emit structured error events with bounded context.
  • Register observability metrics immediately after tracing initialization in run_with_args.
  • Refactor run_with_args to capture verbose mode early and route all exit paths through a new finish_run helper that optionally emits a metrics snapshot.
  • Extend config_err_to_exit to accept an operation identifier and emit structured tracing errors including operation and error_category fields.
  • Wrap diagnostic-mode resolution and full configuration merge calls in record_config_load to capture per-phase metrics.
  • Propagate appropriate operation constants (diag_mode_resolution and config_merge) into error handling paths.
src/main.rs
Add tests to enforce the structured log-field contract for config-load errors and ensure operation/category fields are present.
  • Import OrthoError into main_tests to construct representative validation and file errors.
  • Exercise config_err_to_exit in human-readable mode for both diagnostic-mode and merge operations under a tracing subscriber with a buffering writer.
  • Assert that emitted logs contain the expected operation and error_category field values for each error type.
  • Verify that both error paths produce ExitCode::FAILURE.
src/main_tests.rs
Document the configuration observability contract and recorder usage in the developer guide.
  • Describe the ownership of configuration observability by src/observability.rs and its role at the CLI boundary.
  • Specify the metric names, label vocabulary, and outcome semantics for config_load_total and config_load_duration_seconds.
  • Explain init_metrics and emit_metrics_snapshot behavior, including process-wide recorder installation and verbose-only snapshot emission.
  • Clarify the structured logging fields (operation, error_category, error) and the requirement to keep labels low-cardinality and avoid configuration detail.
docs/developers-guide.md
Promote metrics-util from a dev-only dependency to a main dependency aligned with metrics 0.24 for production observability.
  • Move metrics-util with the debugging feature from dev-dependencies into the main dependencies section of Cargo.toml.
  • Remove the now-redundant dev-dependency comment about DebuggingRecorder being used only in tests, since it is now application-owned.
  • Ensure the metrics-util version and features remain compatible with the existing metrics crate version.
Cargo.toml

Assessment against linked issues

Issue Objective Addressed Explanation
#304 Add structured log fields to configuration-load error paths, including operation (diag_mode_resolution or config_merge) and error_category (io, parse, validation) in the handle_config_load_error / config-load error logging in src/main.rs.
#304 Introduce metrics counters for configuration-load outcomes, incremented for each config-load attempt and labeled by phase (diag_mode vs merge) and outcome (success / failure).
#304 Instrument startup latency for the configuration-load phases (from cli::resolve_merged_diag_json through cli::merge_with_config) using a duration histogram labeled by phase, and document the configuration observability contract (metric names, label conventions, buckets, and structured log fields) in docs/developers-guide.md.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@leynos

leynos commented Aug 9, 2026

Copy link
Copy Markdown
Owner

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response.

Complex Method

src/observability.rs: tests.records_each_config_load_phase_and_outcome

What lead to degradation?

tests.records_each_config_load_phase_and_outcome has a cyclomatic complexity of 15, threshold = 9

Why does this problem occur?

A Complex Method has a high cyclomatic complexity. The recommended threshold for the Rust language is a cyclomatic complexity lower than 9.

How to fix it?

There are many reasons for Complex Method. Sometimes, another design approach is beneficial such as a) modeling state using an explicit state machine rather than conditionals, or b) using table lookup rather than long chains of logic. In other scenarios, the function can be split using EXTRACT FUNCTION. Just make sure you extract natural and cohesive functions. Complex Methods can also be addressed by identifying complex conditional expressions and then using the DECOMPOSE CONDITIONAL refactoring.

Helpful refactoring examples

To get a general understanding of what this code health issue looks like - and how it might be addressed - we have prepared some diffs for illustrative purposes.

SAMPLE

# complex_method.js
 function postItem(item) {
   if (!item.id) {
-    if (item.x != null && item.y != null) {
-      post(item);
-    } else {
-      throw Error("Item must have x and y");
-    }
+    // extract a separate function for creating new item
+    postNew(item);
   } else {
-    if (item.x < 10 && item.y > 25) {
-      put(item);
-    } else {
-      throw Error("Item must have an x and y value between 10 and 25");
-    }
+    // and one for updating existing items
+    updateItem(item);
   }
 }
+
+function postNew(item) {
+  validateNew(item);
+  post(item);
+}
+
+function updateItem(item) {
+  validateUpdate(item);
+  put(item);
+}
+

@coderabbitai

This comment was marked as resolved.

leynos added 3 commits August 9, 2026 04:43
Record bounded configuration-load outcomes and durations at the CLI
boundary, and include the failing startup operation and error category in
human-readable error logs. Install the application-owned debugging recorder
so verbose runs emit a shutdown snapshot without affecting isolated tests.
Define the stable configuration-load metrics, structured log fields, recorder
lifecycle, and raw-sample histogram policy so future changes preserve the
operator-facing contract.
Satisfy the module-level test documentation contract enforced by Whitaker
so the configuration observability suite remains lint-clean.
@lodyai
lodyai Bot force-pushed the issue-304-improve-observability-of-config-load-error-paths-structured-log-fields-metrics-by-phase branch from e659ee1 to 3c73c99 Compare August 9, 2026 02:52
codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

Extract snapshot predicates from the configuration-load metric test so
each expected record remains explicit while the test scenario stays
straightforward to read.
codescene-access[bot]

This comment was marked as outdated.

@codescene-access codescene-access Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No quality gates enabled for this code.

@leynos
leynos marked this pull request as ready for review August 9, 2026 17:17

@sourcery-ai sourcery-ai Bot 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.

Sorry @leynos, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 37432ada78

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/main.rs
// The buffer was settled inside, before the branch that exits.
Err(code) => return code,
};
let verbose = parsed_cli.verbose;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Gate the snapshot on merged verbosity

When verbose mode is enabled through a configuration file or NETSUKE_VERBOSE, parsed_cli.verbose remains the pre-merge default while merged_cli.verbose becomes true. Capturing the former here and passing it to the final finish_run therefore suppresses the metrics snapshot even though the command otherwise runs in verbose mode; use the merged value after a successful merge, retaining the pre-merge value only for earlier failure paths.

Useful? React with 👍 / 👎.

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.

Improve observability of config-load error paths: structured log fields, metrics by phase

1 participant