86 double epsilon = 1e-9)
161 static std::shared_ptr<class range_trigger>
in_range(
double min_val,
double max_val);
166 static std::shared_ptr<class range_trigger>
out_of_range(
double min_val,
double max_val);
202 return "value in [" + std::to_string(
min_value_) +
", " +
205 return "value outside [" + std::to_string(
min_value_) +
", " +
216 return std::make_shared<range_trigger>(min_val, max_val,
true);
220 return std::make_shared<range_trigger>(min_val, max_val,
false);
261 std::chrono::milliseconds window,
263 size_t min_samples = 2)
270 auto now = std::chrono::steady_clock::now();
272 std::lock_guard<std::mutex> lock(
mutex_);
304 return "rate_of_change";
315 " per " + std::to_string(
window_.count()) +
"ms";
322 std::lock_guard<std::mutex> lock(
mutex_);
338 double sum_x = 0.0, sum_y = 0.0, sum_xy = 0.0, sum_xx = 0.0;
339 auto base_time =
samples_.front().timestamp;
342 double x = std::chrono::duration<double, std::milli>(
343 s.timestamp - base_time).count();
351 double n =
static_cast<double>(
samples_.size());
352 double denominator = n * sum_xx - sum_x * sum_x;
354 if (std::abs(denominator) < 1e-10) {
359 double slope = (n * sum_xy - sum_x * sum_y) / denominator;
362 return slope *
static_cast<double>(
window_.count());
401 size_t window_size = 100,
402 size_t min_samples = 10)
408 std::lock_guard<std::mutex> lock(
mutex_);
422 double mean_val =
mean();
426 if (stddev < 1e-10) {
431 double z_score = std::abs(value - mean_val) / stddev;
441 return "value > " + std::to_string(
sensitivity_) +
" std devs from mean";
448 std::lock_guard<std::mutex> lock(
mutex_);
456 std::lock_guard<std::mutex> lock(
mutex_);
464 std::lock_guard<std::mutex> lock(
mutex_);
474 return sum /
static_cast<double>(
history_.size());
483 double diff = val - mean_val;
484 sq_sum += diff * diff;
486 return std::sqrt(sq_sum /
static_cast<double>(
history_.size() - 1));
536 std::vector<std::shared_ptr<alert_trigger>>
triggers)
544 std::vector<double> values(
triggers_.size(), value);
558 std::vector<bool> results;
561 for (
size_t i = 0; i <
triggers_.size(); ++i) {
562 double val = (i < values.size()) ? values[i] : values.back();
568 return std::all_of(results.begin(), results.end(),
569 [](
bool b) { return b; });
571 return std::any_of(results.begin(), results.end(),
572 [](
bool b) { return b; });
574 size_t count = std::count(results.begin(), results.end(),
true);
578 return !results.front();
597 std::string result =
"(";
598 for (
size_t i = 0; i <
triggers_.size(); ++i) {
611 const std::vector<std::shared_ptr<alert_trigger>>&
triggers()
const {
619 static std::shared_ptr<composite_trigger>
all_of(
620 std::vector<std::shared_ptr<alert_trigger>>
triggers) {
628 static std::shared_ptr<composite_trigger>
any_of(
629 std::vector<std::shared_ptr<alert_trigger>>
triggers) {
637 static std::shared_ptr<composite_trigger>
invert(
638 std::shared_ptr<alert_trigger> trigger) {
640 std::vector<std::shared_ptr<alert_trigger>>{std::move(trigger)});
665 auto now = std::chrono::steady_clock::now();
667 std::lock_guard<std::mutex> lock(
mutex_);
673 if (previous == std::chrono::steady_clock::time_point{}) {
693 std::lock_guard<std::mutex> lock(
mutex_);
694 last_seen_ = std::chrono::steady_clock::time_point{};
722 std::lock_guard<std::mutex> lock(
mutex_);
754 std::lock_guard<std::mutex> lock(
mutex_);
Alert rule configuration and evaluation.
Trigger when no data is received for a period.
std::chrono::steady_clock::time_point last_seen_
std::string type_name() const override
Get trigger type name.
std::string description() const override
Get human-readable description.
void reset()
Reset last seen timestamp.
bool evaluate(double) const override
Evaluate the trigger condition.
absent_trigger(std::chrono::milliseconds absent_duration)
Construct an absent trigger.
std::chrono::milliseconds absent_duration_
Base class for alert trigger conditions.
Trigger based on statistical anomaly detection.
double current_mean() const
Get current mean of historical values.
bool evaluate(double value) const override
Evaluate the trigger condition.
std::deque< double > history_
anomaly_trigger(double sensitivity=3.0, size_t window_size=100, size_t min_samples=10)
Construct an anomaly trigger.
double current_stddev() const
Get current standard deviation.
std::string description() const override
Get human-readable description.
double standard_deviation(double mean_val) const
std::string type_name() const override
Get trigger type name.
void reset()
Clear historical data.
Combines multiple triggers with logical operations.
composite_operation operation_
bool evaluate(double value) const override
Evaluate with a single value (applies to all triggers)
const std::vector< std::shared_ptr< alert_trigger > > & triggers() const
Get child triggers.
std::string type_name() const override
Get trigger type name.
static std::shared_ptr< composite_trigger > all_of(std::vector< std::shared_ptr< alert_trigger > > triggers)
Create AND composite.
std::vector< std::shared_ptr< alert_trigger > > triggers_
composite_trigger(composite_operation op, std::vector< std::shared_ptr< alert_trigger > > triggers)
Construct a composite trigger.
static std::shared_ptr< composite_trigger > any_of(std::vector< std::shared_ptr< alert_trigger > > triggers)
Create OR composite.
static std::shared_ptr< composite_trigger > invert(std::shared_ptr< alert_trigger > trigger)
Create NOT composite.
bool evaluate_multi(const std::vector< double > &values) const
Evaluate with multiple values (one per trigger)
std::string description() const override
Get human-readable description.
Trigger based on change from previous value.
std::string description() const override
Get human-readable description.
delta_trigger(double delta_threshold, bool absolute=true)
Construct a delta trigger.
std::string type_name() const override
Get trigger type name.
void reset()
Reset previous value.
bool evaluate(double value) const override
Evaluate the trigger condition.
Trigger based on value being within or outside a range.
std::string type_name() const override
Get trigger type name.
bool evaluate(double value) const override
Evaluate the trigger condition.
range_trigger(double min_value, double max_value, bool inside_range)
Construct a range trigger.
std::string description() const override
Get human-readable description.
Trigger based on rate of change of values.
rate_direction direction_
bool evaluate(double value) const override
Evaluate the trigger condition.
double calculate_rate() const
std::chrono::milliseconds window_
rate_direction
Direction of rate change to monitor.
@ either
Absolute rate of change.
@ increasing
Positive rate of change.
@ decreasing
Negative rate of change.
std::string description() const override
Get human-readable description.
void reset()
Clear accumulated samples.
rate_of_change_trigger(double rate_threshold, std::chrono::milliseconds window, rate_direction direction=rate_direction::either, size_t min_samples=2)
Construct a rate of change trigger.
std::string type_name() const override
Get trigger type name.
std::deque< sample > samples_
Trigger based on comparing value against a threshold.
double threshold() const
Get the threshold value.
static std::shared_ptr< threshold_trigger > below_or_equal(double threshold)
Create trigger for value <= threshold.
static std::shared_ptr< threshold_trigger > below(double threshold)
Create trigger for value < threshold.
static std::shared_ptr< class range_trigger > in_range(double min_val, double max_val)
Create trigger for value within range (inclusive)
std::string type_name() const override
Get trigger type name.
std::string description() const override
Get human-readable description.
comparison_operator op() const
Get the comparison operator.
static std::shared_ptr< threshold_trigger > above_or_equal(double threshold)
Create trigger for value >= threshold.
bool evaluate(double value) const override
Evaluate the trigger condition.
static std::shared_ptr< class range_trigger > out_of_range(double min_val, double max_val)
Create trigger for value outside range (exclusive)
threshold_trigger(double threshold, comparison_operator op=comparison_operator::greater_than, double epsilon=1e-9)
Construct a threshold trigger.
comparison_operator operator_
static std::shared_ptr< threshold_trigger > above(double threshold)
Create trigger for value > threshold.
comparison_operator
Comparison operators for threshold triggers.
@ equal
value == threshold (with epsilon)
@ less_or_equal
value <= threshold
@ less_than
value < threshold
@ not_equal
value != threshold (with epsilon)
@ greater_or_equal
value >= threshold
@ greater_than
value > threshold
composite_operation
Logical operations for combining triggers.
@ NOT
Invert single trigger (uses first trigger only)
@ AND
All triggers must fire.
@ XOR
Exactly one trigger fires.
constexpr const char * comparison_operator_to_string(comparison_operator op) noexcept
Convert comparison operator to string.
std::chrono::steady_clock::time_point timestamp