refactor: 算法子类化 — LogicAlg/BoundAlg/BoundHoldAlg/FeedbackAlg 消除 exp_type_ 分支

将 ExpBase::mon_proc() 中的 exp_type_ 分支逻辑提取为 4 个子类,通过 doMonProc() 虚函数实现多态分发:
- LogicAlg (exp_type 1):实时逻辑判断
- BoundAlg (exp_type 2):监控变量上下限检测
- BoundHoldAlg (exp_type 5):持续超限检测(继承 BoundAlg)
- FeedbackAlg (exp_type 3/4):动作反馈处理

ExpBase 新增纯虚函数 doMonProc() 和钩子函数 doInitExtend(),
init() 和 mon_proc() 中所有类型分支替换为虚函数委托调用。
This commit is contained in:
Huamonarch 2026-05-15 14:37:15 +08:00
parent 4f8eecd828
commit ae7834adaa
10 changed files with 343 additions and 195 deletions

66
eqpalg/algs/bound_alg.cpp Normal file
View File

@ -0,0 +1,66 @@
#include <eqpalg/algs/bound_alg.h>
#include <eqpalg/feature_extraction/daa.h>
#include <eqpalg/utility/build_alarm_info.h>
#include <shm/RuleStatShm.h>
BoundAlg::BoundAlg(const std::string& name, const mix_cc::json& rule_json,
const std::string& ruleId, size_t exp_type)
: ExpBase(name, rule_json, ruleId, exp_type) {
logger_.reset(new LOG("BoundAlg:" + rule_name_, AUTO_CATCH_PID));
}
BoundAlg::~BoundAlg() = default;
int BoundAlg::init() {
int ret = ExpBase::init();
if (ret == 0) {
exp_is_wrong_ = false;
}
return ret;
}
void BoundAlg::doInitExtend() {
// BoundAlg 额外的初始化:上下限
reload_config_up_down();
reload_ci_dist();
last_load_time_ = std::chrono::system_clock::now();
stat_collector_.configure(rule_id_, rule_name_, dist_mode_, is_learning_);
}
bool BoundAlg::checkFilter() {
if (!expr_engine_->exps_.count("feedback")) {
return true; // 无筛选表达式,所有数据参与
}
try {
return expr_engine_->evaluateBool("feedback");
} catch (...) {
return false;
}
}
AlarmInfo BoundAlg::doMonProc() {
double result_value = expr_engine_->evaluate("act");
filter_flag_ = false;
// 数据筛选
filter_flag_ = checkFilter();
// 自学习统计
if (is_learning_ && filter_flag_) {
rule_stat_.current_value = result_value;
SingletonTemp<EqpStat>::GetInstance().add_stat_values(rule_id_, result_value);
}
// 超限检测
if (filter_flag_ && bound_checker_.isOutOfBounds(result_value)) {
rule_stat_.alarm_value = result_value;
auto msg = error_str_ + ":" + DAA::double2str(result_value) + unit_ +
",合理区间:[" + DAA::double2strLimit(bound_checker_.limitDown()) +
"," + DAA::double2strLimit(bound_checker_.limitUp()) + "]" + unit_;
query_time_range_.set_left(query_time_range_.get_right() - delay_time_);
expr_engine_->markFunVarsNeedReset();
return utility::build_alarm_info(MsgLevel::ERROR, rule_id_, rule_name_,
"EXP2", msg, get_alarm_time());
}
return AlarmInfo{};
}

19
eqpalg/algs/bound_alg.h Normal file
View File

@ -0,0 +1,19 @@
#pragma once
#include <eqpalg/algs/exp_base.h>
class BoundAlg : public ExpBase {
public:
BoundAlg(const std::string& name, const mix_cc::json& rule_json,
const std::string& ruleId,
size_t exp_type = ExpType::Bound);
~BoundAlg() override;
int init() override;
protected:
AlarmInfo doMonProc() override;
void doInitExtend() override;
// 数据筛选检查
bool checkFilter();
};

View File

