-
Notifications
You must be signed in to change notification settings - Fork 0
Implement metrics & observability #213
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
leynos
merged 10 commits into
main
from
codex/implement-metrics-and-observability-feature
Jul 24, 2025
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
11b7c6e
Add metrics instrumentation and Prometheus example
leynos cd5becd
Gate metrics behind feature
leynos 18189be
Add module docs for metrics tests
leynos b0dc759
Fix docs wording and format metrics test
leynos aeb4205
Add metrics ER diagram
leynos 817ad0d
Update toolchain and fix unused structs
leynos 24dab39
Refine metrics tests and docs
leynos 840bdaa
Format inbound metrics test
leynos b607d09
Use expect for dead code
leynos 6f71257
Add doc comment for EmptyPreamble and tidy metrics test
leynos File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| [toolchain] | ||
| channel = "nightly-2025-06-10" | ||
| channel = "nightly-2025-07-22" | ||
| components = ["rustfmt", "clippy"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| //! Metric helpers for `wireframe`. | ||
| //! | ||
| //! This module defines metric names and helper functions wrapping the | ||
| //! [`metrics`](https://docs.rs/metrics) crate. All functions become no-ops | ||
| //! if the optional `metrics` Cargo feature is disabled. | ||
| //! | ||
| //! # Prometheus Integration | ||
| //! | ||
| //! ``` | ||
| //! use metrics_exporter_prometheus::PrometheusBuilder; | ||
| //! | ||
| //! let handle = PrometheusBuilder::new() | ||
| //! .install_recorder() | ||
| //! .expect("recorder install"); | ||
| //! println!("{}", handle.render()); | ||
| //! ``` | ||
|
|
||
| #[cfg(feature = "metrics")] | ||
| use metrics::{counter, gauge}; | ||
|
|
||
| /// Name of the gauge tracking active connections. | ||
| pub const CONNECTIONS_ACTIVE: &str = "wireframe_connections_active"; | ||
| /// Name of the counter tracking processed frames. | ||
| pub const FRAMES_PROCESSED: &str = "wireframe_frames_processed_total"; | ||
| /// Name of the counter tracking error occurrences. | ||
| pub const ERRORS_TOTAL: &str = "wireframe_errors_total"; | ||
|
|
||
| /// Direction of frame processing. | ||
| #[derive(Clone, Copy)] | ||
| pub enum Direction { | ||
| /// Inbound frames received from a client. | ||
| Inbound, | ||
| /// Outbound frames sent to a client. | ||
| Outbound, | ||
| } | ||
|
|
||
| impl Direction { | ||
| fn as_str(self) -> &'static str { | ||
| match self { | ||
| Direction::Inbound => "inbound", | ||
| Direction::Outbound => "outbound", | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// Increment the active connections gauge. | ||
| #[cfg(feature = "metrics")] | ||
| pub fn inc_connections() { gauge!(CONNECTIONS_ACTIVE).increment(1.0); } | ||
|
|
||
| #[cfg(not(feature = "metrics"))] | ||
| pub fn inc_connections() {} | ||
|
|
||
| /// Decrement the active connections gauge. | ||
| #[cfg(feature = "metrics")] | ||
| pub fn dec_connections() { gauge!(CONNECTIONS_ACTIVE).decrement(1.0); } | ||
|
|
||
| #[cfg(not(feature = "metrics"))] | ||
| pub fn dec_connections() {} | ||
|
|
||
| /// Record a processed frame for the given direction. | ||
| #[cfg(feature = "metrics")] | ||
| pub fn inc_frames(direction: Direction) { | ||
| counter!(FRAMES_PROCESSED, "direction" => direction.as_str()).increment(1); | ||
| } | ||
|
|
||
| #[cfg(not(feature = "metrics"))] | ||
| pub fn inc_frames(_direction: Direction) {} | ||
|
|
||
| /// Record a deserialization error. | ||
| #[cfg(feature = "metrics")] | ||
| pub fn inc_deser_errors() { counter!(ERRORS_TOTAL, "kind" => "deserialization").increment(1); } | ||
|
|
||
| #[cfg(not(feature = "metrics"))] | ||
| pub fn inc_deser_errors() {} | ||
|
|
||
| /// Record a handler error. | ||
| #[cfg(feature = "metrics")] | ||
| pub fn inc_handler_errors() { counter!(ERRORS_TOTAL, "kind" => "handler").increment(1); } | ||
|
|
||
| #[cfg(not(feature = "metrics"))] | ||
| pub fn inc_handler_errors() {} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| //! Tests for `wireframe` metrics helpers. | ||
| //! | ||
| //! These tests verify that counters and gauges update as expected using | ||
| //! `metrics_util::debugging::DebuggingRecorder`. | ||
| use metrics_util::debugging::{DebugValue, DebuggingRecorder, Snapshotter}; | ||
|
|
||
| /// Creates a debugging recorder and snapshotter for metrics testing. | ||
| fn debugging_recorder_setup() -> (Snapshotter, DebuggingRecorder) { | ||
| let recorder = DebuggingRecorder::new(); | ||
| let snapshotter = recorder.snapshotter(); | ||
| (snapshotter, recorder) | ||
| } | ||
|
|
||
| #[test] | ||
| fn outbound_frame_metric_increments() { | ||
| let (snapshotter, recorder) = debugging_recorder_setup(); | ||
| metrics::with_local_recorder(&recorder, || { | ||
| wireframe::metrics::inc_frames(wireframe::metrics::Direction::Outbound); | ||
| }); | ||
|
|
||
| let metrics = snapshotter.snapshot().into_vec(); | ||
| let found = metrics.iter().any(|(k, _, _, v)| { | ||
| k.key().name() == wireframe::metrics::FRAMES_PROCESSED | ||
| && k.key() | ||
| .labels() | ||
| .any(|l| l.key() == "direction" && l.value() == "outbound") | ||
| && matches!(v, DebugValue::Counter(c) if *c > 0) | ||
| }); | ||
| assert!(found, "outbound frames metric not recorded"); | ||
| } | ||
|
|
||
| #[test] | ||
| fn inbound_frame_metric_increments() { | ||
| let (snapshotter, recorder) = debugging_recorder_setup(); | ||
| metrics::with_local_recorder(&recorder, || { | ||
| wireframe::metrics::inc_frames(wireframe::metrics::Direction::Inbound); | ||
| }); | ||
| let metrics = snapshotter.snapshot().into_vec(); | ||
| let found = metrics.iter().any(|(k, _, _, v)| { | ||
| k.key().name() == wireframe::metrics::FRAMES_PROCESSED | ||
| && k.key() | ||
| .labels() | ||
| .any(|l| l.key() == "direction" && l.value() == "inbound") | ||
| && matches!(v, DebugValue::Counter(c) if *c > 0) | ||
| }); | ||
|
|
||
| assert!(found, "inbound frames metric not recorded"); | ||
| } | ||
|
|
||
| #[test] | ||
| fn error_metric_increments() { | ||
| let (snapshotter, recorder) = debugging_recorder_setup(); | ||
| metrics::with_local_recorder(&recorder, || { | ||
| wireframe::metrics::inc_deser_errors(); | ||
| }); | ||
|
|
||
| let metrics = snapshotter.snapshot().into_vec(); | ||
| let found = metrics.iter().any(|(k, _, _, v)| { | ||
| k.key().name() == wireframe::metrics::ERRORS_TOTAL | ||
| && matches!(v, DebugValue::Counter(c) if *c > 0) | ||
| }); | ||
| assert!(found, "error metric not recorded"); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,3 +11,4 @@ bytes = "^1.0" | |
| rstest = "0.18.2" | ||
| logtest = "2" | ||
| log = "0.4" | ||
| metrics-util = "0.20" | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.