PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
dicom_collector_base.h
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2021-2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
19#pragma once
20
21#include <atomic>
22#include <chrono>
23#include <cstdint>
24#include <mutex>
25#include <string>
26#include <unordered_map>
27#include <vector>
28
30
34using config_map = std::unordered_map<std::string, std::string>;
35
39using stats_map = std::unordered_map<std::string, double>;
40
48 std::string name;
49 double value;
50 std::string type; // "gauge", "counter", "histogram"
51 std::chrono::system_clock::time_point timestamp;
52 std::unordered_map<std::string, std::string> tags;
53
54 dicom_metric() : value(0.0), timestamp(std::chrono::system_clock::now()) {}
55
56 dicom_metric(std::string n,
57 double v,
58 std::string t,
59 std::unordered_map<std::string, std::string> tgs = {})
60 : name(std::move(n))
61 , value(v)
62 , type(std::move(t))
63 , timestamp(std::chrono::system_clock::now())
64 , tags(std::move(tgs)) {}
65};
66
103template <typename Derived>
105public:
107 virtual ~dicom_collector_base() = default;
108
109 // Non-copyable, non-moveable
114
122 bool initialize(const config_map& config) {
123 // Parse common configuration
124 if (auto it = config.find("enabled"); it != config.end()) {
125 enabled_ = (it->second == "true" || it->second == "1");
126 }
127
128 if (auto it = config.find("ae_title"); it != config.end()) {
129 ae_title_ = it->second;
130 }
131
132 init_time_ = std::chrono::steady_clock::now();
133
134 // Delegate to derived class for specific initialization
135 return derived().do_initialize(config);
136 }
137
142 std::vector<dicom_metric> collect() {
143 if (!enabled_) {
144 return {};
145 }
146
147 try {
148 auto metrics = derived().do_collect();
150 last_collection_time_ = std::chrono::system_clock::now();
151 return metrics;
152 } catch (...) {
154 return {};
155 }
156 }
157
162 [[nodiscard]] std::string get_name() const {
163 return Derived::collector_name;
164 }
165
170 [[nodiscard]] std::vector<std::string> get_metric_types() const {
171 return derived().do_get_metric_types();
172 }
173
178 [[nodiscard]] bool is_healthy() const {
179 if (!enabled_) {
180 return true; // Disabled collectors are considered healthy
181 }
182 return derived().is_available();
183 }
184
189 [[nodiscard]] stats_map get_statistics() const {
190 std::lock_guard<std::mutex> lock(stats_mutex_);
191 stats_map stats;
192
193 // Common statistics
194 stats["enabled"] = enabled_ ? 1.0 : 0.0;
195 stats["collection_count"] = static_cast<double>(collection_count_.load());
196 stats["collection_errors"] = static_cast<double>(collection_errors_.load());
197
198 // Uptime if initialized
199 if (init_time_.time_since_epoch().count() > 0) {
200 const auto uptime = std::chrono::duration_cast<std::chrono::seconds>(
201 std::chrono::steady_clock::now() - init_time_);
202 stats["uptime_seconds"] = static_cast<double>(uptime.count());
203 }
204
205 // Let derived class add specific statistics
206 derived().do_add_statistics(stats);
207
208 return stats;
209 }
210
215 [[nodiscard]] bool is_enabled() const { return enabled_; }
216
221 [[nodiscard]] std::size_t get_collection_count() const {
222 return collection_count_.load();
223 }
224
229 [[nodiscard]] std::size_t get_collection_errors() const {
230 return collection_errors_.load();
231 }
232
237 [[nodiscard]] std::string get_ae_title() const { return ae_title_; }
238
243 void set_ae_title(std::string ae_title) { ae_title_ = std::move(ae_title); }
244
245protected:
255 const std::string& name,
256 double value,
257 const std::string& type,
258 const std::unordered_map<std::string, std::string>& extra_tags = {}) const {
259
260 std::unordered_map<std::string, std::string> tags = extra_tags;
261 tags["collector"] = Derived::collector_name;
262 if (!ae_title_.empty()) {
263 tags["ae_title"] = ae_title_;
264 }
265
266 return dicom_metric(name, value, type, std::move(tags));
267 }
268
269 // Configuration
270 bool enabled_{true};
271 std::string ae_title_{"PACS_SCP"};
272
273 // Statistics
274 mutable std::mutex stats_mutex_;
275 std::atomic<std::size_t> collection_count_{0};
276 std::atomic<std::size_t> collection_errors_{0};
277 std::chrono::steady_clock::time_point init_time_;
278 std::chrono::system_clock::time_point last_collection_time_;
279
280private:
284 Derived& derived() { return static_cast<Derived&>(*this); }
285 const Derived& derived() const { return static_cast<const Derived&>(*this); }
286};
287
288} // namespace kcenon::pacs::monitoring
CRTP base class for DICOM metric collectors.
std::chrono::steady_clock::time_point init_time_
std::size_t get_collection_errors() const
Get error count.
dicom_collector_base & operator=(const dicom_collector_base &)=delete
bool initialize(const config_map &config)
Initialize the collector with configuration.
std::vector< std::string > get_metric_types() const
Get supported metric types.
dicom_collector_base(dicom_collector_base &&)=delete
std::vector< dicom_metric > collect()
Collect metrics from the data source.
std::string get_ae_title() const
Get the AE title.
bool is_healthy() const
Check if the collector is healthy.
void set_ae_title(std::string ae_title)
Set the AE title.
std::size_t get_collection_count() const
Get collection count.
std::chrono::system_clock::time_point last_collection_time_
Derived & derived()
Get reference to derived class (CRTP helper)
dicom_collector_base & operator=(dicom_collector_base &&)=delete
dicom_collector_base(const dicom_collector_base &)=delete
stats_map get_statistics() const
Get collector statistics.
std::string get_name() const
Get the name of this collector.
dicom_metric create_base_metric(const std::string &name, double value, const std::string &type, const std::unordered_map< std::string, std::string > &extra_tags={}) const
Create a metric with common tags.
bool is_enabled() const
Check if collector is enabled.
std::unordered_map< std::string, double > stats_map
Type alias for statistics map.
std::unordered_map< std::string, std::string > config_map
Type alias for configuration map.
Standard metric structure for DICOM data.
std::unordered_map< std::string, std::string > tags
dicom_metric(std::string n, double v, std::string t, std::unordered_map< std::string, std::string > tgs={})
std::chrono::system_clock::time_point timestamp
std::string_view name