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 {
43 public:
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 MakeWithPrefix(const std::string& prefix,
52 AddLabels add_labels = {},
53 std::vector<Label> require_labels = {});
54
55 /// Makes request for metrics whose path is `path`.
56 static Request MakeWithPath(const std::string& path,
57 AddLabels add_labels = {},
58 std::vector<Label> require_labels = {});
59
60 /// Return metrics whose path matches with this `prefix`
61 const std::string prefix{};
62
63 /// Enum for different match types of the `prefix`
64 enum class PrefixMatch {
65 kNoop, ///< Do not match, the `prefix` is empty
66 kExact, ///< `prefix` equal to path
67 kStartsWith, ///< Metric path starts with `prefix`
68 };
69
70 /// Match type of the `prefix`
72
73 /// Require those labels in the metric
75
76 /// Add those labels to each returned metric
78
79 private:
80 Request(std::string prefix_in, PrefixMatch path_match_type_in,
81 std::vector<Label> require_labels_in, AddLabels add_labels_in);
82};
83
84using ExtenderFunc =
85 std::function<formats::json::ValueBuilder(const StatisticsRequest&)>;
86
87using WriterFunc = std::function<void(Writer&)>;
88
89namespace impl {
90
91struct MetricsSource final {
92 std::string prefix_path;
93 std::vector<std::string> path_segments;
94 ExtenderFunc extender;
95
96 WriterFunc writer;
97 std::vector<Label> writer_labels;
98};
99
100using StorageData = std::list<MetricsSource>;
101using StorageIterator = StorageData::iterator;
102
103inline constexpr bool kCheckSubscriptionUB = utils::impl::kEnableAssert;
104
105} // namespace impl
106
108 public:
109 virtual ~BaseFormatBuilder();
110
111 virtual void HandleMetric(std::string_view path, LabelsSpan labels,
112 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 {
121 public:
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,
144 std::vector<Label> add_labels = {});
145
146 /// @deprecated Use RegisterWriter instead.
147 Entry RegisterExtender(std::string prefix, ExtenderFunc func);
148
149 void UnregisterExtender(impl::StorageIterator iterator,
150 impl::UnregisteringKind kind) noexcept;
151
152 private:
153 Entry DoRegisterExtender(impl::MetricsSource&& source);
154
155 std::atomic<bool> may_register_extenders_;
156 impl::StorageData metrics_sources_;
157 mutable engine::SharedMutex mutex_;
158};
159
160} // namespace utils::statistics
161
162USERVER_NAMESPACE_END