运维服务中台
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

465 lines
24 KiB

2 years ago
const moment = require('moment')
module.exports = function (app, opts) {
const alarmsPush = app.fs.scheduleInit(
{
interval: '12 */1 * * * *',
immediate: true, // dev
2 years ago
proRun: true,
2 years ago
},
async () => {
try {
const { models, ORM: sequelize } = app.fs.dc
const { clickHouse } = app.fs
2 years ago
const { database: anxinyun } = clickHouse.anxinyun.opts.config
2 years ago
const { pushBySms, pushByEmail } = app.fs.utils
const curMinOfYear = moment().diff(moment().startOf('year'), 'minutes')
const configListRes = await models.AlarmPushConfig.findAll({
where: {
del: false
},
include: [{
model: models.ProjectCorrelation,
where: {
del: false
},
required: true
}]
})
let pepProjectIds = new Set()
for (let { dataValues: c } of configListRes) {
if (c.projectCorrelation.pepProjectId) {
pepProjectIds.add(c.projectCorrelation.pepProjectId)
}
}
const pepProjectRes = pepProjectIds.size ?
await clickHouse.projectManage.query(
`
SELECT
t_pim_project.id AS id,
t_pim_project.project_name AS project_name,
t_pim_project.isdelete AS isdelete,
t_pim_project_construction.construction_status_id AS construction_status_id,
t_pim_project_state.construction_status AS construction_status
FROM t_pim_project
LEFT JOIN t_pim_project_construction
ON t_pim_project.id = t_pim_project_construction.project_id
LEFT JOIN t_pim_project_state
ON t_pim_project_construction.construction_status_id = t_pim_project_state.id
WHERE id IN (${[...pepProjectIds].join(',')})
`
).toPromise() :
[]
for (let { dataValues: c } of configListRes) {
if (c.tacticsParams && c.tactics) {
const { projectCorrelation, strucId, pomsProjectId, } = c
2 years ago
const { interval, deviceProportion } = c.tacticsParams
if (
curMinOfYear % parseInt(interval) == 0
2 years ago
) {
const corPepProject = projectCorrelation.pepProjectId ?
pepProjectRes.find(p => p.id == projectCorrelation.pepProjectId)
: null
if (
!projectCorrelation.pepProjectId
|| (
corPepProject
&& c.timeType.some(ct => ct == corPepProject.construction_status_id)
)
) {
const { anxinProjectId, pepProjectId } = projectCorrelation
// 查当前 poms 下的结构物 并把不包含的去掉
// 可能有结构物已解绑
const strucListRes = strucId.length && anxinProjectId.length ?
await clickHouse.anxinyun.query(
`
SELECT
DISTINCT id,
t_structure.id AS id,
t_structure.name AS name,
t_structure.iota_thing_id AS iotaThingId
FROM
t_project
LEFT JOIN
t_project_structure
ON t_project_structure.project = t_project.id
LEFT JOIN
t_project_structuregroup
ON t_project_structuregroup.project = t_project.id
LEFT JOIN
t_structuregroup_structure
ON t_structuregroup_structure.structuregroup = t_project_structuregroup.structuregroup
LEFT JOIN
t_project_construction
ON t_project_construction.project = t_project.id
LEFT JOIN
t_structure_site
ON t_structure_site.siteid = t_project_construction.construction
RIGHT JOIN
t_structure
ON t_structure.id = t_project_structure.structure
OR t_structure.id = t_structuregroup_structure.structure
OR t_structure.id = t_structure_site.structid
WHERE
project_state != -1
AND t_project.id IN (${anxinProjectId.join(',')})
AND t_structure.id IN (${strucId.join(',')})
`
).toPromise() :
[]
let searchStrucIds = strucListRes.map(s => s.id)
if (searchStrucIds.length) {
searchStrucIds.unshift(-1)
}
let pepProjectName = pepProjectId ?
pepProjectRes.find(p => p.id == pepProjectId).project_name
: projectCorrelation.name
let emailTitle = `${pepProjectName}-${c.name}-`
let emailSubTitle = ''
2 years ago
2 years ago
let dataAlarmOption = []
let dataAlarmGroupOption = []
let dataAlarms = []
let videoAlarmWhereOption = []
2 years ago
let videoAlarms = []
let appAlarmWhereOption = {
confirmTime: null,
}
let appAlarms = []
2 years ago
let deviceCount = 0
let alarmDeviceCount = 0
2 years ago
let cameraCount = 0
let alarmCameraCount = 0
2 years ago
// 判断推送策略
let nowTime = moment().startOf('minute')
let pointTime = moment().subtract(parseInt(interval), 'minute').startOf('minute').format('YYYY-MM-DD HH:mm:ss')
2 years ago
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分')}`
2 years ago
} else if (c.tactics == 'continue') {
// dataAlarmOption.push(`StartTime <= '${pointTime}'`);
// appAlarmWhereOption.createTime = { $lte: pointTime }
// videoAlarmWhereOption.push(`camera_status_alarm.create_time <= '${pointTime}'`)
emailTitle += `持续时长推送服务`
emailSubTitle += `告警持续时长超${interval}分钟的告警源,详情如下:`
2 years ago
} else if (c.tactics == 'abnormal_rate') {
// dataAlarmOption.push(`StartTime <= '${pointTime}'`);
2 years ago
if (c.alarmType.includes('data_outages') || c.alarmType.includes('data_exception')) {
// 查了设备异常率 去安心云查当前项目下的设备数量
2 years ago
// TODO 等同步以太数据再查
deviceCount = 9999
2 years ago
// await clickHouse.anxinyun.query(`
// SELECT count(*) FROM
// `).toPromise()
}
if (c.alarmType.includes('video_exception')) {
// 查了视频异常 去安心云查 接入的 萤石 设备数量
cameraCount = searchStrucIds.length ?
2 years ago
(await clickHouse.anxinyun.query(`
SELECT count(*) AS count FROM t_video_ipc
WHERE structure IN (${searchStrucIds.join(',')})
2 years ago
`).toPromise())[0].count
: 0
2 years ago
}
// appAlarmWhereOption.createTime = { $lte: pointTime }
// videoAlarmWhereOption.push(`camera_status_alarm.create_time <= '${pointTime}'`)
emailTitle += `异常率推送服务`
emailSubTitle += `持续产生时间超过${interval}分钟的异常设备数量${interval}个,异常率达到项目或结构物内设备总数量${deviceCount + cameraCount}个的${interval}%,详情如下`
2 years ago
}
emailTitle += '——POMS飞尚运维中台'
2 years ago
// 判断告警数据范围
if (c.alarmType.includes('data_outages')) {
dataAlarmGroupOption.push(1)
}
if (c.alarmType.includes('data_exception')) {
dataAlarmGroupOption.push(2)
}
if (c.alarmType.includes('strategy_hit')) {
dataAlarmGroupOption.push(3)
}
if (c.alarmType.includes('video_exception')) {
videoAlarms = searchStrucIds.length ? await clickHouse.vcmp.query(
2 years ago
`
SELECT
cameraAlarm.cameraId AS cameraId,
cameraAlarm.cameraName AS cameraName,
cameraAlarm.cameraSerialNo AS cameraSerialNo,
cameraAlarm.cameraChannelNo AS cameraChannelNo,
cameraAlarm.alarmId AS alarmId,
cameraAlarm.createTime AS createTime,
cameraAlarm.confirmContent AS confirmContent,
cameraAlarm.confirmTime AS confirmTime,
cameraAlarm.autoRestore AS autoRestore,
camera_status.describe AS statusDescribe,
"gbCamera".online AS cameraOnline,
anxinIpc.t_video_ipc.name AS anxinIpcPosition,
anxinStation.id AS anxinStationId,
anxinStation.name AS anxinStationName,
anxinStruc.name AS strucName,
anxinStruc.id AS strucId
FROM (
SELECT
camera.id AS cameraId,
camera.gb_id AS gbId,
camera.name AS cameraName,
camera_status_alarm.id AS alarmId,
camera_status_alarm.create_time AS createTime,
camera_status_alarm.status_id AS statusId,
camera_status_alarm.serial_no AS cameraSerialNo,
camera_status_alarm.channel_no AS cameraChannelNo,
camera_status_alarm.confirm AS confirmContent,
camera_status_alarm.auto_restore AS autoRestore,
2 years ago
camera_status_alarm.confirm_time AS confirmTime
FROM camera_status_alarm
INNER JOIN ${anxinyun}.t_video_ipc
ON toString(${anxinyun}.t_video_ipc.channel_no) = camera_status_alarm.channel_no
AND ${anxinyun}.t_video_ipc.serial_no = camera_status_alarm.serial_no
AND ${anxinyun}.t_video_ipc.structure IN (${searchStrucIds.join(',')})
2 years ago
INNER JOIN camera
ON camera.serial_no = camera_status_alarm.serial_no
AND camera.channel_no = camera_status_alarm.channel_no
AND camera.delete = false
2 years ago
AND camera.recycle_time is null
WHERE
camera_status_alarm.confirm_time IS null
${videoAlarmWhereOption.length ? ` AND ${videoAlarmWhereOption.join(' AND ')}` : ''}
2 years ago
) AS cameraAlarm
LEFT JOIN camera_status
ON cameraAlarm.platform = camera_status.platform
AND cameraAlarm.statusId = camera_status.id
LEFT JOIN "gbCamera"
ON "gbCamera".id = cameraAlarm.gbId
LEFT JOIN ${anxinyun}.t_video_ipc AS anxinIpc
ON toString(anxinIpc.channel_no) = cameraAlarm.cameraChannelNo
AND anxinIpc.serial_no = cameraAlarm.cameraSerialNo
LEFT JOIN ${anxinyun}.t_structure AS anxinStruc
ON anxinStruc.id = anxinIpc.structure
AND anxinStruc.id IN (${searchStrucIds.join(',')})
2 years ago
LEFT JOIN ${anxinyun}.t_video_ipc_station AS anxinIpcStation
ON anxinIpcStation.ipc = anxinIpc.id
LEFT JOIN ${anxinyun}.t_sensor AS anxinStation
ON anxinStation.id = anxinIpcStation.station
`
).toPromise() : []
let returnD = []
let positionD = {}
// 每个设备一个告警
for (let a of videoAlarms) {
if (positionD[a.cameraId]) {
let curD = returnD[positionD[a.cameraId].positionReturnD]
2 years ago
if (a.strucId && !curD.struc.some(s => s.id == a.strucId)) {
curD.struc.push({
id: a.strucId,
projectId: a.projectId,
name: a.strucName
})
}
if (a.anxinStationId && !curD.station.some(s => s.id == a.anxinStationId)) {
curD.station.push({
id: a.anxinStationId,
name: a.anxinStationName,
position: a.anxinIpcPosition
})
}
} else {
let d = {
cameraId: a.cameraId,
cameraName: a.cameraName,
camerOnline: a.cameraOnline,
cameraSerialNo: a.cameraSerialNo,
cameraChannelNo: a.cameraChannelNo,
autoRestore: a.autoRestore,
createTime: a.createTime,
updateTime: a.updateTime,
platform: a.platform,
statusDescribe: a.statusDescribe,
alarmId: a.alarmId,
confirmContent: a.confirmContent,
confirmTime: a.confirmTime,
struc: [],
station: []
}
2 years ago
2 years ago
if (a.strucId) {
d.struc.push({
id: a.strucId,
projectId: a.projectId,
name: a.strucName
})
}
if (a.anxinStationId) {
d.station.push({
id: a.anxinStationId,
name: a.anxinStationName,
position: a.anxinIpcPosition
})
}
returnD.push(d)
positionD[a.cameraId] = {
positionReturnD: returnD.length - 1
}
}
}
let p = 1
2 years ago
}
if (c.alarmType.includes('app_exception')) {
appAlarms = await models.AppAlarm.findAll({
where: appAlarmWhereOption,
include: [{
model: models.App,
include: [{
model: models.ProjectApp,
where: {
projectId: pomsProjectId
},
}]
}]
})
let a = 2
2 years ago
}
if (c.alarmType.includes('device_exception')) {
dataAlarmGroupOption.push(4)
dataAlarmGroupOption.push(5)
}
// 查数据告警 三警合一
if (dataAlarmGroupOption.length && searchStrucIds.length) {
2 years ago
dataAlarmGroupOption.push(-1)
dataAlarmOption.push(`AlarmGroup IN (${dataAlarmGroupOption.join(',')})`)
dataAlarms = await clickHouse.dataAlarm.query(`
SELECT * FROM alarms
2 years ago
WHERE
State NOT IN (3, 4)
AND StructureId IN (${searchStrucIds.join(',')})
2 years ago
${dataAlarmOption.length ? ' AND ' + dataAlarmOption.join(' AND ') : ''}
`).toPromise()
console.log(dataAlarms);
}
let dataAlarmTitle = [{
n: '项目',
k: '',
v: pepProjectName
}, {
n: '结构物',
k: '',
f: (d) => {
return (strucListRes.find(s => s.id == d.StructureId) || {}).name
}
}, {
n: '告警源名称',
k: 'SourceName'
}, {
n: '告警源类型',
k: '',
f: (d) => {
switch (d.SourceTypeId) {
case 0:
return 'DTU'
case 1:
return '传感器'
case 2:
return '测点'
default:
return ''
}
}
}, {
n: '告警信息',
k: 'AlarmContent'
}, {
n: '告警等级(当前)',
k: '',
f: (d) => {
switch (d.CurrentLevel) {
case 1:
return '一级'
case 2:
return '二级'
case 3:
return '三级'
default:
return ''
}
}
}, {
n: '持续时间',
k: '',
f: (d) => {
return d.StartTime ?
'超过' + moment().diff(moment(d.StartTime), 'minutes') + '分钟' : ''
}
},]
let html = ''
let tableTitlePostfix = ',详情如下:'
function packageTableTitle (tArr) {
}
if (c.alarmType.includes('data_outages')) {
let tableTitlePrefix = '数据中断告警源'
let newAddCount = 0
let alarmHtml = ''
if (c.tactics == 'immediately') {
for (let a of dataAlarms.filter(d => d.AlarmGroup == 1)) {
alarmHtml += 1
}
tableTitlePrefix += 1
} else if (c.tactics == 'continue') {
} else if (c.tactics == 'abnormal_rate') {
}
}
if (c.alarmType.includes('data_exception')) {
}
if (c.alarmType.includes('strategy_hit')) {
}
if (c.alarmType.includes('video_exception')) {
}
if (c.alarmType.includes('app_exception')) {
}
if (c.alarmType.includes('device_exception')) {
}
2 years ago
await pushByEmail({
email: ['1650192445@qq.com'],
title: emailTitle,
text: '',
html: ''
})
2 years ago
}
}
}
}
} catch (error) {
console.error(error);
}
}
)
return {
alarmsPush,
}
}