Skip to content

feat(acp-nats): align metrics with OTEL SemConv naming#32

Merged
yordis merged 1 commit intomainfrom
feat/acp-nats-metrics
Mar 11, 2026
Merged

feat(acp-nats): align metrics with OTEL SemConv naming#32
yordis merged 1 commit intomainfrom
feat/acp-nats-metrics

Conversation

@yordis
Copy link
Member

@yordis yordis commented Mar 11, 2026

Summary

Aligns acp-nats metrics with OpenTelemetry Semantic Conventions:

  • acp.request.countacp.requests (counters must not use count; pluralize the entity)
  • acp.errors.totalacp.errors (counters must not append _total)
  • Add acp.sessions.created counter with record_session_created()
  • Add unit tests for the Metrics struct
  • Update all handler test assertions to use the new metric names

Rationale

OTEL SemConv explicitly forbids _total on counters (confusing in delta backends) and reserves count for limit-type instruments. For counters of discrete items, pluralization is preferred (e.g. system.paging.faults, system.network.packets).

Files changed

  • telemetry/metrics.rs — full replacement (renames, new counter, unit tests)
  • agent/*.rs — test assertion updates across 9 handler files
  • agent/new_session.rs — add record_session_created() call in success path

Validation

cargo build -p acp-nats
cargo test -p acp-nats --lib

All 440 tests pass.

@cursor
Copy link

cursor bot commented Mar 11, 2026

PR Summary

Medium Risk
Renames exported metric names, which can break existing dashboards/alerts and downstream metric consumers even though runtime logic changes are minimal. Adds a new session-created counter and hooks it into the new_session success path.

Overview
Aligns acp-nats OpenTelemetry counters with SemConv naming by renaming acp.request.countacp.requests and acp.errors.totalacp.errors, and updates all agent handler tests to assert on the new metric names.

Adds a new acp.sessions.created counter (Metrics::record_session_created) and records it when new_session succeeds, plus adds unit tests covering the Metrics recording APIs.

Written by Cursor Bugbot for commit f80c975. This will update automatically on new commits. Configure here.

@coderabbitai
Copy link

coderabbitai bot commented Mar 11, 2026

Walkthrough

Renames ACP metrics from acp.request.countacp.requests and acp.errors.totalacp.errors across agent handlers and tests, adds a new sessions_created counter and Metrics::record_session_created(), and invokes it after a successful NewSession response.

Changes

Cohort / File(s) Summary
Agent Handlers - Metric Renames
rsworkspace/crates/acp-nats/src/agent/authenticate.rs, rsworkspace/crates/acp-nats/src/agent/cancel.rs, rsworkspace/crates/acp-nats/src/agent/ext_method.rs, rsworkspace/crates/acp-nats/src/agent/ext_notification.rs, rsworkspace/crates/acp-nats/src/agent/initialize.rs, rsworkspace/crates/acp-nats/src/agent/load_session.rs, rsworkspace/crates/acp-nats/src/agent/prompt.rs, rsworkspace/crates/acp-nats/src/agent/set_session_mode.rs
Updated metric names and related test assertions/lookups: acp.request.countacp.requests, acp.errors.totalacp.errors. Changes are confined to metric naming, histogram/metric construction, and test messages.
New Session Handler — telemetry side-effect
rsworkspace/crates/acp-nats/src/agent/new_session.rs
After successful NewSession response, calls bridge.metrics.record_session_created(). Also updated local metric name references in tests to match renames.
Telemetry core and API
rsworkspace/crates/acp-nats/src/telemetry/metrics.rs
Metrics struct field renames: requests_totalrequests, errors_totalerrors; added sessions_created: Counter<u64>; Metrics::new registers acp.requests, acp.errors, and new acp.sessions.created; added pub fn record_session_created(&self); adjusted record_request/record_error to use renamed fields and added unit tests for new behavior.
Manifests / Cargo updates (tests or feature wiring)
Cargo.toml (various crates)
Updated manifest entries referenced by tests or new metric additions where applicable.

Sequence Diagram(s)

sequenceDiagram
    participant Client as "Client"
    participant Handler as "NewSessionHandler"
    participant Bridge as "Bridge"
    participant Metrics as "Metrics"
    participant Exporter as "Telemetry Exporter"

    Client->>Handler: send NewSession request
    Handler->>Bridge: process NewSession
    alt NewSession success
        Bridge->>Metrics: record_request(duration, success)
        Bridge->>Metrics: record_session_created()
        Metrics->>Exporter: increment `acp.sessions.created`
        Metrics->>Exporter: increment `acp.requests`/record duration
    else failure
        Bridge->>Metrics: record_error()
        Metrics->>Exporter: increment `acp.errors`
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 A hop, a counter, a tiny cheer,
acp.requests now rings so clear.
acp.errors watches every fall,
and sessions bloom — I counted all.
Thump-thump—metrics hop, I sing with glee!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 58.62% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: aligning metrics with OpenTelemetry Semantic Conventions naming. It clearly reflects the primary objective and is specific to the changeset.
Description check ✅ Passed The description is well-organized and clearly related to the changeset. It explains the metric renaming, rationale, affected files, and validation steps performed.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/acp-nats-metrics

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions
Copy link

github-actions bot commented Mar 11, 2026

badge

Code Coverage Summary

Details
Filename                                                     Stmts    Miss  Cover    Missing
---------------------------------------------------------  -------  ------  -------  --------------------------------------------
crates/trogon-std/src/dirs/fixed.rs                             84       0  100.00%
crates/trogon-std/src/dirs/system.rs                            98      11  88.78%   57, 65, 67, 75, 77, 85, 87, 96, 98, 109, 154
crates/trogon-std/src/fs/system.rs                              29      12  58.62%   17-19, 31-45
crates/trogon-std/src/fs/mem.rs                                220      10  95.45%   61-63, 77-79, 133-135, 158
crates/trogon-std/src/time/system.rs                            24       0  100.00%
crates/trogon-std/src/time/mock.rs                             123       0  100.00%
crates/acp-nats/src/client/fs_read_text_file.rs                384       0  100.00%
crates/acp-nats/src/client/terminal_release.rs                 357       0  100.00%
crates/acp-nats/src/client/ext_session_prompt_response.rs      145       0  100.00%
crates/acp-nats/src/client/mod.rs                             2977       0  100.00%
crates/acp-nats/src/client/terminal_wait_for_exit.rs           396       0  100.00%
crates/acp-nats/src/client/fs_write_text_file.rs               451       0  100.00%
crates/acp-nats/src/client/rpc_reply.rs                         71       0  100.00%
crates/acp-nats/src/client/terminal_kill.rs                    311       0  100.00%
crates/acp-nats/src/client/request_permission.rs               338       0  100.00%
crates/acp-nats/src/client/session_update.rs                    54       0  100.00%
crates/acp-nats/src/client/terminal_create.rs                  294       0  100.00%
crates/acp-nats/src/client/terminal_output.rs                  359       0  100.00%
crates/acp-nats/src/nats/extensions.rs                           3       0  100.00%
crates/acp-nats/src/nats/subjects.rs                           155       0  100.00%
crates/acp-nats/src/nats/token.rs                                8       0  100.00%
crates/acp-nats/src/nats/parsing.rs                            104       0  100.00%
crates/acp-nats/src/nats/client_method.rs                       14       0  100.00%
crates/trogon-std/src/json.rs                                   30       0  100.00%
crates/trogon-std/src/env/in_memory.rs                          76       3  96.05%   48-50
crates/trogon-std/src/env/system.rs                             17       0  100.00%
crates/acp-nats/src/agent/new_session.rs                       313       0  100.00%
crates/acp-nats/src/agent/cancel.rs                            197       0  100.00%
crates/acp-nats/src/agent/ext_method.rs                        289       0  100.00%
crates/acp-nats/src/agent/prompt.rs                            578       0  100.00%
crates/acp-nats/src/agent/set_session_mode.rs                  219       0  100.00%
crates/acp-nats/src/agent/ext_notification.rs                  222       0  100.00%
crates/acp-nats/src/agent/mod.rs                                36       0  100.00%
crates/acp-nats/src/agent/load_session.rs                      330       0  100.00%
crates/acp-nats/src/agent/initialize.rs                        196       2  98.98%   113, 118
crates/acp-nats/src/agent/authenticate.rs                      180       2  98.89%   106, 111
crates/acp-nats/src/telemetry/metrics.rs                        93       0  100.00%
crates/acp-nats/src/in_flight_slot_guard.rs                     32       0  100.00%
crates/acp-nats/src/prompt_slot_counter.rs                      78       0  100.00%
crates/acp-nats/src/jsonrpc.rs                                   6       0  100.00%
crates/acp-nats/src/config.rs                                   82       0  100.00%
crates/acp-nats/src/pending_prompt_waiters.rs                  160       0  100.00%
crates/acp-nats/src/session_id.rs                               88       0  100.00%
crates/acp-nats/src/ext_method_name.rs                          85       0  100.00%
crates/acp-nats/src/acp_prefix.rs                               63       0  100.00%
crates/trogon-nats/src/connect.rs                               96      16  83.33%   21-23, 36, 50, 69-152
crates/trogon-nats/src/messaging.rs                            507      12  97.63%   14-16, 51-52, 135-140, 150-151, 203-205
crates/trogon-nats/src/client.rs                                25      25  0.00%    50-89
crates/trogon-nats/src/auth.rs                                 114       3  97.37%   49-51
crates/trogon-nats/src/mocks.rs                                291       0  100.00%
TOTAL                                                        11402      96  99.16%

Diff against main

Filename                                    Stmts    Miss  Cover
----------------------------------------  -------  ------  --------
crates/acp-nats/src/telemetry/metrics.rs      +61       0  +100.00%
TOTAL                                         +61       0  +0.00%

Results for commit: f80c975

Minimum allowed coverage is 95%

♻️ This comment has been updated with latest results

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
rsworkspace/crates/acp-nats/src/telemetry/metrics.rs (1)

83-158: Consider strengthening test assertions to verify actual metric names.

The current tests only verify that metrics are non-empty after recording. They don't confirm that the correct metric names (acp.requests, acp.errors, acp.sessions.created) were actually emitted. This gap is covered by the handler-level tests, but unit tests here could provide stronger guarantees.

Example: Verify metric name in test_metrics_record_session_created
 #[tokio::test]
 async fn test_metrics_record_session_created() {
     let (metrics, exporter, provider) = create_test_metrics();

     metrics.record_session_created();

     provider.force_flush().unwrap();

     let finished_metrics = exporter.get_finished_metrics().unwrap();
-    assert!(!finished_metrics.is_empty());
+    assert!(!finished_metrics.is_empty());
+    let has_sessions_metric = finished_metrics
+        .iter()
+        .flat_map(|rm| rm.scope_metrics())
+        .flat_map(|sm| sm.metrics())
+        .any(|m| m.name() == "acp.sessions.created");
+    assert!(has_sessions_metric, "expected acp.sessions.created metric");

     provider.shutdown().unwrap();
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rsworkspace/crates/acp-nats/src/telemetry/metrics.rs` around lines 83 - 158,
Update the tests to assert that the expected metric names are present in the
exported metrics rather than only checking non-empty; for each test
(test_metrics_record_request_success, test_metrics_record_request_failure,
test_metrics_record_session_created, test_metrics_record_error,
test_metrics_multiple_recordings) iterate finished_metrics returned by
exporter.get_finished_metrics() and assert that at least one metric has the
expected name (e.g. "acp.requests" for record_request calls, "acp.errors" for
record_error, "acp.sessions.created" for record_session_created), keeping the
existing force_flush()/provider.shutdown() usage.
rsworkspace/crates/acp-nats/src/agent/new_session.rs (1)

85-85: Assert the new acp.sessions.created side effect in this handler.

Line 85 is the behavior added by this PR, but the tests in this file still only verify acp.requests / acp.errors. If this call is dropped later, the Metrics unit tests can still pass while the new_session path regresses silently.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rsworkspace/crates/acp-nats/src/agent/new_session.rs` at line 85, The
new_session handler now calls bridge.metrics.record_session_created(), but the
tests in this file only assert acp.requests/acp.errors; update the existing
new_session tests to also assert the acp.sessions.created side effect by
checking that bridge.metrics.record_session_created was called (or that the
acp.sessions.created metric was emitted/incremented) after invoking the handler;
locate usages of bridge.metrics.record_session_created in new_session.rs and add
an assertion in the corresponding test(s) that inspects the metrics sink/mock
(or the published acp.sessions.created event) to ensure the call happened.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@rsworkspace/crates/acp-nats/src/agent/new_session.rs`:
- Line 85: The new_session handler now calls
bridge.metrics.record_session_created(), but the tests in this file only assert
acp.requests/acp.errors; update the existing new_session tests to also assert
the acp.sessions.created side effect by checking that
bridge.metrics.record_session_created was called (or that the
acp.sessions.created metric was emitted/incremented) after invoking the handler;
locate usages of bridge.metrics.record_session_created in new_session.rs and add
an assertion in the corresponding test(s) that inspects the metrics sink/mock
(or the published acp.sessions.created event) to ensure the call happened.

In `@rsworkspace/crates/acp-nats/src/telemetry/metrics.rs`:
- Around line 83-158: Update the tests to assert that the expected metric names
are present in the exported metrics rather than only checking non-empty; for
each test (test_metrics_record_request_success,
test_metrics_record_request_failure, test_metrics_record_session_created,
test_metrics_record_error, test_metrics_multiple_recordings) iterate
finished_metrics returned by exporter.get_finished_metrics() and assert that at
least one metric has the expected name (e.g. "acp.requests" for record_request
calls, "acp.errors" for record_error, "acp.sessions.created" for
record_session_created), keeping the existing force_flush()/provider.shutdown()
usage.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7c061e0c-e4d0-4cd4-980b-6e282edf980c

📥 Commits

Reviewing files that changed from the base of the PR and between 1e2a8f6 and 83b08a4.

📒 Files selected for processing (10)
  • rsworkspace/crates/acp-nats/src/agent/authenticate.rs
  • rsworkspace/crates/acp-nats/src/agent/cancel.rs
  • rsworkspace/crates/acp-nats/src/agent/ext_method.rs
  • rsworkspace/crates/acp-nats/src/agent/ext_notification.rs
  • rsworkspace/crates/acp-nats/src/agent/initialize.rs
  • rsworkspace/crates/acp-nats/src/agent/load_session.rs
  • rsworkspace/crates/acp-nats/src/agent/new_session.rs
  • rsworkspace/crates/acp-nats/src/agent/prompt.rs
  • rsworkspace/crates/acp-nats/src/agent/set_session_mode.rs
  • rsworkspace/crates/acp-nats/src/telemetry/metrics.rs

- Rename acp.request.count -> acp.requests (counters must not use count)
- Rename acp.errors.total -> acp.errors (counters must not use _total)
- Add acp.sessions.created counter and record_session_created()
- Add unit tests for Metrics struct
- Update all handler test assertions to use new metric names

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis yordis force-pushed the feat/acp-nats-metrics branch from 83b08a4 to f80c975 Compare March 11, 2026 05:01
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
rsworkspace/crates/acp-nats/src/agent/new_session.rs (1)

81-85: Cover the new session counter at the call site.

record_session_created() is the new behavior in this PR, but the surrounding tests still only assert acp.requests/acp.errors. Please add a success-path assertion for acp.sessions.created and a failure-path negative check so this wiring cannot regress silently.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rsworkspace/crates/acp-nats/src/agent/new_session.rs` around lines 81 - 85,
Tests need to assert the new session counter is updated at the call site where
bridge.metrics.record_session_created() is invoked; update the success-path
tests that hit the Ok branch (the code around new_session.rs where result is
matched and record_session_created() is called) to assert that the metric
"acp.sessions.created" increments (or equals expected value) after a successful
create, and update the failure-path tests that exercise the Err branch to assert
that "acp.sessions.created" does not increment (negative check). Ensure you
reference the bridge.metrics.record_session_created() call when adding these
assertions so the wiring cannot regress.
rsworkspace/crates/acp-nats/src/telemetry/metrics.rs (2)

83-157: Assert the concrete metric contract in these tests.

These tests only check finished_metrics.is_empty(). They still pass if record_request() only emits the histogram, or if record_session_created() increments the wrong counter. Please assert the emitted metric names/data points (acp.requests, acp.request.duration, acp.sessions.created, acp.errors) so the rename is actually protected.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rsworkspace/crates/acp-nats/src/telemetry/metrics.rs` around lines 83 - 157,
Update the tests to assert the concrete metric names and datapoints instead of
only checking finished_metrics.is_empty(): after calling create_test_metrics()
and invoking metrics.record_request / record_session_created / record_error
(e.g., in test_metrics_record_request_success,
test_metrics_record_request_failure, test_metrics_record_session_created,
test_metrics_record_error, test_metrics_multiple_recordings) call
provider.force_flush() and then inspect exporter.get_finished_metrics() to
verify it contains metrics with the expected instrument names "acp.requests",
"acp.request.duration", "acp.sessions.created", and "acp.errors" and that their
datapoints reflect the recorded values (counter increments for
requests/sessions/errors and a histogram/summary with the recorded duration for
request.duration). Use the exporter/finished metric objects’ name and datapoint
fields to assert exact counts and duration values for each specific test so
renames or missing emissions would fail.

15-31: Coordinate the observability rollout with this rename.

Removing acp.request.count and acp.errors.total outright will blank any dashboards, alerts, or collector transforms that still query the old names. Please ship the matching observability config updates with this rollout, or keep a short-lived compatibility mapping during the cutover.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rsworkspace/crates/acp-nats/src/telemetry/metrics.rs` around lines 15 - 31,
The diff renames metrics (new instruments requests, errors) which will break
dashboards expecting acp.request.count and acp.errors.total; either update the
observability configs (dashboards/collector transforms/alerts) to use the new
names or add short-lived compatibility metrics by also creating instruments with
the old names (e.g., build u64_counter("acp.request.count") and
u64_counter("acp.errors.total") and increment them alongside requests and errors
in the same code paths) so both sets exist during the cutover; ensure the legacy
instruments are clearly marked for removal and coordinate the rollout with the
observability team.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@rsworkspace/crates/acp-nats/src/agent/new_session.rs`:
- Around line 81-85: Tests need to assert the new session counter is updated at
the call site where bridge.metrics.record_session_created() is invoked; update
the success-path tests that hit the Ok branch (the code around new_session.rs
where result is matched and record_session_created() is called) to assert that
the metric "acp.sessions.created" increments (or equals expected value) after a
successful create, and update the failure-path tests that exercise the Err
branch to assert that "acp.sessions.created" does not increment (negative
check). Ensure you reference the bridge.metrics.record_session_created() call
when adding these assertions so the wiring cannot regress.

In `@rsworkspace/crates/acp-nats/src/telemetry/metrics.rs`:
- Around line 83-157: Update the tests to assert the concrete metric names and
datapoints instead of only checking finished_metrics.is_empty(): after calling
create_test_metrics() and invoking metrics.record_request /
record_session_created / record_error (e.g., in
test_metrics_record_request_success, test_metrics_record_request_failure,
test_metrics_record_session_created, test_metrics_record_error,
test_metrics_multiple_recordings) call provider.force_flush() and then inspect
exporter.get_finished_metrics() to verify it contains metrics with the expected
instrument names "acp.requests", "acp.request.duration", "acp.sessions.created",
and "acp.errors" and that their datapoints reflect the recorded values (counter
increments for requests/sessions/errors and a histogram/summary with the
recorded duration for request.duration). Use the exporter/finished metric
objects’ name and datapoint fields to assert exact counts and duration values
for each specific test so renames or missing emissions would fail.
- Around line 15-31: The diff renames metrics (new instruments requests, errors)
which will break dashboards expecting acp.request.count and acp.errors.total;
either update the observability configs (dashboards/collector transforms/alerts)
to use the new names or add short-lived compatibility metrics by also creating
instruments with the old names (e.g., build u64_counter("acp.request.count") and
u64_counter("acp.errors.total") and increment them alongside requests and errors
in the same code paths) so both sets exist during the cutover; ensure the legacy
instruments are clearly marked for removal and coordinate the rollout with the
observability team.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cc767290-f871-4859-8ad4-8de54b6937ba

📥 Commits

Reviewing files that changed from the base of the PR and between 83b08a4 and f80c975.

📒 Files selected for processing (10)
  • rsworkspace/crates/acp-nats/src/agent/authenticate.rs
  • rsworkspace/crates/acp-nats/src/agent/cancel.rs
  • rsworkspace/crates/acp-nats/src/agent/ext_method.rs
  • rsworkspace/crates/acp-nats/src/agent/ext_notification.rs
  • rsworkspace/crates/acp-nats/src/agent/initialize.rs
  • rsworkspace/crates/acp-nats/src/agent/load_session.rs
  • rsworkspace/crates/acp-nats/src/agent/new_session.rs
  • rsworkspace/crates/acp-nats/src/agent/prompt.rs
  • rsworkspace/crates/acp-nats/src/agent/set_session_mode.rs
  • rsworkspace/crates/acp-nats/src/telemetry/metrics.rs
🚧 Files skipped from review as they are similar to previous changes (5)
  • rsworkspace/crates/acp-nats/src/agent/initialize.rs
  • rsworkspace/crates/acp-nats/src/agent/cancel.rs
  • rsworkspace/crates/acp-nats/src/agent/load_session.rs
  • rsworkspace/crates/acp-nats/src/agent/ext_notification.rs
  • rsworkspace/crates/acp-nats/src/agent/prompt.rs

@yordis yordis merged commit 569d2a8 into main Mar 11, 2026
4 checks passed
@yordis yordis deleted the feat/acp-nats-metrics branch March 11, 2026 05:46
yordis added a commit that referenced this pull request Mar 13, 2026
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
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.

1 participant