348 lines
14 KiB
C++
348 lines
14 KiB
C++
|
|
#include <eqpalg/algs/exp_sample.h>
|
|||
|
|
#include <zlib/MemVar.h>
|
|||
|
|
|
|||
|
|
int ExpSample::init() {
|
|||
|
|
int ret = 0;
|
|||
|
|
act_started_ = false;
|
|||
|
|
try {
|
|||
|
|
Exp::init();
|
|||
|
|
// 载入样本配置
|
|||
|
|
this->reload_config_sample();
|
|||
|
|
sample_stat_ = std::make_unique<stat_tools::Frame>(
|
|||
|
|
rule_id_, rule_name_, dims_, test_mode_, start_date_, end_date_,
|
|||
|
|
padding_low_, padding_up_, is_no_down_limit_);
|
|||
|
|
// 目前暂时使用小时作为归档的单位间隔
|
|||
|
|
sample_stat_->set_archive_interval(hours(archive_interval_day_));
|
|||
|
|
this->sample_stat_->set_prob(this->judge_diff_);
|
|||
|
|
this->sample_stat_->load_data(); ///<加载db2的统计数据 本地文件的特征数据
|
|||
|
|
|
|||
|
|
} catch (const std::exception& e) {
|
|||
|
|
logger_->Info() << "数据载入错误 :" << rule_name_ << endl; // 测试
|
|||
|
|
std::throw_with_nested(
|
|||
|
|
mix_cc::Exception(-1, "数据载入发生异常", BOOST_CURRENT_LOCATION));
|
|||
|
|
ret = -1;
|
|||
|
|
}
|
|||
|
|
return ret;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
AlarmInfo ExpSample::exec_mon() {
|
|||
|
|
AlarmInfo out_alarm;
|
|||
|
|
// 刷新当前时间
|
|||
|
|
this->refresh_now_time();
|
|||
|
|
try {
|
|||
|
|
// 如果当前时间比上次数据载入时间晚10小时以上,刷新数据
|
|||
|
|
if (now_time_ - last_load_time_ > hours(archive_interval_day_ * 10)) {
|
|||
|
|
// 1.从db2载入数据分布信息;2.从本地文件载入数据特征值;3.计算置信区间
|
|||
|
|
this->sample_stat_->load_data();
|
|||
|
|
last_load_time_ = now_time_;
|
|||
|
|
}
|
|||
|
|
switch (data_source_) {
|
|||
|
|
case DataSource::MEMORY: {
|
|||
|
|
// 刷新内存对应的变量数据
|
|||
|
|
refresh_exp_vars_mem();
|
|||
|
|
query_time_range_.set_left(query_time_range_.get_right() -
|
|||
|
|
delay_time_); // 2021-10-27 刷新报警开始时间
|
|||
|
|
out_alarm = mon_proc();
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case DataSource::IHDB: {
|
|||
|
|
// 刷新ihdb缓存
|
|||
|
|
refresh_ihd_cache();
|
|||
|
|
for (auto i = 0; i < queried_data_.rows(); i++) {
|
|||
|
|
// 刷新ihdb对应的变量数据
|
|||
|
|
refresh_exp_vars_ihd(i);
|
|||
|
|
if (!out_alarm.alarmed) {
|
|||
|
|
auto tmp = mon_proc();
|
|||
|
|
if (tmp.alarmed) {
|
|||
|
|
out_alarm = (tmp);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} break;
|
|||
|
|
default:
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
} catch (const std::exception& e) {
|
|||
|
|
std::throw_with_nested(
|
|||
|
|
mix_cc::Exception(-1, "监控进程执行错误", BOOST_CURRENT_LOCATION));
|
|||
|
|
}
|
|||
|
|
return out_alarm;
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* @brief 计算统计类的第一次 写本地数据特征和db2数据分布信息
|
|||
|
|
* @return mix_cc::json
|
|||
|
|
*/
|
|||
|
|
mix_cc::json ExpSample::exec_cron() {
|
|||
|
|
bool jump_out_flag = false;
|
|||
|
|
try {
|
|||
|
|
// 1.首次运行cron目的在于计算步长(组距),同时累积rs的样本;
|
|||
|
|
// 2.非首次运行cron目的在于累积样本,包括rs和分布信息
|
|||
|
|
// 3.没有组距,则被视作首次运行cron
|
|||
|
|
// 4.cron的计算需考虑机组的状态,不要累计停机数据
|
|||
|
|
// if (sample_stat_->is_first_sampling()) {
|
|||
|
|
SampleWindow tmp_data; // 存db2 的样本 -2021-10-29
|
|||
|
|
// if (this->test_mode_ >= stat_tools::TestMode::normal_dist_diff) {
|
|||
|
|
auto time_end = system_clock::now();
|
|||
|
|
auto time_start = time_end - STASTIC_DAYS * 24h;
|
|||
|
|
TimeDur f_delay_time = 5 * delay_time_;
|
|||
|
|
this->query_time_range_.set_left(time_start - 2 * f_delay_time);
|
|||
|
|
this->query_time_range_.set_right(time_start - f_delay_time);
|
|||
|
|
// 目的在于刷pv变量 f_delay_time start end
|
|||
|
|
this->now_time_ = time_start;
|
|||
|
|
// refresh_ihd_cache(this->delay_time_);
|
|||
|
|
refresh_ihd_cache(); //刷 queried_time_,
|
|||
|
|
// queried_data_,query_time_range_(左右相差f_delay_time)
|
|||
|
|
// 本次查询5天前-f_delay_time 到五天前
|
|||
|
|
for (auto i = 0; i < queried_data_.rows(); i++) {
|
|||
|
|
refresh_exp_vars_ihd(i);
|
|||
|
|
} // !end or (auto i = 0; i < queried_data_.rows(); i++)
|
|||
|
|
// 刷一遍缓存数据 刷到5天前的(4 3 2 1)个50ms之前的值 pv变量
|
|||
|
|
//
|
|||
|
|
for (auto t = time_start; t < time_end; t += query_interval_time_) {
|
|||
|
|
this->now_time_ = t;
|
|||
|
|
gb_logger_->log_info("执行,当前时间" +
|
|||
|
|
mix_cc::mix_time_t(now_time_).to_formatted_time());
|
|||
|
|
refresh_ihd_cache();
|
|||
|
|
// 如果机组检查发现没开机,则不累计数据
|
|||
|
|
if (!cron_check_is_line_start()) {
|
|||
|
|
gb_logger_->log_info(
|
|||
|
|
this->rule_id_ + ":当前时间段:" +
|
|||
|
|
mix_cc::mix_time_t(this->query_time_range_.get_left())
|
|||
|
|
.to_formatted_time() +
|
|||
|
|
"~" +
|
|||
|
|
mix_cc::mix_time_t(this->query_time_range_.get_right())
|
|||
|
|
.to_formatted_time() +
|
|||
|
|
"存在机组停机情况");
|
|||
|
|
// return {};
|
|||
|
|
}
|
|||
|
|
// queried_data_每一行都进行如下操作
|
|||
|
|
// 每一行相差 ihd_min_time_particles_
|
|||
|
|
// 即iHyperDB数据查询最小时间颗粒(默认50ms)
|
|||
|
|
else {
|
|||
|
|
for (auto i = 0; i < queried_data_.rows(); i++) {
|
|||
|
|
refresh_exp_vars_ihd(i);
|
|||
|
|
auto o_value = this->cron_proc_sample(); ///< 筛选后的样本
|
|||
|
|
if (o_value.has_value()) {
|
|||
|
|
tmp_data.push_back(o_value.value());
|
|||
|
|
// 3小时的最大数据量为 216000
|
|||
|
|
if (tmp_data.size() > 216000) {
|
|||
|
|
gb_logger_->log_error(
|
|||
|
|
"数据量异常,超过3小时的最大数据,暂停执行");
|
|||
|
|
jump_out_flag = true;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
if (jump_out_flag) {
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
} // !end if (o_value.has_value())
|
|||
|
|
} // !end for (auto i = 0; i < queried_data_.rows(); i++)
|
|||
|
|
// if (this->test_mode_ == stat_tools::TestMode::degrad &&
|
|||
|
|
// !tmp_data.empty()) {
|
|||
|
|
// gb_logger_->log_info("开始执行-执行完成:" + rule_name_);
|
|||
|
|
// this->sample_stat_->cron_sampling_data(tmp_data, now_time_);
|
|||
|
|
// tmp_data.clear();
|
|||
|
|
// }
|
|||
|
|
if (this->test_mode_ != stat_tools::TestMode::degrad &&
|
|||
|
|
!tmp_data.empty()) {
|
|||
|
|
gb_logger_->log_info("开始执行-执行完成:" + rule_name_);
|
|||
|
|
this->sample_stat_->cron_sampling_data(tmp_data, now_time_);
|
|||
|
|
tmp_data.clear();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
} //机组开机的情况
|
|||
|
|
} // !end for (auto t = time_start; t < time_end; t +=
|
|||
|
|
// query_interval_time_)
|
|||
|
|
// } // !end if (this->test_mode_ >=
|
|||
|
|
// stat_tools::TestMode::normal_dist_diff) } //! end if
|
|||
|
|
// (sample_stat_->is_first_sampling())
|
|||
|
|
} //! end try
|
|||
|
|
catch (const std::exception& e) {
|
|||
|
|
gb_logger_->log_exception(e);
|
|||
|
|
}
|
|||
|
|
return {};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
AlarmInfo ExpSample::exec_normal_task(mix_cc::time_range_t time_range) {
|
|||
|
|
gb_logger_->log_info("exec_normal_task:" + rule_name_);
|
|||
|
|
gb_logger_->log_info(
|
|||
|
|
"开始时间:" +
|
|||
|
|
mix_cc::mix_time_t(time_range.get_left()).to_formatted_time());
|
|||
|
|
gb_logger_->log_info(
|
|||
|
|
"结束时间:" +
|
|||
|
|
mix_cc::mix_time_t(time_range.get_right()).to_formatted_time());
|
|||
|
|
SampleWindow tmp_data;
|
|||
|
|
//刷一遍mmvar
|
|||
|
|
TimeDur f_delay_time = 5 * delay_time_;
|
|||
|
|
auto time_end = time_range.get_right();
|
|||
|
|
auto time_start = time_range.get_left();
|
|||
|
|
query_interval_time_ = std::chrono::duration_cast<std::chrono::milliseconds>(
|
|||
|
|
time_end - time_start);
|
|||
|
|
this->query_time_range_.set_left(time_start - 2 * query_interval_time_);
|
|||
|
|
this->query_time_range_.set_right(time_start - query_interval_time_);
|
|||
|
|
|
|||
|
|
// 目的在于刷pv变量 query_interval_time_ start end
|
|||
|
|
this->now_time_ = time_start;
|
|||
|
|
refresh_ihd_cache(this->delay_time_); //刷 queried_time_,query_time_range_
|
|||
|
|
{
|
|||
|
|
gb_logger_->log_info(
|
|||
|
|
"ihd查询开始时间1:" +
|
|||
|
|
mix_cc::mix_time_t(query_time_range_.get_left()).to_formatted_time());
|
|||
|
|
gb_logger_->log_info(
|
|||
|
|
"ihd查询结束时间1:" +
|
|||
|
|
mix_cc::mix_time_t(query_time_range_.get_right()).to_formatted_time());
|
|||
|
|
gb_logger_->log_info("ihd查询的时间间隔:" +
|
|||
|
|
std::to_string(delay_time_.count()));
|
|||
|
|
gb_logger_->log_info("ihd查询的数据量:" +
|
|||
|
|
std::to_string(queried_data_.rows()));
|
|||
|
|
}
|
|||
|
|
for (auto i = 0; i < queried_data_.rows(); i++) {
|
|||
|
|
refresh_exp_vars_ihd(i);
|
|||
|
|
} // 刷 mmvar
|
|||
|
|
this->now_time_ = time_end; // 防止出问题,没有实际用处
|
|||
|
|
|
|||
|
|
refresh_ihd_cache(this->delay_time_); //
|
|||
|
|
{ // 日志
|
|||
|
|
gb_logger_->log_info(
|
|||
|
|
"ihd查询开始时间2:" +
|
|||
|
|
mix_cc::mix_time_t(query_time_range_.get_left()).to_formatted_time());
|
|||
|
|
gb_logger_->log_info(
|
|||
|
|
"ihd查询结束时间2:" +
|
|||
|
|
mix_cc::mix_time_t(query_time_range_.get_right()).to_formatted_time());
|
|||
|
|
gb_logger_->log_info("ihd查询的时间间隔:" +
|
|||
|
|
std::to_string(delay_time_.count()));
|
|||
|
|
gb_logger_->log_info("ihd查询的数据量:" +
|
|||
|
|
std::to_string(queried_data_.rows()));
|
|||
|
|
}
|
|||
|
|
for (auto i = 0; i < queried_data_.rows(); i++) {
|
|||
|
|
refresh_exp_vars_ihd(i);
|
|||
|
|
auto o_value = this->cron_proc_sample();
|
|||
|
|
if (o_value.has_value()) {
|
|||
|
|
tmp_data.push_back(o_value.value());
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (this->test_mode_ == stat_tools::TestMode::normal_dist_diff) {
|
|||
|
|
StatAlarm alarm_info;
|
|||
|
|
try {
|
|||
|
|
alarm_info = this->sample_stat_->get_task_normal_info(tmp_data);
|
|||
|
|
} catch (std::exception& e) {
|
|||
|
|
logger_->Error() << "get_task_normal_info执行错误: " << this->rule_name_
|
|||
|
|
<< std::endl;
|
|||
|
|
}
|
|||
|
|
if (alarm_info) {
|
|||
|
|
gb_logger_->log_info("exec_normal_task:" + rule_name_ +
|
|||
|
|
alarm_info.alarm_str);
|
|||
|
|
return utility::build_alarm_info(MsgLevel::INFO, rule_id_, rule_name_,
|
|||
|
|
"EXPSMP", alarm_info.alarm_str,
|
|||
|
|
query_time_range_);
|
|||
|
|
} else {
|
|||
|
|
gb_logger_->log_info(" alarm_info.alarm_str获取失败:" + rule_name_);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int ExpSample::reload_config_sample() {
|
|||
|
|
try {
|
|||
|
|
archive_interval_day_ =
|
|||
|
|
rule_json_.at("sample").at("archive").at(1).get<int>();
|
|||
|
|
logger_->Debug() << "archive:" << archive_interval_day_ << endl;
|
|||
|
|
start_date_ =
|
|||
|
|
mix_cc::mix_time_t(
|
|||
|
|
rule_json_.at("sample").at("datestart").at(1).get<std::string>(),
|
|||
|
|
"%Y-%m-%d")
|
|||
|
|
.to_chrono_time();
|
|||
|
|
end_date_ =
|
|||
|
|
mix_cc::mix_time_t(
|
|||
|
|
rule_json_.at("sample").at("dateend").at(1).get<std::string>(),
|
|||
|
|
"%Y-%m-%d")
|
|||
|
|
.to_chrono_time();
|
|||
|
|
if (rule_json_.at("alarm_option").contains("value")) {
|
|||
|
|
auto tmp_exp =
|
|||
|
|
rule_json_.at("alarm_option").at("value").at(1).get<std::string>();
|
|||
|
|
exp_str_ = get_macro_replaced_exp(tmp_exp);
|
|||
|
|
if (exp_result_ == nullptr) {
|
|||
|
|
exp_result_ =
|
|||
|
|
std::make_unique<mix_cc::matheval::Expression>(exp_str_, &mm_vars);
|
|||
|
|
logger_->Debug() << exp_str_ << ":" << exp_result_->evaluate() << endl;
|
|||
|
|
} else {
|
|||
|
|
logger_->Info() << "指针已经初始化完成" << exp_str_ << ":"
|
|||
|
|
<< exp_result_->evaluate() << endl;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (rule_json_.at("alarm_option").contains("sample_is_infinite_mode")) {
|
|||
|
|
this->is_no_down_limit_ =
|
|||
|
|
static_cast<bool>(rule_json_.at("alarm_option")
|
|||
|
|
.at("sample_is_infinite_mode")
|
|||
|
|
.at(1)
|
|||
|
|
.get<int>());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
test_mode_ = static_cast<stat_tools::TestMode>(
|
|||
|
|
rule_json_.at("alarm_option").at("mode").at(1).get<int>());
|
|||
|
|
judge_diff_ = rule_json_.at("alarm_option").at("diff").at(1).get<double>();
|
|||
|
|
error_str_ =
|
|||
|
|
rule_json_.at("alarm_option").at("error").at(1).get<std::string>();
|
|||
|
|
logger_->Debug()
|
|||
|
|
<< "modejudge(0: absolute difference, 1: error percentage (%), 2: "
|
|||
|
|
"normal value signal (%),3. dtw curve distance(%), 4.poly fit(%)"
|
|||
|
|
<< static_cast<int>(test_mode_) << " samplediff:" << judge_diff_
|
|||
|
|
<< endl;
|
|||
|
|
} catch (std::exception& e) {
|
|||
|
|
logger_->Error() << "表达式-样本取样异常,表达式为: " << exp_str_
|
|||
|
|
<< std::endl;
|
|||
|
|
throw_with_nested(
|
|||
|
|
mix_cc::Exception(-1, "表达式样本载入错误", BOOST_CURRENT_LOCATION));
|
|||
|
|
}
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int ExpSample::log_action_info(double result_value) {
|
|||
|
|
this->print_exp_vars(exp_str_);
|
|||
|
|
logger_->Debug() << " action start:"
|
|||
|
|
<< mix_cc::mix_time_t(act_start_time_).to_formatted_time()
|
|||
|
|
<< ",end:"
|
|||
|
|
<< mix_cc::mix_time_t(now_time_).to_formatted_time()
|
|||
|
|
<< ",timediff:" << mm_vars["time"]
|
|||
|
|
<< ",value:" << result_value << endl;
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool ExpSample::cron_check_is_line_start() {
|
|||
|
|
// 1.查数据
|
|||
|
|
const string tagname_main_speed =
|
|||
|
|
string(CMemVar::Const()->UnitNo) + "_" +
|
|||
|
|
string(CMemVar::Const()->eis_tagname_main_speed);
|
|||
|
|
vector<string> main_speed_ihd({tagname_main_speed});
|
|||
|
|
TimeDur check_internal = 2s;
|
|||
|
|
auto queried_batch_maybe = mix_cc::ihd::make_query_batch_maybe(
|
|||
|
|
main_speed_ihd, query_time_range_, check_internal);
|
|||
|
|
if (queried_batch_maybe.is_nothing()) {
|
|||
|
|
this->gb_logger_->log_error(
|
|||
|
|
this->rule_name_ +
|
|||
|
|
":ihd没有查到tagname_main_speed:" + tagname_main_speed + "的信息");
|
|||
|
|
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
auto queried_bath = queried_batch_maybe.unsafe_get_just();
|
|||
|
|
auto result_maybe = mix_cc::ihd::read_data_with_time_maybe(&queried_bath);
|
|||
|
|
if (result_maybe.is_nothing()) {
|
|||
|
|
this->gb_logger_->log_error(
|
|||
|
|
this->rule_name_ +
|
|||
|
|
":ihd没有查到tagname_main_speed:" + tagname_main_speed + "的数据");
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
// 2.检查机组速度
|
|||
|
|
Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> queried_data;
|
|||
|
|
vector<TimePoint> queried_time;
|
|||
|
|
std::tie(queried_time, queried_data) = result_maybe.unsafe_get_just();
|
|||
|
|
for (size_t i = 0; i < queried_data.rows(); i++) {
|
|||
|
|
if (std::abs(queried_data(i, 0)) < std::numeric_limits<double>::min()) {
|
|||
|
|
// this->gb_logger_->log_error(
|
|||
|
|
// this->rule_name_ + "时间:" +
|
|||
|
|
// mix_cc::mix_time_t(queried_time[i]).to_formatted_time() +
|
|||
|
|
// "时,机组速度:" + std::to_string(queried_data(i, 0)));
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return true;
|
|||
|
|
}
|