1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
//! This crate contains the attribute macro for generating Prometheus metrics.
//! Refer to the [metrics] attribute documentation for more information.
use TokenStream;
use ;
use crateMetricsAttr;
/// This attribute macro instruments all of the struct fields with Prometheus metrics according to
/// the attributes on the fields. It also generates an ergonomic accessor API for each of the
/// defined metrics.
///
/// # Attributes
///
/// - `scope`: Sets the prefix for metric names (required)
/// - `static`: If enabled, generates a static `LazyLock` with a SCREAMING_SNAKE_CASE name.
///
/// # Example
/// ```rust
/// use prometric_derive::metrics;
/// use prometric::{Counter, Gauge, Histogram};
///
/// // The `scope` attribute is used to set the prefix for the metric names in this struct.
/// #[metrics(scope = "app")]
/// struct AppMetrics {
/// /// The total number of HTTP requests.
/// #[metric(rename = "http_requests_total", labels = ["method", "path"])]
/// http_requests: Counter,
///
/// // For histograms, the `buckets` attribute is optional. It will default to [prometheus::DEFAULT_BUCKETS] if not provided.
/// /// The duration of HTTP requests.
/// #[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])]
/// http_requests_duration: Histogram,
///
/// /// This doc comment will be overwritten by the `help` attribute.
/// #[metric(rename = "current_active_users", labels = ["service"], help = "The current number of active users.")]
/// current_users: Gauge,
///
/// /// The balance of the account, in dollars. Uses a floating point number.
/// #[metric(rename = "account_balance", labels = ["account_id"])]
/// account_balance: Gauge<f64>,
///
/// /// The total number of errors.
/// #[metric]
/// errors: Counter,
/// }
///
/// // Build the metrics struct with static labels, which will initialize and register the metrics with the default registry.
/// // A custom registry can be used by passing it to the builder using `with_registry`.
/// let metrics = AppMetrics::builder().with_label("host", "localhost").with_label("port", "8080").build();
///
/// // Metric fields each get an accessor method generated, which can be used to interact with the metric.
/// // The arguments to the accessor method are the labels for the metric.
/// metrics.http_requests("GET", "/").inc();
/// metrics.http_requests_duration("GET", "/").observe(1.0);
/// metrics.current_users("service-1").set(10);
/// metrics.account_balance("1234567890").set(-12.2);
/// metrics.errors().inc();
/// ```
///
/// # Sample Output
/// ```text
/// # HELP app_account_balance The balance of the account, in dollars. Uses a floating point number.
/// # TYPE app_account_balance gauge
/// app_account_balance{account_id="1234567890",host="localhost",port="8080"} -12.2
///
/// # HELP app_current_active_users The current number of active users.
/// # TYPE app_current_active_users gauge
/// app_current_active_users{host="localhost",port="8080",service="service-1"} 20
///
/// # HELP app_errors The total number of errors.
/// # TYPE app_errors counter
/// app_errors{host="localhost",port="8080"} 1
///
/// # HELP app_http_requests_duration The duration of HTTP requests.
/// # TYPE app_http_requests_duration histogram
/// app_http_requests_duration_bucket{host="localhost",method="GET",path="/",port="8080",le="0.005"} 0
/// app_http_requests_duration_bucket{host="localhost",method="GET",path="/",port="8080",le="0.01"} 0
/// app_http_requests_duration_bucket{host="localhost",method="GET",path="/",port="8080",le="0.025" } 0
/// app_http_requests_duration_bucket{host="localhost",method="GET",path="/",port="8080",le="0.05"} 0
/// app_http_requests_duration_bucket{host="localhost",method="GET",path="/",port="8080",le="0.1"} 0
/// app_http_requests_duration_bucket{host="localhost",method="GET",path="/",port="8080",le="0.25"} 0
/// app_http_requests_duration_bucket{host="localhost",method="GET",path="/",port="8080",le="0.5"} 0
/// app_http_requests_duration_bucket{host="localhost",method="GET",path="/",port="8080",le="1"} 1
/// app_http_requests_duration_bucket{host="localhost",method="GET",path="/",port="8080",le="2.5"} 1
/// app_http_requests_duration_bucket{host="localhost",method="GET",path="/",port="8080",le="5"} 1
/// app_http_requests_duration_bucket{host="localhost",method="GET",path="/",port="8080",le="+Inf"} 1
/// app_http_requests_duration_sum{host="localhost",method="GET",path="/",port="8080"} 1
/// app_http_requests_duration_count{host="localhost",method="GET",path="/",port="8080"} 1
///
/// # HELP app_http_requests_total The total number of HTTP requests.
/// # TYPE app_http_requests_total counter
/// app_http_requests_total{host="localhost",method="GET",path="/",port="8080"} 2
/// app_http_requests_total{host="localhost",method="POST",path="/",port="8080"} 2
/// ```
/// # Static Metrics Example
///
/// When the `static` attribute is enabled, a static `LazyLock` is generated with a
/// SCREAMING_SNAKE_CASE name. The builder methods and `Default` implementation are made private,
/// ensuring the only way to access the metrics is through the static instance.
///
/// If `static` is enabled, `prometheus::default_registry()` is used.
///
/// ```rust
/// use prometric::{Counter, Gauge};
/// use prometric_derive::metrics;
///
/// #[metrics(scope = "app", static)]
/// struct AppMetrics {
/// /// The total number of requests.
/// #[metric(labels = ["method"])]
/// requests: Counter,
///
/// /// The current number of active connections.
/// #[metric]
/// active_connections: Gauge,
/// }
///
/// // Use the static directly anywhere
/// APP_METRICS.requests("GET").inc();
/// APP_METRICS.active_connections().set(10);
///
/// // The following would not compile:
/// // let metrics = AppMetrics::builder(); // Error: builder() is private
/// // let metrics = AppMetrics::default(); // Error: Default is not implemented
/// ```
///
/// # Exporting Metrics
/// An HTTP exporter is provided by [`prometric::exporter::ExporterBuilder`]. Usage:
///
/// ```rust
/// use prometric::exporter::ExporterBuilder;
///
/// // Metric definitions...
///
/// // Export the metrics on an HTTP endpoint in the background:
/// ExporterBuilder::new()
/// // Specify the address to listen on
/// .with_address("127.0.0.1:9090")
/// // Set the global namespace for the metrics (usually the name of the application)
/// .with_namespace("exporter")
/// // Install the exporter. This will start an HTTP server and serve metrics on the specified
/// // address.
/// .install()
/// .expect("Failed to install exporter");
/// ```
///
/// # Process Metrics Example
///
/// When the `process` feature is enabled, the `ProcessCollector` is used to collect metrics about
/// the current process.
///
/// ```rust
/// # #[cfg(feature = "process")] {
/// use prometric::process::ProcessCollector;
/// use prometric_derive::metrics;
///
/// let mut collector = ProcessCollector::default();
/// collector.collect();
/// # }
/// ```
///
/// #### Output
/// ```text
/// # HELP process_collection_duration_seconds The duration of the associated collection routine in seconds.
/// # TYPE process_collection_duration_seconds gauge
/// process_collection_duration_seconds 0.016130356
/// # HELP process_cpu_usage The CPU usage of the process as a percentage.
/// # TYPE process_cpu_usage gauge
/// process_cpu_usage 6.2536187171936035
/// # HELP process_disk_written_bytes_total The total written bytes to disk by the process.
/// # TYPE process_disk_written_bytes_total gauge
/// process_disk_written_bytes_total 0
/// # HELP process_max_fds The maximum number of open file descriptors of the process.
/// # TYPE process_max_fds gauge
/// process_max_fds 1048576
/// # HELP process_open_fds The number of open file descriptors of the process.
/// # TYPE process_open_fds gauge
/// process_open_fds 639
/// # HELP process_resident_memory_bytes The resident memory of the process in bytes. (RSS)
/// # TYPE process_resident_memory_bytes gauge
/// process_resident_memory_bytes 4702208
/// # HELP process_resident_memory_usage The resident memory usage of the process as a percentage of the total memory available.
/// # TYPE process_resident_memory_usage gauge
/// process_resident_memory_usage 0.00007072418111501723
/// # HELP process_start_time_seconds The start time of the process in UNIX seconds.
/// # TYPE process_start_time_seconds gauge
/// process_start_time_seconds 1763056609
/// # HELP process_thread_usage Per-thread CPU usage as a percentage of the process's CPU usage (Linux only).
/// # TYPE process_thread_usage gauge
/// process_thread_usage{name="process::tests:",pid="980490"} 0.9259260296821594
/// process_thread_usage{name="test-thread-1",pid="980491"} 0
/// process_thread_usage{name="test-thread-2",pid="980492"} 94.44445037841797
/// # HELP process_threads The number of OS threads used by the process (Linux only).
/// # TYPE process_threads gauge
/// process_threads 3
/// # HELP system_cpu_cores The number of logical CPU cores available in the system.
/// # TYPE system_cpu_cores gauge
/// system_cpu_cores 16
/// # HELP system_cpu_usage System-wide CPU usage percentage.
/// # TYPE system_cpu_usage gauge
/// system_cpu_usage 6.7168498039245605
/// # HELP system_max_cpu_frequency The maximum CPU frequency of all cores in MHz.
/// # TYPE system_max_cpu_frequency gauge
/// system_max_cpu_frequency 5339
/// # HELP system_memory_usage System-wide memory usage percentage.
/// # TYPE system_memory_usage gauge
/// system_memory_usage 6.398677876736871
/// # HELP system_min_cpu_frequency The minimum CPU frequency of all cores in MHz.
/// # TYPE system_min_cpu_frequency gauge
/// system_min_cpu_frequency 545
/// ```