@ -0,0 +1,62 @@
#include <eqpalg/algs/bound_hold_alg.h>
#include <eqpalg/feature_extraction/daa.h>
#include <eqpalg/utility/build_alarm_info.h>
BoundHoldAlg::BoundHoldAlg(const std::string& name, const mix_cc::json& rule_json,
const std::string& ruleId)
: BoundAlg(name, rule_json, ruleId, ExpType::BoundHoldTime) {
logger_.reset(new LOG("BoundHoldAlg:" + rule_name_, AUTO_CATCH_PID));
}
BoundHoldAlg::~BoundHoldAlg() = default;
int BoundHoldAlg::init() {
int ret = BoundAlg::init();
if (ret == 0) {
reload_config_up_down_hold_time();
}
return ret;
}
AlarmInfo BoundHoldAlg::doMonProc() {
double result_value = expr_engine_->evaluate("act");
filter_flag_ = checkFilter();
if (is_learning_ && filter_flag_) {
rule_stat_.current_value = result_value;
SingletonTemp<EqpStat>::GetInstance().add_stat_values(rule_id_, result_value);
}
bool is_over = bound_checker_.isOutOfBounds(result_value);
if (!filter_flag_) {
act_start_time_ = now_time_;
act_started_ = false;
} else {
if (is_over) {
if (!act_started_) {
act_started_ = true;
act_start_time_ = now_time_;
}
if ((hold_time_ <= delay_time_) ||
(now_time_ - act_start_time_ > hold_time_)) {
rule_stat_.alarm_value = result_value;
auto msg = error_str_ + ":" + DAA::double2str(result_value) + unit_ +
",合理区间:[" + DAA::double2strLimit(bound_checker_.limitDown()) +
"," + DAA::double2strLimit(bound_checker_.limitUp()) + "]" + unit_;
query_time_range_.set_left(query_time_range_.get_right() - delay_time_);
expr_engine_->markFunVarsNeedReset();
act_start_time_ = now_time_;
act_started_ = false;
return utility::build_alarm_info(
utility::get_msg_level(bound_checker_.limitDown(),
bound_checker_.limitUp(), result_value),
rule_id_, rule_name_, "EXP5", msg, get_alarm_time());
}
} else {
act_start_time_ = now_time_;
act_started_ = false;
}
}
return AlarmInfo{};
}

View File

@ -0,0 +1,14 @@
#pragma once
#include <eqpalg/algs/bound_alg.h>
class BoundHoldAlg : public BoundAlg {
public:
BoundHoldAlg(const std::string& name, const mix_cc::json& rule_json,
const std::string& ruleId);
~BoundHoldAlg() override;
int init() override;
protected:
AlarmInfo doMonProc() override;
};

View File

