1#![doc = include_str!("../README.md")]
19#![cfg_attr(docsrs, feature(doc_cfg))]
20#![cfg_attr(docsrs, doc(auto_cfg))]
21#![deny(missing_docs)]
22use opendal_core::OperationContext;
23use opendal_core::raw::*;
24use opendal_layer_observe_metrics_common as observe;
25use prometheus_client::encoding::EncodeLabel;
26use prometheus_client::encoding::EncodeLabelSet;
27use prometheus_client::encoding::LabelSetEncoder;
28use prometheus_client::metrics::counter::Counter;
29use prometheus_client::metrics::family::Family;
30use prometheus_client::metrics::family::MetricConstructor;
31use prometheus_client::metrics::gauge::Gauge;
32use prometheus_client::metrics::histogram::Histogram;
33use prometheus_client::registry::Metric;
34use prometheus_client::registry::Registry;
35use prometheus_client::registry::Unit;
36
37#[derive(Clone, Debug)]
80pub struct PrometheusClientLayer {
81 interceptor: PrometheusClientInterceptor,
82}
83
84impl PrometheusClientLayer {
85 pub fn builder() -> PrometheusClientLayerBuilder {
87 PrometheusClientLayerBuilder::default()
88 }
89}
90
91impl Layer for PrometheusClientLayer {
92 fn apply_service(&self, inner: Servicer) -> Servicer {
93 observe::MetricsLayer::new(self.interceptor.clone()).apply_service(inner)
94 }
95
96 fn apply_context(&self, srv: Servicer, inner: OperationContext) -> OperationContext {
98 observe::MetricsLayer::new(self.interceptor.clone()).apply_context(srv, inner)
99 }
100}
101
102pub struct PrometheusClientLayerBuilder {
104 bytes_buckets: Vec<f64>,
105 bytes_rate_buckets: Vec<f64>,
106 entries_buckets: Vec<f64>,
107 entries_rate_buckets: Vec<f64>,
108 duration_seconds_buckets: Vec<f64>,
109 ttfb_buckets: Vec<f64>,
110 disable_label_root: bool,
111}
112
113impl Default for PrometheusClientLayerBuilder {
114 fn default() -> Self {
115 Self {
116 bytes_buckets: observe::DEFAULT_BYTES_BUCKETS.to_vec(),
117 bytes_rate_buckets: observe::DEFAULT_BYTES_RATE_BUCKETS.to_vec(),
118 entries_buckets: observe::DEFAULT_ENTRIES_BUCKETS.to_vec(),
119 entries_rate_buckets: observe::DEFAULT_ENTRIES_RATE_BUCKETS.to_vec(),
120 duration_seconds_buckets: observe::DEFAULT_DURATION_SECONDS_BUCKETS.to_vec(),
121 ttfb_buckets: observe::DEFAULT_TTFB_BUCKETS.to_vec(),
122 disable_label_root: false,
123 }
124 }
125}
126
127impl PrometheusClientLayerBuilder {
128 pub fn bytes_buckets(mut self, buckets: Vec<f64>) -> Self {
130 if !buckets.is_empty() {
131 self.bytes_buckets = buckets;
132 }
133 self
134 }
135
136 pub fn bytes_rate_buckets(mut self, buckets: Vec<f64>) -> Self {
138 if !buckets.is_empty() {
139 self.bytes_rate_buckets = buckets;
140 }
141 self
142 }
143
144 pub fn entries_buckets(mut self, buckets: Vec<f64>) -> Self {
146 if !buckets.is_empty() {
147 self.entries_buckets = buckets;
148 }
149 self
150 }
151
152 pub fn entries_rate_buckets(mut self, buckets: Vec<f64>) -> Self {
154 if !buckets.is_empty() {
155 self.entries_rate_buckets = buckets;
156 }
157 self
158 }
159
160 pub fn duration_seconds_buckets(mut self, buckets: Vec<f64>) -> Self {
162 if !buckets.is_empty() {
163 self.duration_seconds_buckets = buckets;
164 }
165 self
166 }
167
168 pub fn ttfb_buckets(mut self, buckets: Vec<f64>) -> Self {
170 if !buckets.is_empty() {
171 self.ttfb_buckets = buckets;
172 }
173 self
174 }
175
176 pub fn disable_label_root(mut self, disable: bool) -> Self {
179 self.disable_label_root = disable;
180 self
181 }
182
183 pub fn register(self, registry: &mut Registry) -> PrometheusClientLayer {
205 let operation_bytes =
206 Family::<OperationLabels, Histogram, _>::new_with_constructor(HistogramConstructor {
207 buckets: self.bytes_buckets.clone(),
208 });
209 let operation_bytes_rate =
210 Family::<OperationLabels, Histogram, _>::new_with_constructor(HistogramConstructor {
211 buckets: self.bytes_rate_buckets.clone(),
212 });
213 let operation_entries =
214 Family::<OperationLabels, Histogram, _>::new_with_constructor(HistogramConstructor {
215 buckets: self.entries_buckets.clone(),
216 });
217 let operation_entries_rate =
218 Family::<OperationLabels, Histogram, _>::new_with_constructor(HistogramConstructor {
219 buckets: self.entries_rate_buckets.clone(),
220 });
221 let operation_duration_seconds =
222 Family::<OperationLabels, Histogram, _>::new_with_constructor(HistogramConstructor {
223 buckets: self.duration_seconds_buckets.clone(),
224 });
225 let operation_errors_total = Family::<OperationLabels, Counter>::default();
226 let operation_executing = Family::<OperationLabels, Gauge>::default();
227 let operation_ttfb_seconds =
228 Family::<OperationLabels, Histogram, _>::new_with_constructor(HistogramConstructor {
229 buckets: self.ttfb_buckets.clone(),
230 });
231
232 let http_executing = Family::<OperationLabels, Gauge>::default();
233 let http_request_bytes =
234 Family::<OperationLabels, Histogram, _>::new_with_constructor(HistogramConstructor {
235 buckets: self.bytes_buckets.clone(),
236 });
237 let http_request_bytes_rate =
238 Family::<OperationLabels, Histogram, _>::new_with_constructor(HistogramConstructor {
239 buckets: self.bytes_rate_buckets.clone(),
240 });
241 let http_request_duration_seconds =
242 Family::<OperationLabels, Histogram, _>::new_with_constructor(HistogramConstructor {
243 buckets: self.duration_seconds_buckets.clone(),
244 });
245 let http_response_bytes =
246 Family::<OperationLabels, Histogram, _>::new_with_constructor(HistogramConstructor {
247 buckets: self.bytes_buckets.clone(),
248 });
249 let http_response_bytes_rate =
250 Family::<OperationLabels, Histogram, _>::new_with_constructor(HistogramConstructor {
251 buckets: self.bytes_rate_buckets.clone(),
252 });
253 let http_response_duration_seconds =
254 Family::<OperationLabels, Histogram, _>::new_with_constructor(HistogramConstructor {
255 buckets: self.duration_seconds_buckets.clone(),
256 });
257 let http_connection_errors_total = Family::<OperationLabels, Counter>::default();
258 let http_status_errors_total = Family::<OperationLabels, Counter>::default();
259
260 register_metric(
261 registry,
262 operation_bytes.clone(),
263 observe::MetricValue::OperationBytes(0),
264 );
265 register_metric(
266 registry,
267 operation_bytes_rate.clone(),
268 observe::MetricValue::OperationBytesRate(0.0),
269 );
270 register_metric(
271 registry,
272 operation_entries.clone(),
273 observe::MetricValue::OperationEntries(0),
274 );
275 register_metric(
276 registry,
277 operation_entries_rate.clone(),
278 observe::MetricValue::OperationEntriesRate(0.0),
279 );
280 register_metric(
281 registry,
282 operation_duration_seconds.clone(),
283 observe::MetricValue::OperationDurationSeconds(Duration::default()),
284 );
285 register_metric(
286 registry,
287 operation_errors_total.clone(),
288 observe::MetricValue::OperationErrorsTotal,
289 );
290 register_metric(
291 registry,
292 operation_executing.clone(),
293 observe::MetricValue::OperationExecuting(0),
294 );
295 register_metric(
296 registry,
297 operation_ttfb_seconds.clone(),
298 observe::MetricValue::OperationTtfbSeconds(Duration::default()),
299 );
300
301 register_metric(
302 registry,
303 http_executing.clone(),
304 observe::MetricValue::HttpExecuting(0),
305 );
306 register_metric(
307 registry,
308 http_request_bytes.clone(),
309 observe::MetricValue::HttpRequestBytes(0),
310 );
311 register_metric(
312 registry,
313 http_request_bytes_rate.clone(),
314 observe::MetricValue::HttpRequestBytesRate(0.0),
315 );
316 register_metric(
317 registry,
318 http_request_duration_seconds.clone(),
319 observe::MetricValue::HttpRequestDurationSeconds(Duration::default()),
320 );
321 register_metric(
322 registry,
323 http_response_bytes.clone(),
324 observe::MetricValue::HttpResponseBytes(0),
325 );
326 register_metric(
327 registry,
328 http_response_bytes_rate.clone(),
329 observe::MetricValue::HttpResponseBytesRate(0.0),
330 );
331 register_metric(
332 registry,
333 http_response_duration_seconds.clone(),
334 observe::MetricValue::HttpResponseDurationSeconds(Duration::default()),
335 );
336 register_metric(
337 registry,
338 http_connection_errors_total.clone(),
339 observe::MetricValue::HttpConnectionErrorsTotal,
340 );
341 register_metric(
342 registry,
343 http_status_errors_total.clone(),
344 observe::MetricValue::HttpStatusErrorsTotal,
345 );
346
347 PrometheusClientLayer {
348 interceptor: PrometheusClientInterceptor {
349 operation_bytes,
350 operation_bytes_rate,
351 operation_entries,
352 operation_entries_rate,
353 operation_duration_seconds,
354 operation_errors_total,
355 operation_executing,
356 operation_ttfb_seconds,
357
358 http_executing,
359 http_request_bytes,
360 http_request_bytes_rate,
361 http_request_duration_seconds,
362 http_response_bytes,
363 http_response_bytes_rate,
364 http_response_duration_seconds,
365 http_connection_errors_total,
366 http_status_errors_total,
367
368 disable_label_root: self.disable_label_root,
369 },
370 }
371 }
372}
373
374#[derive(Clone)]
375struct HistogramConstructor {
376 buckets: Vec<f64>,
377}
378
379impl MetricConstructor<Histogram> for HistogramConstructor {
380 fn new_metric(&self) -> Histogram {
381 Histogram::new(self.buckets.iter().cloned())
382 }
383}
384
385#[doc(hidden)]
386#[derive(Clone, Debug)]
387pub struct PrometheusClientInterceptor {
388 operation_bytes: Family<OperationLabels, Histogram, HistogramConstructor>,
389 operation_bytes_rate: Family<OperationLabels, Histogram, HistogramConstructor>,
390 operation_entries: Family<OperationLabels, Histogram, HistogramConstructor>,
391 operation_entries_rate: Family<OperationLabels, Histogram, HistogramConstructor>,
392 operation_duration_seconds: Family<OperationLabels, Histogram, HistogramConstructor>,
393 operation_errors_total: Family<OperationLabels, Counter>,
394 operation_executing: Family<OperationLabels, Gauge>,
395 operation_ttfb_seconds: Family<OperationLabels, Histogram, HistogramConstructor>,
396
397 http_executing: Family<OperationLabels, Gauge>,
398 http_request_bytes: Family<OperationLabels, Histogram, HistogramConstructor>,
399 http_request_bytes_rate: Family<OperationLabels, Histogram, HistogramConstructor>,
400 http_request_duration_seconds: Family<OperationLabels, Histogram, HistogramConstructor>,
401 http_response_bytes: Family<OperationLabels, Histogram, HistogramConstructor>,
402 http_response_bytes_rate: Family<OperationLabels, Histogram, HistogramConstructor>,
403 http_response_duration_seconds: Family<OperationLabels, Histogram, HistogramConstructor>,
404 http_connection_errors_total: Family<OperationLabels, Counter>,
405 http_status_errors_total: Family<OperationLabels, Counter>,
406
407 disable_label_root: bool,
408}
409
410impl observe::MetricsIntercept for PrometheusClientInterceptor {
411 fn observe(&self, labels: observe::MetricLabels, value: observe::MetricValue) {
412 let labels = OperationLabels {
413 labels,
414 disable_label_root: self.disable_label_root,
415 };
416 match value {
417 observe::MetricValue::OperationBytes(v) => self
418 .operation_bytes
419 .get_or_create(&labels)
420 .observe(v as f64),
421 observe::MetricValue::OperationBytesRate(v) => {
422 self.operation_bytes_rate.get_or_create(&labels).observe(v)
423 }
424 observe::MetricValue::OperationEntries(v) => self
425 .operation_entries
426 .get_or_create(&labels)
427 .observe(v as f64),
428 observe::MetricValue::OperationEntriesRate(v) => self
429 .operation_entries_rate
430 .get_or_create(&labels)
431 .observe(v),
432 observe::MetricValue::OperationDurationSeconds(v) => self
433 .operation_duration_seconds
434 .get_or_create(&labels)
435 .observe(v.as_secs_f64()),
436 observe::MetricValue::OperationErrorsTotal => {
437 self.operation_errors_total.get_or_create(&labels).inc();
438 }
439 observe::MetricValue::OperationExecuting(v) => {
440 self.operation_executing
441 .get_or_create(&labels)
442 .inc_by(v as i64);
443 }
444 observe::MetricValue::OperationTtfbSeconds(v) => self
445 .operation_ttfb_seconds
446 .get_or_create(&labels)
447 .observe(v.as_secs_f64()),
448
449 observe::MetricValue::HttpExecuting(v) => {
450 self.http_executing.get_or_create(&labels).inc_by(v as i64);
451 }
452 observe::MetricValue::HttpRequestBytes(v) => self
453 .http_request_bytes
454 .get_or_create(&labels)
455 .observe(v as f64),
456 observe::MetricValue::HttpRequestBytesRate(v) => self
457 .http_request_bytes_rate
458 .get_or_create(&labels)
459 .observe(v),
460 observe::MetricValue::HttpRequestDurationSeconds(v) => self
461 .http_request_duration_seconds
462 .get_or_create(&labels)
463 .observe(v.as_secs_f64()),
464 observe::MetricValue::HttpResponseBytes(v) => self
465 .http_response_bytes
466 .get_or_create(&labels)
467 .observe(v as f64),
468 observe::MetricValue::HttpResponseBytesRate(v) => self
469 .http_response_bytes_rate
470 .get_or_create(&labels)
471 .observe(v),
472 observe::MetricValue::HttpResponseDurationSeconds(v) => self
473 .http_response_duration_seconds
474 .get_or_create(&labels)
475 .observe(v.as_secs_f64()),
476 observe::MetricValue::HttpConnectionErrorsTotal => {
477 self.http_connection_errors_total
478 .get_or_create(&labels)
479 .inc();
480 }
481 observe::MetricValue::HttpStatusErrorsTotal => {
482 self.http_status_errors_total.get_or_create(&labels).inc();
483 }
484 _ => {}
485 };
486 }
487}
488
489#[derive(Clone, Debug, PartialEq, Eq, Hash)]
490struct OperationLabels {
491 labels: observe::MetricLabels,
492 disable_label_root: bool,
493}
494
495impl EncodeLabelSet for OperationLabels {
496 fn encode(&self, encoder: &mut LabelSetEncoder<'_>) -> std::fmt::Result {
497 (observe::LABEL_SCHEME, self.labels.scheme).encode(encoder.encode_label())?;
498 (observe::LABEL_NAMESPACE, self.labels.namespace.as_ref())
499 .encode(encoder.encode_label())?;
500 if !self.disable_label_root {
501 (observe::LABEL_ROOT, self.labels.root.as_ref()).encode(encoder.encode_label())?;
502 }
503 (observe::LABEL_OPERATION, self.labels.operation).encode(encoder.encode_label())?;
504
505 if let Some(error) = &self.labels.error {
506 (observe::LABEL_ERROR, error.into_static()).encode(encoder.encode_label())?;
507 }
508 if let Some(code) = &self.labels.status_code {
509 (observe::LABEL_STATUS_CODE, code.as_str()).encode(encoder.encode_label())?;
510 }
511 if let Some(service_operation) = self.labels.service_operation {
512 (observe::LABEL_SERVICE_OPERATION, service_operation).encode(encoder.encode_label())?;
513 }
514 Ok(())
515 }
516}
517
518fn register_metric(registry: &mut Registry, metric: impl Metric, value: observe::MetricValue) {
519 let ((name, unit), help) = (value.name_with_unit(), value.help());
520
521 if let Some(unit) = unit {
522 registry.register_with_unit(name, help, Unit::Other(unit.to_string()), metric);
523 } else {
524 registry.register(name, help, metric);
525 }
526}