Skip to content

Commit 80f8352

Browse files
authored
feat: summary metric (#47)
2 parents 2099680 + 5837ce5 commit 80f8352

File tree

19 files changed

+2683
-388
lines changed

19 files changed

+2683
-388
lines changed

Cargo.lock

Lines changed: 1031 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 14 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -18,51 +18,32 @@ instead of [metrics](https://docs.rs/metrics/latest/metrics), and supports dynam
1818

1919
### Basic Usage
2020

21-
```rust
22-
use prometric_derive::metrics;
23-
use prometric::{Counter, Gauge, Histogram};
21+
See [`basic_usage`](./prometric-derive/examples/basic_usage.rs) example for usage. Here's a reduced example usage:
2422

23+
``` rust
2524
// The `scope` attribute is used to set the prefix for the metric names in this struct.
2625
#[metrics(scope = "app")]
2726
struct AppMetrics {
2827
/// The total number of HTTP requests.
2928
#[metric(rename = "http_requests_total", labels = ["method", "path"])]
3029
http_requests: Counter,
31-
32-
// For histograms, the `buckets` attribute is optional. It will default to [prometheus::DEFAULT_BUCKETS] if not provided.
33-
// `buckets` can also be an expression that evaluates into a `Vec<f64>`.
34-
/// The duration of HTTP requests.
35-
#[metric(labels = ["method", "path"], buckets = [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0])]
36-
http_requests_duration: Histogram,
37-
38-
/// This doc comment will be overwritten by the `help` attribute.
39-
#[metric(rename = "current_active_users", labels = ["service"], help = "The current number of active users.")]
40-
current_users: Gauge,
41-
42-
/// The balance of the account, in dollars. Uses a floating point number.
43-
#[metric(rename = "account_balance", labels = ["account_id"])]
44-
account_balance: Gauge<f64>,
45-
46-
/// The total number of errors.
47-
#[metric]
48-
errors: Counter,
4930
}
5031

51-
// Build the metrics struct with static labels, which will initialize and register the metrics with the default registry.
52-
// A custom registry can be used by passing it to the builder using `with_registry`.
53-
let metrics = AppMetrics::builder().with_label("host", "localhost").with_label("port", "8080").build();
32+
// Build the metrics struct with static labels, which will initialize and register the metrics
33+
// with the default registry. A custom registry can be used by passing it to the builder
34+
// using `with_registry`.
35+
let metrics =
36+
AppMetrics::builder().with_label("host", "localhost").with_label("port", "8080").build();
5437

55-
// Metric fields each get an accessor method generated, which can be used to interact with the metric.
56-
// The arguments to the accessor method are the labels for the metric.
38+
// Metric fields each get an accessor method generated, which can be used to interact with the
39+
// metric. The arguments to the accessor method are the labels for the metric.
5740
metrics.http_requests("GET", "/").inc();
58-
metrics.http_requests_duration("GET", "/").observe(1.0);
59-
metrics.current_users("service-1").set(10);
60-
metrics.account_balance("1234567890").set(-12.2);
61-
metrics.errors().inc();
6241
```
6342

6443
#### Sample Output
6544

45+
TODO: document how to obtain sample output
46+
6647
```text
6748
# HELP app_account_balance The balance of the account, in dollars. Uses a floating point number.
6849
# TYPE app_account_balance gauge
@@ -102,47 +83,13 @@ app_http_requests_total{host="localhost",method="POST",path="/",port="8080"} 2
10283

10384
You can also generate a static `LazyLock` instance by using the `static` attribute. When enabled, the builder methods and `Default` implementation are made private, ensuring the only way to access the metrics is through the static instance:
10485

105-
```rust
106-
use prometric_derive::metrics;
107-
use prometric::{Counter, Gauge};
108-
109-
#[metrics(scope = "app", static)]
110-
struct AppMetrics {
111-
/// The total number of requests.
112-
#[metric(labels = ["method"])]
113-
requests: Counter,
114-
115-
/// The current number of active connections.
116-
#[metric]
117-
active_connections: Gauge,
118-
}
119-
120-
// Use the static directly (the name is APP_METRICS in SCREAMING_SNAKE_CASE)
121-
APP_METRICS.requests("GET").inc();
122-
APP_METRICS.active_connections().set(10);
123-
124-
// The following would not compile:
125-
// let metrics = AppMetrics::builder(); // Error: builder() is private
126-
// let metrics = AppMetrics::default(); // Error: Default is not implemented
127-
```
86+
See [`static_metrics`](./prometric-derive/examples/static_metrics.rs) example for usage.
12887

12988
### Exporting Metrics
13089

131-
An HTTP exporter is provided by [`prometric::exporter::ExporterBuilder`]. Usage:
90+
An HTTP exporter is provided by [`prometric::exporter::ExporterBuilder`].
13291

133-
```rust
134-
use prometric::exporter::ExporterBuilder;
135-
136-
ExporterBuilder::new()
137-
// Specify the address to listen on
138-
.with_address("127.0.0.1:9090")
139-
// Set the global namespace for the metrics (usually the name of the application)
140-
.with_namespace("exporter")
141-
// Install the exporter. This will start an HTTP server and serve metrics on the specified
142-
// address.
143-
.install()
144-
.expect("Failed to install exporter");
145-
```
92+
See [`exporter`](./prometric-derive/examples/exporter.rs) example for usage.
14693

14794
### Process Metrics
14895

justfile

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
default: check doc fmt clippy
2+
3+
check:
4+
cargo check --workspace --all-features --all-targets
5+
6+
doc:
7+
cargo doc --workspace --all-features --no-deps --document-private-items
8+
9+
clippy:
10+
cargo +nightly clippy --all --all-features -- -D warnings
11+
12+
fmt:
13+
cargo +nightly fmt --all -- --check
14+
15+
test:
16+
cargo nextest run --workspace --all-features --retries 3
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
use prometric::{Counter, Gauge, Histogram, Summary};
2+
use prometric_derive::metrics;
3+
4+
// The `scope` attribute is used to set the prefix for the metric names in this struct.
5+
#[metrics(scope = "app")]
6+
struct AppMetrics {
7+
/// The total number of HTTP requests.
8+
#[metric(rename = "http_requests_total", labels = ["method", "path"])]
9+
http_requests: Counter,
10+
11+
// For histograms, the `buckets` attribute is optional. It will default to
12+
// [prometheus::DEFAULT_BUCKETS] if not provided. `buckets` can also be an expression that
13+
// evaluates into a `Vec<f64>`.
14+
/// The duration of HTTP requests.
15+
#[metric(labels = ["method", "path"], buckets = [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0])]
16+
http_requests_duration: Histogram,
17+
18+
/// The size fo HTTP requests.
19+
#[metric(labels = ["method", "path"], quantiles = [0.0, 0.5, 0.9, 0.95, 0.99, 0.999, 1.0])]
20+
http_request_sizes: Summary,
21+
22+
/// This doc comment will be overwritten by the `help` attribute.
23+
#[metric(rename = "current_active_users", labels = ["service"], help = "The current number of active users.")]
24+
current_users: Gauge,
25+
26+
/// The balance of the account, in dollars. Uses a floating point number.
27+
#[metric(rename = "account_balance", labels = ["account_id"])]
28+
account_balance: Gauge<f64>,
29+
30+
/// The total number of errors.
31+
#[metric]
32+
errors: Counter,
33+
}
34+
35+
#[tokio::main(flavor = "current_thread")]
36+
async fn main() {
37+
// Build the metrics struct with static labels, which will initialize and register the metrics
38+
// with the default registry. A custom registry can be used by passing it to the builder
39+
// using `with_registry`.
40+
let metrics =
41+
AppMetrics::builder().with_label("host", "localhost").with_label("port", "8080").build();
42+
43+
// Metric fields each get an accessor method generated, which can be used to interact with the
44+
// metric. The arguments to the accessor method are the labels for the metric.
45+
metrics.http_requests("GET", "/").inc();
46+
metrics.http_requests_duration("GET", "/").observe(1.0);
47+
metrics.http_request_sizes("GET", "/").observe(12345);
48+
metrics.current_users("service-1").set(10);
49+
metrics.account_balance("1234567890").set(-12.2);
50+
metrics.errors().inc();
51+
}

prometric-derive/examples/exporter.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ use prometric_derive::metrics;
33

44
#[metrics(scope = "example")]
55
struct ExampleMetrics {
6+
/// A simple counter
67
#[metric]
78
counter: Counter,
89

10+
/// A simple gauge
911
#[metric]
1012
gauge: Gauge,
1113
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use prometric::{Counter, Gauge};
2+
use prometric_derive::metrics;
3+
4+
#[metrics(scope = "app", static)]
5+
struct AppMetrics {
6+
/// The total number of requests.
7+
#[metric(labels = ["method"])]
8+
requests: Counter,
9+
10+
/// The current number of active connections.
11+
#[metric]
12+
active_connections: Gauge,
13+
}
14+
15+
#[tokio::main(flavor = "current_thread")]
16+
async fn main() {
17+
// Use the static directly (the name is APP_METRICS in SCREAMING_SNAKE_CASE)
18+
APP_METRICS.requests("GET").inc();
19+
APP_METRICS.active_connections().set(10);
20+
21+
// The following would not compile:
22+
// let metrics = AppMetrics::builder(); // Error: builder() is private
23+
// let metrics = AppMetrics::default(); // Error: Default is not implemented
24+
}

0 commit comments

Comments
 (0)