@ -44,16 +44,7 @@ int ExpBase::init() {
fb_fsm_.configure(keep_mode_, time_out_);
}
if (exp_type_ == ExpType::Bound || exp_type_ == ExpType::CondBound ||
exp_type_ == ExpType::BoundHoldTime) {
ret += this->reload_config_up_down(); /*7.上下限*/
this->reload_ci_dist();
this->last_load_time_ = chrono::system_clock::now();
stat_collector_.configure(rule_id_, rule_name_, dist_mode_, is_learning_);
}
if (exp_type_ == ExpType::BoundHoldTime) {
ret += this->reload_config_up_down_hold_time(); /*8.上下限-保持时间*/
}
doInitExtend();
} catch (const std::exception &e) {
logger_->Debug() << e.what() << ".location:" << BOOST_CURRENT_LOCATION
<< endl;
@ -268,195 +259,13 @@ std::vector<AlarmInfo> ExpBase::exec_task(mix_cc::time_range_t time_range) {
}
AlarmInfo ExpBase::mon_proc() {
// 监控基本过程
double result_value;
filter_flag_ = false;
expr_engine_->autoResetFunVars();
try {
// 获得是否满足前提条件表达式
result_value = expr_engine_->evaluate("act");
if (exp_type_ == ExpType::Bound || exp_type_ == ExpType::BoundHoldTime) {
try {
/*有数据筛选*/
filter_flag_ = expr_engine_->evaluateBool("feedback");
} catch (...) {
/*无数据筛选*/
logger_->Debug() << "ruleid:" << rule_id_ << ",feedback evaluate ERROR!"
<< endl;
filter_flag_ = true;
}
if (is_learning_ && filter_flag_ == true) {
rule_stat_.current_value = result_value;
SingletonTemp<EqpStat>::GetInstance().add_stat_values(this->rule_id_,
result_value);
}
}
bool act_triggered = static_cast<bool>(result_value);
// 如果是反馈模式
if (feedback_mode_) {
// === 使用 FbStateMachine ===
auto [fbState, needFunReset] = fb_fsm_.update(
act_triggered, now_time_, expr_engine_->vars(), m_tags.size());
if (needFunReset) {
expr_engine_->markFunVarsNeedReset();
}
if (fbState == FbState::Started) {
// 刚启动,下周期继续
// query_time_range 左边界设为动作开始时间
query_time_range_.set_left(now_time_);
return AlarmInfo{};
}
if (fbState == FbState::NotHold) {
return AlarmInfo{};
}
if (fbState == FbState::InProgress) {
// 检查反馈条件
bool fbCond = expr_engine_->evaluateBool("feedback");
bool done = fb_fsm_.checkFeedback(fbCond, now_time_, expr_engine_->vars());
if (done) {
// 动作完成,计算结果
query_time_range_.set_left(
query_time_range_.get_right() -
milliseconds(static_cast<int>(expr_engine_->vars()["time"])));
result_value = expr_engine_->evaluate("result");
expr_engine_->markFunVarsNeedReset();
rule_stat_.limit_down = limit_down_;
rule_stat_.limit_up = limit_up_;
rule_stat_.current_value = result_value;
if (exp_type_ == ExpType::CondBound) {
if (is_learning_) {
SingletonTemp<EqpStat>::GetInstance().add_stat_values(
rule_id_, result_value);
}
if (bound_checker_.isOutOfBounds(result_value)) {
rule_stat_.alarm_value = result_value;
std::string msg = "";
if (fb_fsm_.isTimeMode()) {
msg = error_str_ + ":" + DAA::double2str(result_value) +
"ms,时间范围:[0," + DAA::double2str(bound_checker_.limitUp()) + "] ms";
} else {
msg = error_str_ + ":" + DAA::double2str(result_value) + unit_ +
",合理区间:[" + DAA::double2strLimit(bound_checker_.limitDown()) + "," +
DAA::double2strLimit(bound_checker_.limitUp()) + "]" + unit_;
}
return utility::build_alarm_info(
utility::get_msg_level(bound_checker_.limitDown(), bound_checker_.limitUp(), result_value),
rule_id_, rule_name_, "EXP4", msg, get_alarm_time());
}
} else {
if (result_value) {
rule_stat_.alarm_value = result_value;
auto msg = rule_name_ + " " + error_str_;
return utility::build_alarm_info(MsgLevel::ERROR, rule_id_,
rule_name_, "EXP3", msg,
get_alarm_time());
}
}
}
// fbCondition 不满足,继续 InProgress
return AlarmInfo{};
}
if (fbState == FbState::Timeout) {
if (!fb_fsm_.isTimeMode()) {
return AlarmInfo{};
}
string msg =
rule_name_ + " 反馈超时:" + std::to_string(time_out_.count()) + " ms";
logger_->Debug() << msg << endl;
return utility::build_alarm_info(MsgLevel::ERROR, rule_id_, rule_name_,
"EXPACT", msg, query_time_range_);
}
// Idle state (from terminal auto-reset) — nothing to do
return AlarmInfo{};
}
// 不是动作反馈
else {
if (exp_type_ == ExpType::Bound) {
if (filter_flag_ == true && bound_checker_.isOutOfBounds(result_value)) {
rule_stat_.alarm_value = result_value;
auto msg = error_str_ + ":" + DAA::double2str(result_value) + unit_ +
",合理区间:[" + DAA::double2strLimit(bound_checker_.limitDown()) + "," +
DAA::double2strLimit(bound_checker_.limitUp()) + "]" + unit_;
logger_->Debug() << msg << endl;
this->query_time_range_.set_left(query_time_range_.get_right() -
delay_time_);
expr_engine_->markFunVarsNeedReset();
return utility::build_alarm_info(MsgLevel::ERROR, rule_id_,
rule_name_, "EXP2", msg,
this->get_alarm_time());
}
}
else if (exp_type_ == ExpType::BoundHoldTime) {
bool is_over_up_down =
bound_checker_.isOutOfBounds(result_value);
if (!filter_flag_) {
/*前提条件不满足*/
act_start_time_ = this->now_time_;
act_started_ = false;
} else {
/*前提条件满足*/
/*检查范围*/
if (is_over_up_down) {
/*超范围*/
if (!act_started_) {
// 首次检测到异常,记录开始时间
act_started_ = true;
act_start_time_ = this->now_time_;
}
/*检查时间*/
if ((hold_time_ <= delay_time_) ||
(now_time_ - act_start_time_ > hold_time_)) {
rule_stat_.alarm_value = result_value;
auto msg = error_str_ + ":" + DAA::double2str(result_value) +
unit_ + ",合理区间:[" +
DAA::double2strLimit(bound_checker_.limitDown()) + "," +
DAA::double2strLimit(bound_checker_.limitUp()) + "]" + unit_;
expr_engine_->printVars();
this->query_time_range_.set_left(query_time_range_.get_right() -
delay_time_);
expr_engine_->markFunVarsNeedReset();
act_start_time_ =
this->now_time_;
act_started_ = false;
return utility::build_alarm_info(
utility::get_msg_level(bound_checker_.limitDown(), bound_checker_.limitUp(), result_value),
rule_id_, rule_name_, "EXP5", msg, this->get_alarm_time());
}
} else {
act_start_time_ = this->now_time_;
act_started_ = false;
}
}
}
else {
if (act_triggered) {
rule_stat_.alarm_value = act_triggered;
expr_engine_->printVars();
auto msg = rule_name_ + " " + error_str_;
logger_->Debug() << msg << endl;
this->query_time_range_.set_left(query_time_range_.get_right() -
delay_time_);
expr_engine_->markFunVarsNeedReset();
return utility::build_alarm_info(MsgLevel::ERROR, rule_id_,
rule_name_, "EXP1", msg,
this->get_alarm_time());
}
}
}
return doMonProc();
} catch (const std::exception &e) {
gb_logger_->log_error("rule_name:" + rule_name_ + ",error:" + e.what());
return AlarmInfo{};
}
return AlarmInfo{};
}
bool ExpBase::get_cycled_cron() {
auto now = system_clock::now();

View File

@ -103,6 +103,17 @@ public:
bool get_prr() override;
protected:
/**
* @brief
* @return AlarmInfo
*/
virtual AlarmInfo doMonProc() = 0;
/**
* @brief
*/
virtual void doInitExtend() {}
/**
* @brief
* @return int
@ -120,7 +131,6 @@ protected:
*/
bool get_cycled_cron();
private:
/**
* @brief
* @return int
@ -128,7 +138,7 @@ private:
int reload_config_up_down();
/**
* @brief载入上
* @brief
* @return int
*/
int reload_config_up_down_hold_time();

View File

@ -0,0 +1,116 @@
#include <eqpalg/algs/feedback_alg.h>
#include <eqpalg/feature_extraction/daa.h>
#include <eqpalg/utility/build_alarm_info.h>
#include <shm/RuleStatShm.h>
FeedbackAlg::FeedbackAlg(const std::string& name, const mix_cc::json& rule_json,
const std::string& ruleId, size_t exp_type)
: ExpBase(name, rule_json, ruleId, exp_type),
hasBoundCheck_(exp_type == ExpType::CondBound) {
logger_.reset(new LOG("FeedbackAlg:" + rule_name_, AUTO_CATCH_PID));
}
FeedbackAlg::~FeedbackAlg() = default;
void FeedbackAlg::doInitExtend() {
if (hasBoundCheck_) {
reload_config_up_down();
reload_ci_dist();
last_load_time_ = std::chrono::system_clock::now();
stat_collector_.configure(rule_id_, rule_name_, dist_mode_, is_learning_);
}
}
AlarmInfo FeedbackAlg::doMonProc() {
double result_value = expr_engine_->evaluate("act");
// CondBound: filter + statistics
if (hasBoundCheck_) {
bool filter_ok = true;
try {
filter_ok = expr_engine_->evaluateBool("feedback");
} catch (...) {}
if (is_learning_ && filter_ok) {
rule_stat_.current_value = result_value;
SingletonTemp<EqpStat>::GetInstance().add_stat_values(rule_id_, result_value);
}
}
bool triggered = static_cast<bool>(result_value);
// === FbStateMachine ===
auto [fbState, needFunReset] = fb_fsm_.update(
triggered, now_time_, expr_engine_->vars(), m_tags.size());
if (needFunReset) {
expr_engine_->markFunVarsNeedReset();
}
if (fbState == FbState::Started) {
query_time_range_.set_left(now_time_);
return AlarmInfo{};
}
if (fbState == FbState::NotHold) {
return AlarmInfo{};
}
if (fbState == FbState::InProgress) {
bool fbCond = expr_engine_->evaluateBool("feedback");
bool done = fb_fsm_.checkFeedback(fbCond, now_time_, expr_engine_->vars());
if (done) {
query_time_range_.set_left(
query_time_range_.get_right() -
std::chrono::milliseconds(static_cast<int>(expr_engine_->vars()["time"])));
result_value = expr_engine_->evaluate("result");
expr_engine_->markFunVarsNeedReset();
rule_stat_.limit_down = bound_checker_.limitDown();
rule_stat_.limit_up = bound_checker_.limitUp();
rule_stat_.current_value = result_value;
if (hasBoundCheck_) {
if (is_learning_) {
SingletonTemp<EqpStat>::GetInstance().add_stat_values(
rule_id_, result_value);
}
if (bound_checker_.isOutOfBounds(result_value)) {
rule_stat_.alarm_value = result_value;
std::string msg;
if (fb_fsm_.isTimeMode()) {
msg = error_str_ + ":" + DAA::double2str(result_value) +
"ms,时间范围:[0," + DAA::double2str(bound_checker_.limitUp()) + "] ms";
} else {
msg = error_str_ + ":" + DAA::double2str(result_value) + unit_ +
",合理区间:[" + DAA::double2strLimit(bound_checker_.limitDown()) +
"," + DAA::double2strLimit(bound_checker_.limitUp()) + "]" + unit_;
}
return utility::build_alarm_info(
utility::get_msg_level(bound_checker_.limitDown(),
bound_checker_.limitUp(), result_value),
rule_id_, rule_name_, "EXP4", msg, get_alarm_time());
}
} else {
if (static_cast<bool>(result_value)) {
rule_stat_.alarm_value = result_value;
auto msg = rule_name_ + " " + error_str_;
return utility::build_alarm_info(MsgLevel::ERROR, rule_id_,
rule_name_, "EXP3", msg,
get_alarm_time());
}
}
}
return AlarmInfo{};
}
if (fbState == FbState::Timeout) {
if (fb_fsm_.isTimeMode()) {
std::string msg = rule_name_ + " 反馈超时:" +
std::to_string(time_out_.count()) + " ms";
return utility::build_alarm_info(MsgLevel::ERROR, rule_id_, rule_name_,
"EXPACT", msg, query_time_range_);
}
return AlarmInfo{};
}
return AlarmInfo{};
}

View File

@ -0,0 +1,16 @@
#pragma once
#include <eqpalg/algs/exp_base.h>
class FeedbackAlg : public ExpBase {
public:
FeedbackAlg(const std::string& name, const mix_cc::json& rule_json,
const std::string& ruleId, size_t exp_type);
~FeedbackAlg() override;
protected:
AlarmInfo doMonProc() override;
void doInitExtend() override;
private:
bool hasBoundCheck_; // CondBound (exp_type 4) vs Logic (exp_type 3)
};

24
eqpalg/algs/logic_alg.cpp Normal file
View File

@ -0,0 +1,24 @@
#include <eqpalg/algs/logic_alg.h>
#include <eqpalg/utility/build_alarm_info.h>
LogicAlg::LogicAlg(const std::string& name, const mix_cc::json& rule_json,
const std::string& ruleId)
: ExpBase(name, rule_json, ruleId, ExpType::Logic) {
logger_.reset(new LOG("LogicAlg:" + rule_name_, AUTO_CATCH_PID));
}
LogicAlg::~LogicAlg() = default;
AlarmInfo LogicAlg::doMonProc() {
double result_value = expr_engine_->evaluate("act");
if (static_cast<bool>(result_value)) {
rule_stat_.alarm_value = result_value;
auto msg = rule_name_ + " " + error_str_;
query_time_range_.set_left(query_time_range_.get_right() - delay_time_);
expr_engine_->markFunVarsNeedReset();
return utility::build_alarm_info(MsgLevel::ERROR, rule_id_, rule_name_,
"EXP1", msg, get_alarm_time());
}
return AlarmInfo{};
}

12
eqpalg/algs/logic_alg.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include <eqpalg/algs/exp_base.h>
class LogicAlg : public ExpBase {
public:
LogicAlg(const std::string& name, const mix_cc::json& rule_json,
const std::string& ruleId);
~LogicAlg() override;
protected:
AlarmInfo doMonProc() override;
};