|
|
|
|
@ -7,9 +7,20 @@ from iti.applications.models import (
|
|
|
|
|
IotAlertLog,
|
|
|
|
|
IotAlertRule,
|
|
|
|
|
IotAlertPush,
|
|
|
|
|
IotNode,
|
|
|
|
|
IotEndpoint,
|
|
|
|
|
)
|
|
|
|
|
from sqlalchemy import select, distinct
|
|
|
|
|
from simpleeval import simple_eval
|
|
|
|
|
|
|
|
|
|
def delete_node_alert_rule(node: IotNode):
|
|
|
|
|
"""
|
|
|
|
|
删除节点告警规则
|
|
|
|
|
Args:
|
|
|
|
|
node: 节点对象
|
|
|
|
|
"""
|
|
|
|
|
db.session.query(IotAlertRule).filter_by(node_id=node.id).delete()
|
|
|
|
|
db.session.commit()
|
|
|
|
|
|
|
|
|
|
def add_endpoint_alert_log(endpoint_id: int):
|
|
|
|
|
"""
|
|
|
|
|
@ -42,6 +53,81 @@ def add_endpoint_alert_log(endpoint_id: int):
|
|
|
|
|
db.session.commit()
|
|
|
|
|
return ""
|
|
|
|
|
|
|
|
|
|
def add_node_alert_log(node_id: int, alert_value: str):
|
|
|
|
|
"""
|
|
|
|
|
添加节点值异常告警日志
|
|
|
|
|
Args:
|
|
|
|
|
node_id: 节点ID
|
|
|
|
|
alert_value: 告警值
|
|
|
|
|
"""
|
|
|
|
|
node = db.session.scalar(select(IotNode).filter_by(id=node_id))
|
|
|
|
|
if not node:
|
|
|
|
|
return "节点不存在"
|
|
|
|
|
|
|
|
|
|
alert_rule_list = db.session.scalars(select(IotAlertRule).filter_by(node_id=node_id)).all()
|
|
|
|
|
if len(alert_rule_list) > 0:
|
|
|
|
|
for alert_rule in alert_rule_list:
|
|
|
|
|
if alert_rule.status == 1:
|
|
|
|
|
# 根据data_type转换alert_value
|
|
|
|
|
value_data = get_value(node.data_type, alert_value)
|
|
|
|
|
# 检查告警值是否满足触发规则
|
|
|
|
|
if is_alert_trigger(alert_rule.alert_rule, value_data):
|
|
|
|
|
alert_tag = f"ep{node.endpoint_id}_nd{node_id}"
|
|
|
|
|
alert_log = db.session.scalar(select(IotAlertLog).filter_by(alert_tag=alert_tag))
|
|
|
|
|
if alert_log:
|
|
|
|
|
alert_log.trigger_count += 1
|
|
|
|
|
alert_log.alert_content = complete_alert_text(node, alert_rule, alert_value)
|
|
|
|
|
if alert_log.trigger_count >= alert_rule.trigger_count:
|
|
|
|
|
alert_log.status = 1
|
|
|
|
|
push_alert(alert_log)
|
|
|
|
|
else:
|
|
|
|
|
dict_data = dict(
|
|
|
|
|
alert_tag=alert_tag,
|
|
|
|
|
alert_target_name=f"采集节点({node.node_number})",
|
|
|
|
|
alert_level=alert_rule.alert_level,
|
|
|
|
|
status=0,
|
|
|
|
|
trigger_count=1,
|
|
|
|
|
alert_content=complete_alert_text(node, alert_rule, alert_value),
|
|
|
|
|
)
|
|
|
|
|
alert_log = IotAlertLog(**dict_data)
|
|
|
|
|
db.session.add(alert_log)
|
|
|
|
|
db.session.commit()
|
|
|
|
|
else:
|
|
|
|
|
current_app.logger.info(f"节点{node.node_number}值{alert_value}未触发告警规则{alert_rule.alert_rule}")
|
|
|
|
|
|
|
|
|
|
return ""
|
|
|
|
|
|
|
|
|
|
def get_value(data_type: str, alert_value: str):
|
|
|
|
|
"""
|
|
|
|
|
获取告警值
|
|
|
|
|
Args:
|
|
|
|
|
data_type: 数据类型
|
|
|
|
|
alert_value: 告警值
|
|
|
|
|
"""
|
|
|
|
|
if data_type == "int":
|
|
|
|
|
return int(alert_value)
|
|
|
|
|
elif data_type == "float":
|
|
|
|
|
return float(alert_value)
|
|
|
|
|
elif data_type == "double":
|
|
|
|
|
return float(alert_value)
|
|
|
|
|
else:
|
|
|
|
|
return alert_value
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def is_alert_trigger(alert_rule_text: str, value_data: Any):
|
|
|
|
|
"""
|
|
|
|
|
检查告警值是否满足触发规则
|
|
|
|
|
Args:
|
|
|
|
|
alert_rule_text: 告警规则文本
|
|
|
|
|
value_data: 告警值
|
|
|
|
|
"""
|
|
|
|
|
# 解析告警规则文本,判断是否满足触发规则
|
|
|
|
|
try:
|
|
|
|
|
result = simple_eval_expression(alert_rule_text, {'x': value_data})
|
|
|
|
|
return result
|
|
|
|
|
except (NameError, SyntaxError, TypeError) as e:
|
|
|
|
|
current_app.logger.error(f"评估表达式 {alert_rule_text} 时出错: {e}")
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def push_alert(alert_log: IotAlertLog):
|
|
|
|
|
"""
|
|
|
|
|
@ -51,8 +137,34 @@ def push_alert(alert_log: IotAlertLog):
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
level = f"{alert_log.alert_level}"
|
|
|
|
|
alert_push_list = db.session.scalars(select(IotAlertPush).filter(IotAlertPush.alert_level.contains(level))).all()
|
|
|
|
|
alert_push_list = db.session.scalars(select(IotAlertPush).filter(IotAlertPush.alert_level.contains(level)).filter_by(status=1)).all()
|
|
|
|
|
if alert_push_list:
|
|
|
|
|
for alert_push in alert_push_list:
|
|
|
|
|
# TODO 调用地址发送告警消息
|
|
|
|
|
current_app.logger.info(f"推送告警消息到 {alert_push.push_url},内容:{alert_log.alert_content}")
|
|
|
|
|
|
|
|
|
|
def complete_alert_text(node: IotNode, alert_rule: IotAlertRule, alert_value: str):
|
|
|
|
|
"""
|
|
|
|
|
完善告警内容文本
|
|
|
|
|
Args:
|
|
|
|
|
node: 节点
|
|
|
|
|
alert_rule: 告警规则
|
|
|
|
|
alert_value: 告警值
|
|
|
|
|
"""
|
|
|
|
|
alert_text_temp = alert_rule.alert_text or ""
|
|
|
|
|
alert_text_temp = alert_text_temp.replace("{_workshopName_}", node.workshop.workshop_name+"("+node.workshop.workshop_number+")")
|
|
|
|
|
alert_text_temp = alert_text_temp.replace("{_deviceName_}", node.device.device_name+"("+node.device.device_number+")")
|
|
|
|
|
alert_text_temp = alert_text_temp.replace("{_endpointName_}", node.endpoint.endpoint_name+"("+node.endpoint.endpoint_number+")")
|
|
|
|
|
alert_text_temp = alert_text_temp.replace("{_mark_}", node.mark)
|
|
|
|
|
alert_text_temp = alert_text_temp.replace("{_nodeNumber_}", node.node_number)
|
|
|
|
|
alert_text_temp = alert_text_temp.replace("{_alertValue_}", alert_value)
|
|
|
|
|
return alert_text_temp
|
|
|
|
|
|
|
|
|
|
def simple_eval_expression(expr, variables):
|
|
|
|
|
"""
|
|
|
|
|
简单地评估包含变量的字符串表达式
|
|
|
|
|
:param expr: 字符串表达式,如 "x > 5 and y < 10"
|
|
|
|
|
:param variables: 变量字典,如 {'x': 7, 'y': 3}
|
|
|
|
|
:return: 表达式结果
|
|
|
|
|
"""
|
|
|
|
|
return simple_eval(expr, names=variables)
|