referrerpolicy=no-referrer-when-downgrade
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
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Polkadot.

// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.

//! This module provides an implementation for the runtime metrics types: `Counter`,
//! `CounterVec` and `Histogram`. These types expose a Prometheus like interface and
//! same functionality. Each instance of a runtime metric is mapped to a Prometheus
//! metric on the client side. The runtime metrics must be registered with the registry
//! in the client, otherwise they will not be published.

const TRACING_TARGET: &'static str = "metrics";

use alloc::vec::Vec;
use codec::Encode;
use polkadot_primitives::{
	metric_definitions::{CounterDefinition, CounterVecDefinition, HistogramDefinition},
	RuntimeMetricLabelValues, RuntimeMetricOp, RuntimeMetricUpdate,
};

/// Holds a set of counters that have different values for their labels,
/// like Prometheus `CounterVec`.
pub struct CounterVec {
	name: &'static str,
}

/// A counter metric.
pub struct Counter {
	name: &'static str,
}

pub struct Histogram {
	name: &'static str,
}

/// Convenience trait implemented for all metric types.
trait MetricEmitter {
	fn emit(metric_op: &RuntimeMetricUpdate) {
		sp_tracing::event!(
			target: TRACING_TARGET,
			sp_tracing::Level::TRACE,
			update_op = bs58::encode(&metric_op.encode()).into_string().as_str()
		);
	}
}

///
pub struct LabeledMetric {
	name: &'static str,
	label_values: RuntimeMetricLabelValues,
}

impl LabeledMetric {
	/// Increment the counter by `value`.
	pub fn inc_by(&self, value: u64) {
		let metric_update = RuntimeMetricUpdate {
			metric_name: Vec::from(self.name),
			op: RuntimeMetricOp::IncrementCounterVec(value, self.label_values.clone()),
		};

		Self::emit(&metric_update);
	}

	/// Increment the counter value.
	pub fn inc(&self) {
		self.inc_by(1);
	}
}

impl MetricEmitter for LabeledMetric {}
impl MetricEmitter for Counter {}
impl MetricEmitter for Histogram {}

impl CounterVec {
	/// Create a new counter as specified by `definition`. This metric needs to be registered
	/// in the client before it can be used.
	pub const fn new(definition: CounterVecDefinition) -> Self {
		// No register op is emitted since the metric is supposed to be registered
		// on the client by the time `inc()` is called.
		CounterVec { name: definition.name }
	}

	/// Returns a `LabeledMetric` instance that provides an interface for incrementing
	/// the metric.
	pub fn with_label_values(&self, label_values: &[&'static str]) -> LabeledMetric {
		LabeledMetric { name: self.name, label_values: label_values.into() }
	}
}

impl Counter {
	/// Create a new counter as specified by `definition`. This metric needs to be registered
	/// in the client before it can be used.
	pub const fn new(definition: CounterDefinition) -> Self {
		Counter { name: definition.name }
	}

	/// Increment counter by `value`.
	pub fn inc_by(&self, value: u64) {
		let metric_update = RuntimeMetricUpdate {
			metric_name: Vec::from(self.name),
			op: RuntimeMetricOp::IncrementCounter(value),
		};

		Self::emit(&metric_update);
	}

	/// Increment counter.
	pub fn inc(&self) {
		self.inc_by(1);
	}
}

impl Histogram {
	/// Create a new histogram as specified by `definition`. This metric needs to be registered
	/// in the client before it can be used.
	pub const fn new(definition: HistogramDefinition) -> Self {
		// No register op is emitted since the metric is supposed to be registered
		// on the client by the time `inc()` is called.
		Histogram { name: definition.name }
	}

	// Observe a value in the histogram
	pub fn observe(&self, value: u128) {
		let metric_update = RuntimeMetricUpdate {
			metric_name: Vec::from(self.name),
			op: RuntimeMetricOp::ObserveHistogram(value),
		};
		Self::emit(&metric_update);
	}
}

/// Returns current time in ns
pub fn get_current_time() -> u128 {
	frame_benchmarking::benchmarking::current_time()
}