Skip to content

Add Prometheus metrics export (issue 60)#81

Closed
joaquinbejar wants to merge 4 commits intomainfrom
issue-60-metrics
Closed

Add Prometheus metrics export (issue 60)#81
joaquinbejar wants to merge 4 commits intomainfrom
issue-60-metrics

Conversation

@joaquinbejar
Copy link
Copy Markdown
Owner

Added optional metrics feature to export Prometheus counters. See issue 60.

Issue #60. Adds an optional `metrics` cargo feature (off by default)
that wires Prometheus-style observability into the matching engine
without affecting matching latency or determinism.

This commit lands the feature scaffolding plus the reject-counter
surface; depth and trade counters land in the next commit.

Surface
- `metrics = "0.24"` is the new optional dependency.
- `feature = "metrics"` enables it.
- New `orderbook::metrics` module with feature-gated helpers that
  compile to no-ops when the feature is disabled, so call-sites in
  the matching hot path stay unconditional.
- `orderbook_rejects_total{reason="..."}` counter — incremented
  exactly once per rejection. Hooked at the single chokepoint
  `OrderBook::track_state` (every `OrderStatus::Rejected` transition
  emits) plus the cold rejection sites that bypass `track_state`
  (lot-size, min/max range, IOC/FOK insufficient-liquidity, market
  order on empty book, STP cancel-taker). The label value is the
  `RejectReason::Display` string.

Constraints respected
- Allocation-free on the happy path.
- No influence on matching outcomes.
- `restore_from_snapshot_package` does not rehydrate metric
  counters.
- `#[deny(unsafe_code)]` still on; no new unsafe.
Issue #60. Adds the remaining two operational metrics on top of the
reject counter from the previous commit, plus the integration test
binary that exercises all three.

Surface
- `orderbook_depth_levels_bid` / `orderbook_depth_levels_ask` —
  gauges, current count of distinct bid / ask price levels. Hooked
  via a new `OrderBook::record_depth_metric` helper that reads
  `self.bids.len()` / `self.asks.len()` (`SkipMap::len` is O(1)) and
  forwards to `metrics::record_depth`. Refreshed on every structural
  mutation: `place_order_in_book`, `add_order` resting insertion,
  cancel-driven level removal, modify-path level removal, matching
  empty-level cleanup, and `cancel_all_orders` bulk drain.
- `orderbook_trades_total` — counter, incremented exactly once per
  emitted `MatchResult` transaction. Hooked at all three trade
  emission sites (`match_market_order_with_user`,
  `match_limit_order_with_user`, `add_order` matching path). The
  counter increments independently of whether a `TradeListener` is
  configured.

Testing
- New dedicated test binary `tests/metrics/` (gated on
  `required-features = ["metrics"]`) with three integration tests:
  reject + trade counters, depth gauges across add / cancel, and a
  determinism guard that confirms metrics emission produces
  byte-identical snapshots.
- The metrics tests live in their own binary so the broader
  integration suite under `tests/unit/` doesn't perturb the global
  recorder via routine `OrderBook` mutations.
Issue #60. Adds a runnable example that demonstrates the optional
`metrics` feature end-to-end:

1. Installs the `metrics-exporter-prometheus` recorder.
2. Builds an `OrderBook<()>`, seeds resting depth, crosses a few
   limit orders to print trades, then engages the kill switch and
   submits one order to force a reject.
3. Calls `PrometheusHandle::render()` and prints the exposition
   payload to stdout, showing all four metric series:
   `orderbook_rejects_total{reason="..."}`,
   `orderbook_trades_total`,
   `orderbook_depth_levels_bid`, `orderbook_depth_levels_ask`.

The example is gated behind `required-features = ["metrics"]` and
the examples crate gains a feature pass-through:

    metrics = ["orderbook-rs/metrics", "dep:metrics",
               "dep:metrics-exporter-prometheus"]

`metrics = "0.24"` and `metrics-exporter-prometheus = "0.18"` are
the new optional dev-dependencies on the examples crate. They do
not affect the library crate.

Run with:

    cd examples
    cargo run --features metrics --bin prometheus_export
Issue #60. Closes the documentation surface for the new optional
`metrics` feature.

- `CHANGELOG.md` gets a new "Added — Prometheus metrics feature
  (#60)" subsection under the unreleased `0.7.0` umbrella with the
  full surface (counters, gauges, label semantics) and the
  determinism / no-op-when-disabled guarantees.
- `src/lib.rs` gains a "v0.7.0 — Metrics and Observability (#60)"
  block in the crate-level "What's New" section. Cross-references
  the helper module, the example binary, and the test binary.
@joaquinbejar joaquinbejar added the enhancement New feature or request label Apr 25, 2026
@joaquinbejar joaquinbejar self-assigned this Apr 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant