userver: userver/utils/statistics/storage.hpp Source File
Loading...
Searching...
No Matches
storage.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utils/statistics/storage.hpp
4/// @brief @copybrief utils::statistics::Storage
5
6#include <atomic>
7#include <functional>
8#include <initializer_list>
9#include <list>
10#include <string>
11#include <unordered_map>
12#include <variant>
13#include <vector>
14
15#include <userver/engine/shared_mutex.hpp>
16#include <userver/formats/json/value_builder.hpp>
17#include <userver/utils/assert.hpp>
18#include <userver/utils/statistics/entry.hpp>
19#include <userver/utils/statistics/metric_value.hpp>
20#include <userver/utils/statistics/writer.hpp>
21
22USERVER_NAMESPACE_BEGIN
23
24namespace utils::statistics {
25
26/// @brief Used in legacy statistics extenders
27struct StatisticsRequest final {};
28
29/// @brief Class describing the request for metrics data.
30///
31/// Metric path and metric name are the same thing. For example for code like
32///
33/// @code
34/// writer["a"]["b"]["c"] = 42;
35/// @endcode
36///
37/// the metric name is "a.b.c" and in Prometheus format it would be escaped like
38/// "a_b_c{} 42".
39///
40/// @note `add_labels` should not match labels from Storage, otherwise the
41/// returned metrics may not be read by metrics server.
42class Request final {
43public:
44 using AddLabels = std::unordered_map<std::string, std::string>;
45
46 /// Default request without parameters. Equivalent to requesting all the
47 /// metrics without adding or requiring any labels.
48 Request() = default;
49
50 /// Makes request for metrics whose path starts with the `prefix`.
51 static Request
52 MakeWithPrefix(const std::string& prefix, AddLabels add_labels = {}, std::vector<Label> require_labels = {});
53
54 /// Makes request for metrics whose path is `path`.
55 static Request
56 MakeWithPath(const std::string& path, AddLabels add_labels = {}, std::vector<Label> require_labels = {});
57
58 /// Return metrics whose path matches with this `prefix`
59 const std::string prefix{};
60
61 /// Enum for different match types of the `prefix`
62 enum class PrefixMatch {
63 kNoop, ///< Do not match, the `prefix` is empty
64 kExact, ///< `prefix` equal to path
65 kStartsWith, ///< Metric path starts with `prefix`
66 };
67
68 /// Match type of the `prefix`
70
71 /// Require those labels in the metric
73
74 /// Add those labels to each returned metric
76
77private:
78 Request(
79 std::string prefix_in,
80 PrefixMatch path_match_type_in,
81 std::vector<Label> require_labels_in,
82 AddLabels add_labels_in
83 );
84};
85
86using ExtenderFunc = std::function<formats::json::ValueBuilder(const StatisticsRequest&)>;
87
88using WriterFunc = std::function<void(Writer&)>;
89
90namespace impl {
91
92struct MetricsSource final {
93 std::string prefix_path;
94 std::vector<std::string> path_segments;
95 ExtenderFunc extender;
96
97 WriterFunc writer;
98 std::vector<Label> writer_labels;
99};
100
101using StorageData = std::list<MetricsSource>;
102using StorageIterator = StorageData::iterator;
103
104inline constexpr bool kCheckSubscriptionUB = utils::impl::kEnableAssert;
105
106} // namespace impl
107
109public:
110 virtual ~BaseFormatBuilder();
111
112 virtual void HandleMetric(std::string_view path, LabelsSpan labels, const MetricValue& value) = 0;
113};
114
115/// @ingroup userver_clients
116///
117/// Storage of metrics, usually retrieved from components::StatisticsStorage.
118///
119/// See utils::statistics::Writer for an information on how to write metrics.
120class Storage final {
121public:
122 Storage();
123
124 Storage(const Storage&) = delete;
125
126 /// Creates new Json::Value and calls every deprecated registered extender
127 /// func over it.
128 ///
129 /// @deprecated Use VisitMetrics instead.
130 formats::json::Value GetAsJson() const;
131
132 /// Visits all the metrics and calls `out.HandleMetric` for each metric.
133 void VisitMetrics(BaseFormatBuilder& out, const Request& request = {}) const;
134
135 /// @cond
136 /// Must be called from StatisticsStorage only. Don't call it from user
137 /// components.
138 void StopRegisteringExtenders();
139 /// @endcond
140
141 /// @brief Add a writer function. Note that `func` is called concurrently with
142 /// other code, so it should be thread\coroutine safe.
143 Entry RegisterWriter(std::string common_prefix, WriterFunc func, std::vector<Label> add_labels = {});
144
145 /// @deprecated Use RegisterWriter instead.
146 Entry RegisterExtender(std::string prefix, ExtenderFunc func);
147
148 void UnregisterExtender(impl::StorageIterator iterator, impl::UnregisteringKind kind) noexcept;
149
150private:
151 Entry DoRegisterExtender(impl::MetricsSource&& source);
152
153 std::atomic<bool> may_register_extenders_;
154 impl::StorageData metrics_sources_;
155 mutable engine::SharedMutex mutex_;
156};
157
158} // namespace utils::statistics
159
160USERVER_NAMESPACE_END