Browse Source

邮件告警推送 88%

dev
巴林闲侠 2 years ago
parent
commit
28b754c877
  1. 2
      api/.vscode/launch.json
  2. 352
      api/app/lib/schedule/alarms_push.js

2
api/.vscode/launch.json

@ -56,7 +56,7 @@
// "--clickHouseDataAlarm default",
//
"--clickHouseAnxincloud Anxinyun22",
"--clickHouseAnxincloud Anxinyun23",
"--clickHousePepEmis pepca8",
"--clickHouseProjectManage peppm8",
"--clickHouseVcmp video_access_dev",

352
api/app/lib/schedule/alarms_push.js

@ -5,7 +5,7 @@ module.exports = function (app, opts) {
{
interval: '12 */1 * * * *',
immediate: true, // dev
proRun: true,
// proRun: true,
},
async () => {
try {
@ -18,13 +18,14 @@ module.exports = function (app, opts) {
where: {
del: false
},
order: ['id'],
include: [{
model: models.ProjectCorrelation,
where: {
del: false
},
required: true
}]
}],
})
let pepProjectIds = new Set()
for (let { dataValues: c } of configListRes) {
@ -112,6 +113,9 @@ module.exports = function (app, opts) {
).toPromise() :
[]
let searchStrucIds = strucListRes.map(s => s.id)
searchStrucIds = searchStrucIds.concat([991, 1052, 700])
if (searchStrucIds.length) {
searchStrucIds.unshift(-1)
}
@ -139,42 +143,58 @@ module.exports = function (app, opts) {
let alarmCameraCount = 0
// 判断推送策略
let nowTime = moment().startOf('minute')
let pointTime = moment().subtract(parseInt(interval), 'minute').startOf('minute').format('YYYY-MM-DD HH:mm:ss')
let pointTime =
moment()
.subtract(
parseInt(interval),
// + 1440 * 365,
'minute'
)
.startOf('minute')
.format('YYYY-MM-DD HH:mm:ss')
let newAddStartTime = pointTime
let newAddEndTime = nowTime.clone()
if (c.tactics == 'immediately') {
// !查所有未解决告警 所以时间范围大可不必
// dataAlarmOption.push(`StartTime >= '${pointTime}'`);
// appAlarmWhereOption.createTime = { $gte: pointTime }
// videoAlarmWhereOption.push(`camera_status_alarm.create_time >= '${pointTime}'`)
emailTitle += `即时推送服务`
emailSubTitle += `截止${moment(pointTime).format('YYYY年MM月DD日 HH时mm分')}-${moment(nowTime).format('HH时mm分')}`
} else if (c.tactics == 'continue') {
// dataAlarmOption.push(`StartTime <= '${pointTime}'`);
// appAlarmWhereOption.createTime = { $lte: pointTime }
// videoAlarmWhereOption.push(`camera_status_alarm.create_time <= '${pointTime}'`)
emailTitle += `持续时长推送服务`
emailSubTitle += `告警持续时长超${interval}分钟的告警源,详情如下:`
} else if (c.tactics == 'abnormal_rate') {
// dataAlarmOption.push(`StartTime <= '${pointTime}'`);
if (c.alarmType.includes('data_outages') || c.alarmType.includes('data_exception')) {
// 查了设备异常率 去安心云查当前项目下的设备数量
// TODO 等同步以太数据再查
deviceCount = 9999
// await clickHouse.anxinyun.query(`
// SELECT count(*) FROM
// `).toPromise()
}
if (c.alarmType.includes('video_exception')) {
// 查了视频异常 去安心云查 接入的 萤石 设备数量
cameraCount = searchStrucIds.length ?
(await clickHouse.anxinyun.query(`
SELECT count(*) AS count FROM t_video_ipc
WHERE structure IN (${searchStrucIds.join(',')})
`).toPromise())[0].count
: 0
} else if (c.tactics == 'continue' || c.tactics == 'abnormal_rate') {
// 新增的应该是上一个时间节点到上上个节点之间
dataAlarmOption.push(`StartTime <= '${pointTime}'`);
appAlarmWhereOption.createTime = { $lte: pointTime }
videoAlarmWhereOption.push(`camera_status_alarm.create_time <= '${pointTime}'`)
// 新增的应该是上一个时间节点到上上个节点之间
newAddStartTime = moment(pointTime).subtract(parseInt(interval)).format('YYYY-MM-DD HH:mm:ss')
newAddEndTime = pointTime
if (c.tactics == 'continue') {
emailTitle += `持续时长推送服务`
emailSubTitle += `告警持续时长超${interval}分钟的告警源,详情如下:`
} else {
if (c.alarmType.includes('data_outages') || c.alarmType.includes('data_exception')) {
// 查了设备异常率 去安心云查当前项目下的设备数量
// TODO 等同步以太数据再查
deviceCount = 9999
// await clickHouse.anxinyun.query(`
// SELECT count(*) FROM
// `).toPromise()
}
if (c.alarmType.includes('video_exception')) {
// 查了视频异常 去安心云查 接入的 萤石 设备数量
cameraCount = searchStrucIds.length ?
(await clickHouse.anxinyun.query(`
SELECT count(*) AS count FROM t_video_ipc
WHERE structure IN (${searchStrucIds.join(',')})
`).toPromise())[0].count
: 0
}
emailTitle += `异常率推送服务`
emailSubTitle += `持续产生时间超过${interval}分钟的异常设备数量${interval}个,异常率达到项目或结构物内设备总数量${parseInt(deviceCount) + parseInt(cameraCount)}个的 --%,详情如下`
}
// appAlarmWhereOption.createTime = { $lte: pointTime }
// videoAlarmWhereOption.push(`camera_status_alarm.create_time <= '${pointTime}'`)
emailTitle += `异常率推送服务`
emailSubTitle += `持续产生时间超过${interval}分钟的异常设备数量${interval}个,异常率达到项目或结构物内设备总数量${deviceCount + cameraCount}个的${interval}%,详情如下`
}
emailTitle += '——POMS飞尚运维中台'
@ -202,6 +222,7 @@ module.exports = function (app, opts) {
cameraAlarm.confirmTime AS confirmTime,
cameraAlarm.autoRestore AS autoRestore,
camera_status.describe AS statusDescribe,
camera_kind.kind AS cameraKind,
"gbCamera".online AS cameraOnline,
anxinIpc.t_video_ipc.name AS anxinIpcPosition,
anxinStation.id AS anxinStationId,
@ -213,6 +234,7 @@ module.exports = function (app, opts) {
camera.id AS cameraId,
camera.gb_id AS gbId,
camera.name AS cameraName,
camera.kind_id AS cameraKindId,
camera_status_alarm.id AS alarmId,
camera_status_alarm.create_time AS createTime,
camera_status_alarm.status_id AS statusId,
@ -240,7 +262,8 @@ module.exports = function (app, opts) {
AND cameraAlarm.statusId = camera_status.id
LEFT JOIN "gbCamera"
ON "gbCamera".id = cameraAlarm.gbId
LEFT JOIN camera_kind
ON camera_kind.id = cameraAlarm.cameraKindId
LEFT JOIN ${anxinyun}.t_video_ipc AS anxinIpc
ON toString(anxinIpc.channel_no) = cameraAlarm.cameraChannelNo
AND anxinIpc.serial_no = cameraAlarm.cameraSerialNo
@ -251,6 +274,7 @@ module.exports = function (app, opts) {
ON anxinIpcStation.ipc = anxinIpc.id
LEFT JOIN ${anxinyun}.t_sensor AS anxinStation
ON anxinStation.id = anxinIpcStation.station
ORDER BY cameraAlarm.createTime DESC
`
).toPromise() : []
@ -290,6 +314,7 @@ module.exports = function (app, opts) {
alarmId: a.alarmId,
confirmContent: a.confirmContent,
confirmTime: a.confirmTime,
cameraKind: a.cameraKind,
struc: [],
station: []
}
@ -315,10 +340,12 @@ module.exports = function (app, opts) {
}
}
let p = 1
videoAlarms = returnD
}
if (c.alarmType.includes('app_exception')) {
appAlarms = await models.AppAlarm.findAll({
where: appAlarmWhereOption,
order: [['createTime', 'DESC']],
include: [{
model: models.App,
include: [{
@ -329,7 +356,6 @@ module.exports = function (app, opts) {
}]
}]
})
let a = 2
}
if (c.alarmType.includes('device_exception')) {
dataAlarmGroupOption.push(4)
@ -343,9 +369,10 @@ module.exports = function (app, opts) {
dataAlarms = await clickHouse.dataAlarm.query(`
SELECT * FROM alarms
WHERE
State NOT IN (3, 4)
AND StructureId IN (${searchStrucIds.join(',')})
${/*`'State NOT IN (3, 4) AND '`*/''}
StructureId IN (${searchStrucIds.join(',')})
${dataAlarmOption.length ? ' AND ' + dataAlarmOption.join(' AND ') : ''}
ORDER BY StartTime DESC
`).toPromise()
console.log(dataAlarms);
}
@ -358,7 +385,7 @@ module.exports = function (app, opts) {
n: '结构物',
k: '',
f: (d) => {
return (strucListRes.find(s => s.id == d.StructureId) || {}).name
return (strucListRes.find(s => s.id == d.StructureId) || { name: '' }).name
}
}, {
n: '告警源名称',
@ -405,49 +432,258 @@ module.exports = function (app, opts) {
}
},]
let html = ''
let videoAlarmTitle = [{
n: '项目',
k: '',
v: pepProjectName
}, {
n: '结构物',
k: '',
f: (d) => {
return d.struc.map(ds => ds.name).join('、')
}
}, {
n: '告警源名称',
k: 'cameraName'
}, {
n: '告警源类型',
k: 'cameraKind'
}, {
n: '序列号',
k: 'cameraSerialNo'
}, {
n: '通道号',
k: 'cameraChannelNo'
}, {
n: '测点',
k: '',
f: (d) => {
return d.station.map(ds => ds.name).join('、')
}
}, {
n: '位置',
k: '',
f: (d) => {
return d.station.map(ds => ds.position).join('、')
}
}, {
n: '告警信息',
k: 'statusDescribe'
}, {
n: '持续时间',
k: '',
f: (d) => {
return d.createTime ?
'超过' + moment().diff(moment(d.createTime), 'minutes') + '分钟' : ''
}
},]
let appAlarmTitle = [{
n: '项目',
k: '',
v: pepProjectName
}, {
n: '应用名称',
k: '',
f: (d) => {
return d.app ? d.app.name : ''
}
}, {
n: '异常类型',
k: '',
f: (d) => {
if (d.type == 'element') {
return '元素异常'
} else if (d.type == 'apiError') {
return '接口报错'
} else {
return ''
}
}
}, {
n: '异常信息',
k: 'alarmContent'
}, {
n: 'URL地址',
k: 'cameraName',
f: (d) => {
return d.app && d.app.url ? `<a href="${d.app.url}">${d.app.url}</a>` : ''
}
}, {
n: '持续时间',
k: '',
f: (d) => {
return d.createTime ?
'超过' + moment().diff(moment(d.createTime), 'minutes') + '分钟' : ''
}
},]
let ifEmailSend = false
let tableTitlePostfix = ',详情如下:'
function packageTableTitle (tArr) {
function packageTableTitle (titleArr) {
let tableTitle = '<tr>'
for (let t of titleArr) {
tableTitle += `<th style="background-color:#8faadc; color:#fff; text-align:left">${t.n}</th>`
}
tableTitle += '</tr>'
return tableTitle
}
if (c.alarmType.includes('data_outages')) {
let tableTitlePrefix = '数据中断告警源'
function packageTableData (data, titleArr) {
let tableData = '<tr>'
for (let t of titleArr) {
if (t.v) {
tableData += `<td>${t.v}</td>`
} else if (t.f) {
tableData += `<td>${t.f(data)}</td>`
} else if (t.k) {
tableData += `<td>${data[t.k]}</td>`
} else {
tableData += `<td></td>`
}
}
tableData += '</tr>'
return tableData
}
function packageAlarmData2Table (titlePrefix, alarmData, alarmTitleArr, keyOfStartTime = 'StartTime') {
if (!alarmData.length) {
return ''
}
ifEmailSend = true
let tableTitlePrefix = titlePrefix + '告警源'
let newAddCount = 0
let alarmHtml = ''
let alarmHtml = '<table border="1" cellspacing="0" style="border-collapse:collapse;border-spacing:0;border-left:1px solid #888;border-top:1px solid #888;">'
let alarmContent = ''
let alarmHtmlTitle = packageTableTitle(alarmTitleArr)
if (c.tactics == 'immediately') {
for (let a of dataAlarms.filter(d => d.AlarmGroup == 1)) {
alarmHtml += 1
for (let a of alarmData) {
alarmContent += packageTableData(a, alarmTitleArr)
if (a[keyOfStartTime] && moment(a[keyOfStartTime]).isBetween(newAddStartTime, newAddEndTime)) {
newAddCount++
}
tableTitlePrefix += 1
} else if (c.tactics == 'continue') {
}
tableTitlePrefix +=
c.tactics == 'abnormal_rate' ?
`${alarmData.length}` :
`新增${newAddCount}个,未解决累计${alarmData.length}` + tableTitlePostfix
alarmHtml += `<tr><td colspan="${alarmTitleArr.length}" style="background-color:#ffff00">` + tableTitlePrefix + '</td></tr>'
alarmHtml += alarmHtmlTitle
alarmHtml += alarmContent
alarmHtml += '</table><br/>'
} else if (c.tactics == 'abnormal_rate') {
return alarmHtml
}
let dataAlarmG1 = [];
let dataAlarmG2 = [];
let dataAlarmG3 = [];
let dataAlarmG45 = [];
let deviceStatistic = new Set()
for (let d of dataAlarms) {
if (d.AlarmGroup == 1) {
dataAlarmG1.push(d)
} else if (d.AlarmGroup == 2) {
dataAlarmG2.push(d)
} else if (d.AlarmGroup == 3) {
dataAlarmG3.push(d)
} else if (d.AlarmGroup == 4 || d.AlarmGroup == 5) {
dataAlarmG45.push(d)
}
deviceStatistic.add(d.SourceId)
}
if (c.tactics == 'abnormal_rate') {
let a = ((deviceStatistic.size + videoAlarms.length) / (parseInt(deviceCount) + parseInt(cameraCount))).toFixed(1) + '%'
emailSubTitle = emailSubTitle.replace('--%', ((deviceStatistic.size + videoAlarms.length) / (parseInt(deviceCount) + parseInt(cameraCount))).toFixed(1) + '%')
}
let html = `
<html>
<head>
<meta charset="utf-8">
<style>
table {
border-collapse:collapse;border-spacing:0;border-left:1px solid #888;border-top:1px solid #888;
}
th,td{
border-right:1px solid #888;border-bottom:1px solid #888;padding:5px 15px;
}
th{
font-weight:bold;
}
</style>
</head>
</html>
<h5 style="margin-bottom:12px">${emailSubTitle}</h5>
`
if (c.alarmType.includes('data_outages')) {
html += packageAlarmData2Table(
'数据中断',
dataAlarmG1,
dataAlarmTitle,
)
}
if (c.alarmType.includes('data_exception')) {
html += packageAlarmData2Table(
'数据异常',
dataAlarmG2,
dataAlarmTitle,
)
}
if (c.alarmType.includes('strategy_hit')) {
html += packageAlarmData2Table(
'策略命中',
dataAlarmG3,
dataAlarmTitle,
)
}
if (c.alarmType.includes('video_exception')) {
html += packageAlarmData2Table(
'视频异常',
videoAlarms,
videoAlarmTitle,
'createTime',
)
}
if (c.alarmType.includes('app_exception')) {
html += packageAlarmData2Table(
'应用异常',
appAlarms,
appAlarmTitle,
'createTime',
)
}
if (c.alarmType.includes('device_exception')) {
html += packageAlarmData2Table(
'设备异常',
dataAlarmG45,
dataAlarmTitle,
)
}
await pushByEmail({
email: ['1650192445@qq.com'],
title: emailTitle,
text: '',
html: ''
})
if (ifEmailSend) {
// 查接收人的信息
const receiverRes =
c.receiverPepUserId.length ?
await clickHouse.pepEmis.query(`
SELECT email FROM user WHERE id IN (${c.receiverPepUserId.join(',')},-1)
`).toPromise()
: []
const emails = receiverRes.reduce((arr, r) => {
if (r.email) {
arr.push(r.email)
}
return arr
}, [])
if (emails.length || 1) {
await pushByEmail({
email: ['1650192445@qq.com', '777y'],
title: emailTitle,
text: '',
html: html
})
}
}
}
}
}

Loading…
Cancel
Save