12#include <kcenon/monitoring/core/performance_monitor.h>
13#include <kcenon/monitoring/tracing/distributed_tracer.h>
18#include <shared_mutex>
19#include <unordered_map>
53 explicit impl(std::string_view operation_name) {
54 auto& tracer = kcenon::monitoring::global_tracer();
55 auto result = tracer.start_span(std::string(operation_name));
57 span_ = result.value();
64 auto& tracer = kcenon::monitoring::global_tracer();
65 tracer.finish_span(
span_);
69 void set_tag(std::string_view key, std::string_view value) {
71 span_->tags[std::string(key)] = std::string(value);
78 auto now = std::chrono::system_clock::now();
79 auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(
80 now.time_since_epoch())
82 span_->tags[
"event." + std::string(
name)] = std::to_string(timestamp);
88 span_->status = kcenon::monitoring::trace_span::status_code::error;
89 span_->status_message = e.what();
90 span_->tags[
"error"] =
"true";
91 span_->tags[
"error.message"] = e.what();
95 [[nodiscard]]
auto trace_id() const -> std::
string {
97 return span_->trace_id;
102 [[nodiscard]]
auto span_id() const -> std::
string {
104 return span_->span_id;
112 std::shared_ptr<kcenon::monitoring::trace_span>
span_;
118 : impl_(std::make_unique<
impl>(operation_name)) {}
128 impl_->set_tag(key, value);
134 impl_->add_event(
name);
146 return impl_->trace_id();
153 return impl_->span_id();
172 std::lock_guard lock(mutex_);
182 auto& monitor = kcenon::monitoring::global_performance_monitor();
183 monitor.set_enabled(
true);
186 auto init_result = monitor.initialize();
187 if (init_result.is_err()) {
193 counters_[metrics::c_store_total] = 0;
194 counters_[metrics::c_store_success] = 0;
195 counters_[metrics::c_store_failure] = 0;
196 counters_[metrics::c_store_bytes_total] = 0;
197 counters_[metrics::c_find_total] = 0;
198 counters_[metrics::associations_total] = 0;
200 gauges_[metrics::associations_active] = 0.0;
201 gauges_[metrics::storage_instances] = 0.0;
202 gauges_[metrics::storage_bytes] = 0.0;
208 std::lock_guard lock(mutex_);
215 auto& monitor = kcenon::monitoring::global_performance_monitor();
216 auto cleanup_result = monitor.cleanup();
217 (void)cleanup_result;
219 initialized_ =
false;
223 return initialized_.load();
227 if (!initialized_)
return;
229 std::lock_guard lock(counters_mutex_);
230 counters_[std::string(
name)] += value;
234 if (!initialized_)
return;
236 std::lock_guard lock(gauges_mutex_);
237 gauges_[std::string(
name)] = value;
241 if (!initialized_ || !config_.enable_metrics)
return;
243 auto& profiler = kcenon::monitoring::global_performance_monitor().get_profiler();
245 auto duration = std::chrono::nanoseconds(
static_cast<std::int64_t
>(value * 1e9));
246 profiler.record_sample(std::string(
name), duration,
true);
250 if (!initialized_ || !config_.enable_metrics)
return;
252 auto& profiler = kcenon::monitoring::global_performance_monitor().get_profiler();
253 profiler.record_sample(std::string(
name), duration,
true);
259 if (!initialized_)
return;
263 std::lock_guard lock(counters_mutex_);
264 counters_[metrics::c_store_total]++;
266 counters_[metrics::c_store_success]++;
268 counters_[metrics::c_store_failure]++;
270 counters_[metrics::c_store_bytes_total] +=
static_cast<std::int64_t
>(bytes);
274 if (config_.enable_metrics) {
276 kcenon::monitoring::global_performance_monitor().get_profiler();
277 profiler.record_sample(metrics::c_store_duration, duration,
success);
284 if (!initialized_)
return;
288 std::lock_guard lock(counters_mutex_);
289 counters_[metrics::c_find_total]++;
293 if (config_.enable_metrics) {
295 kcenon::monitoring::global_performance_monitor().get_profiler();
296 profiler.record_sample(metrics::c_find_duration, duration,
true);
299 auto matches_as_duration =
300 std::chrono::nanoseconds(
static_cast<std::int64_t
>(matches));
301 profiler.record_sample(metrics::c_find_matches, matches_as_duration,
true);
308 if (!initialized_)
return;
312 std::lock_guard lock(counters_mutex_);
313 counters_[metrics::associations_total]++;
317 std::lock_guard lock(gauges_mutex_);
319 gauges_[metrics::associations_active]++;
321 gauges_[metrics::associations_active] =
322 (std::max)(0.0, gauges_[metrics::associations_active] - 1);
330 if (!initialized_)
return;
332 std::lock_guard lock(gauges_mutex_);
333 gauges_[metrics::storage_instances] =
static_cast<double>(total_instances);
334 gauges_[metrics::storage_bytes] =
static_cast<double>(total_bytes);
339 status.healthy =
true;
340 status.status =
"healthy";
342 std::shared_lock lock(health_checks_mutex_);
343 for (
const auto& [component, check] : health_checks_) {
345 bool component_healthy = check();
346 status.components[component] = component_healthy ?
"healthy" :
"unhealthy";
347 if (!component_healthy) {
348 status.healthy =
false;
349 status.status =
"degraded";
351 }
catch (
const std::exception& e) {
352 status.components[component] = std::string(
"error: ") + e.what();
353 status.healthy =
false;
354 status.status =
"degraded";
362 std::function<
bool()> check) {
363 std::unique_lock lock(health_checks_mutex_);
364 health_checks_[std::string(component)] = std::move(check);
368 std::unique_lock lock(health_checks_mutex_);
369 health_checks_.erase(std::string(component));
382 std::atomic<bool> initialized_{
false};
386 std::unordered_map<std::string, std::int64_t>
counters_;
387 std::unordered_map<std::string, double>
gauges_;
396 std::make_unique<monitoring_adapter::impl>();
417 std::int64_t value) {
430 std::chrono::nanoseconds duration) {
456 std::size_t total_bytes) {
465 return span(operation);
477 std::function<
bool()> check) {
std::unordered_map< std::string, std::function< bool()> > health_checks_
void record_c_find(std::chrono::nanoseconds duration, std::size_t matches, query_level level)
void increment_counter(std::string_view name, std::int64_t value)
auto is_initialized() const noexcept -> bool
std::shared_mutex health_checks_mutex_
auto get_config() const -> const monitoring_config &
void set_gauge(std::string_view name, double value)
std::unordered_map< std::string, std::int64_t > counters_
void unregister_health_check(std::string_view component)
auto get_health() -> monitoring_adapter::health_status
void update_storage_stats(std::size_t total_instances, std::size_t total_bytes)
void initialize(const monitoring_config &config)
void register_health_check(std::string_view component, std::function< bool()> check)
void record_c_store(std::chrono::nanoseconds duration, std::size_t bytes, bool success)
void record_histogram(std::string_view name, double value)
void record_timing(std::string_view name, std::chrono::nanoseconds duration)
std::unordered_map< std::string, double > gauges_
monitoring_config config_
void record_association(const std::string &calling_ae, bool established)
std::mutex counters_mutex_
std::shared_ptr< kcenon::monitoring::trace_span > span_
void set_error(const std::exception &e)
auto trace_id() const -> std::string
void set_tag(std::string_view key, std::string_view value)
void add_event(std::string_view name)
auto span_id() const -> std::string
impl(std::string_view operation_name)
auto is_valid() const noexcept -> bool
Represents a unit of work in distributed tracing.
span & operator=(const span &)=delete
~span()
Destructor - automatically finishes the span.
void set_error(const std::exception &e)
Mark the span as an error.
void set_tag(std::string_view key, std::string_view value)
Set a tag on the span.
auto span_id() const -> std::string
Get the span ID.
void add_event(std::string_view name)
Add an event to the span.
auto is_valid() const noexcept -> bool
Check if span is valid (properly initialized)
auto trace_id() const -> std::string
Get the trace ID.
span(std::string_view operation_name)
Construct a new span.
static void update_storage_stats(std::size_t total_instances, std::size_t total_bytes)
Update storage statistics.
static void record_c_find(std::chrono::nanoseconds duration, std::size_t matches, query_level level)
Record C-FIND operation metrics.
static auto get_health() -> health_status
Get current health status.
static auto get_config() -> const monitoring_config &
Get the current configuration.
static void unregister_health_check(std::string_view component)
Unregister a health check.
static void record_timing(std::string_view name, std::chrono::nanoseconds duration)
Record a timing measurement.
static void record_c_store(std::chrono::nanoseconds duration, std::size_t bytes, bool success)
Record C-STORE operation metrics.
static void record_association(const std::string &calling_ae, bool established)
Record DICOM association metrics.
static auto start_span(std::string_view operation) -> span
Start a new trace span.
static std::unique_ptr< impl > pimpl_
static void record_histogram(std::string_view name, double value)
Record a histogram sample.
static void register_health_check(std::string_view component, std::function< bool()> check)
Register a health check for a component.
static void initialize(const monitoring_config &config)
Initialize the monitoring adapter with configuration.
static void increment_counter(std::string_view name, std::int64_t value=1)
Increment a counter metric.
static void set_gauge(std::string_view name, double value)
Set a gauge metric value.
static auto query_level_to_string(query_level level) -> std::string
static void shutdown()
Shutdown the monitoring adapter.
static auto is_initialized() noexcept -> bool
Check if the monitoring adapter is initialized.
Adapter for PACS performance metrics and distributed tracing.
constexpr const char * c_find_duration
constexpr const char * storage_bytes
constexpr const char * c_find_total
constexpr const char * associations_active
constexpr const char * storage_instances
constexpr const char * associations_total
constexpr const char * c_store_total
constexpr const char * c_find_matches
constexpr const char * c_store_failure
constexpr const char * c_store_success
constexpr const char * c_store_duration
constexpr const char * c_store_bytes_total
query_level
DICOM query retrieve level.
Health check result containing component status.
Configuration options for the monitoring adapter.
bool enable_metrics
Enable metrics collection.
std::size_t max_samples_per_operation
Maximum samples to keep per operation.