Commit 58fb01b0 by trace

[feature] 邮件通知外部人员下线情况, 贷超只有在下线才通知贷超组

parent eae22bf9
let version = '1.0'
let version = '1.1'
let release = `<div><br/>
<br/>1. <br/>
加入对贷超 MGT 的支持. 支持点击"<贷超名MGT>"打开贷超对应管理系统, 点击包名 ID 打开 GooglePlay<br/>
加入邮件通知外部人员功能<br/>
配置文件添加新字段, 用于指名哪个客户, 以及其通知邮件(多个)<br/>
"outsideNotifier" {<br/>
"2060": { "emails": ["developer@xxxxx.com", "xxxxxx"] },<br/>
"2001": { "emails": ["developer@xxxxx.com", "xxxxx"] },<br/>
}<br/>
具体格式可以查看 config 文件中 "outsideNotifier" 字段.<br/>
添加新监控 APP 时只要像原来一样保持 "客户ID空格XXXXX" 的格式即可, 如: "2060 XXXXXX"<br/>
<br/>2. <br/>
在线列表上下线颜色区分. 上线: 绿色, 下线: 红色.<br/>
<br/>other:<br/>
当监控中有上下线变化才会发送邮件, 并且会带上当前在线下线列表<br/>
上下线通知邮件中第一行, "《》" 中的是 VTPM 本次监控情况涉及 APP 数量, "【】" 中是本次监控通知中贷超 APP 涉及数量<br/>
贷超通知更改, 贷超有产品下架才通知贷超人员
添加单独贷超 email 变量: "daichaoNotifyEmail": []
<div/>
<br/>
<br/>
......@@ -17,6 +23,9 @@ let release = `<div><br/>
var gplay = require('google-play-scraper')
var nodemailer = require('nodemailer')
let developer = ['yingchen.nong@starwin.com']
let notifyEmail = developer
// 工具
var fs = require('fs')
var username = require('os').userInfo().username
......@@ -52,6 +61,10 @@ let aliveInterval = isTest() && 0.1 || 3 // 发送邮件间隔时间
let start = true // 是否开始爬取监控
let dailyOnlineStartHours = 7
let dailyOnlineEndHours = 9
let daichaoNotifyEmail = []
// 外部通知客户
let outsideNotifier = {}
let crabName = `东南亚现金贷App监控${isTest() && '(Test)' || ''}`
let monitorRegion = { 'vn': '越南', 'ph': '菲律宾', 'id': '印尼' }
......@@ -60,8 +73,6 @@ let statusFile = `${process.cwd()}/status.json`
let monitorApps = `${process.cwd()}/google-play-monitor-apps.json`
let base_gp_url = 'https://play.google.com/store/apps/details?id='
let developer = ['yingchen.nong@starwin.com']
let notifyEmail = developer
let daichaoApps = []
let daichaoAppInfoes = {}
......@@ -164,6 +175,7 @@ if (isTest()) {
sendEmail(`开始监控-----------------------`)
// mark - 监控主流程
async function startMonitor() {
log('开始监控')
while (start) {
......@@ -171,7 +183,7 @@ async function startMonitor() {
await getConfig()
.then(() => { // 部署通知, 更新说明
if (newDeploy) {
sendEmail(`<div>爬虫部署版本: ${version}</div>更新说明: ${release}`)
sendEmail(`<div>爬虫部署版本: ${version}</div>更新说明: ${release}`, [...notifyEmail, ...daichaoNotifyEmail])
newDeploy = false
}
})
......@@ -186,6 +198,7 @@ async function startMonitor() {
.then(allN => monitorIfOnline(allN))
.then(genMail)
.then(sendEmail)
.then(notifyOutside)
.then(() => {
// 每日在线列表报告
if (!isInTimeInRangeToday(dailyOnlineStartHours, dailyOnlineEndHours)) {
......@@ -197,6 +210,10 @@ async function startMonitor() {
sendEmail(content)
})
.then(() => {
status['lastLoopDate'] = Date()
})
.then(clearLocalVariable)
.then(() => {
log('成功')
// 将status 写入到文件
fs.writeFileSync(statusFile, JSON.stringify(status))
......@@ -215,14 +232,7 @@ async function startMonitor() {
}
// 出错了需要重新抓, 需要清空之前缓存的状态
newOffline = []
newOnline = []
permissionChange = {}
failedApps = []
errorLog = []
newTopMonitorNames = {}
hitDaichao = 0
hitOurs = 0
clearLocalVariable()
})
await sleepForInterVal(lastIntervalTime)
......@@ -246,8 +256,6 @@ function generateDailyOnlineReport() {
async function getDaichao() {
let allRegionDaichaoApps = []
for (region in daichaoRegion) {
// for (index in Object.keys(daichaoRegion)) {
// let region = daichaoRegion[index]
daichaoApiUrl = region + daichao
log(` 贷超 url: ${daichaoApiUrl}`)
await getPromiss(daichaoApiUrl)
......@@ -289,42 +297,6 @@ async function getDaichao() {
log(`目前总共贷超数据: ${daichaoApps.length}`)
}
// async function getDaichao(url) {
// await getPromiss(url)
// .then(val => {
// if (isTest()) {
// daichaoApps = []
// return
// }
// try {
// daichaoData = JSON.parse(val && val.body && val.body || "{}").data
// } catch (err) {
// errMsg = `贷超数据解析出错: ${err}`
// errorLog.push(errMsg)
// return
// }
// daichaoApps = daichaoData && daichaoData.map(app => app.packageName) || []
// daichaoAppInfoes = daichaoData && daichaoData.map(app => {
// let dcApp = {}
// dcApp[app.packageName] = {
// name: app.name,
// appId: app.id
// }
// return dcApp
// })
// log(`代超数据: ${daichaoApps.length} 个`)
// monitorNames["daichao"] = daichaoApps
// if (daichaoApps.length == 0) {
// log('代超数据为空')
// }
// })
// .catch(err => {
// errorLog.push(`贷超获取失败:${err.toString()}`)
// return
// })
// }
async function getConfig() {
await getPromiss(subApi).then(val => {
log('------------ get congfig from gitlab -----------')
......@@ -338,9 +310,11 @@ async function getConfig() {
}
ourApps = dataes.ourApps || {}
ourApps = { ...ourApps, "com.globe.gcash.androida": "2060 测试我的", "com.globe.gcash.androids": "2060 测试我的2" }
ourAppIds = Object.keys(ourApps).slice(0, 1)
ourAppIds = [...ourAppIds, "com.globe.gcash.androida", "com.globe.gcash.androids"]
if (ourAppIds.length == 0) {
ourApps = { "com.globe.gcash.android": "测试我的" }
ourApps = { "com.globe.gcash.androida": "2060 测试我的", "com.globe.gcash.androids": "2060 测试我的2" }
ourAppIds = ["com.globe.gcash.android"]
}
monitorNames["ourApps"] = ourAppIds
......@@ -362,6 +336,7 @@ async function getConfig() {
}
let config = dataes.config
let subscriber = dataes.subscriber
daichaoNotifyEmail = dataes.daichaoNotifyEmail || daichaoNotifyEmail
ourApps = dataes.ourApps || {}
ourAppIds = Object.keys(ourApps)
monitorNames["ourApps"] = ourAppIds
......@@ -398,6 +373,7 @@ async function getConfig() {
start = config.start || start
dailyOnlineStartHours = config.dailyOnlineStartHours || dailyOnlineStartHours
dailyOnlineEndHours = config.dailyOnlineEndHours || dailyOnlineEndHours
outsideNotifier = config.outsideNotifier || outsideNotifier
log(JSON.stringify(config))
log(JSON.stringify(notifyEmail))
}
......@@ -559,7 +535,7 @@ function genMail() {
let lastLoopDate = status['lastLoopDate'] && new Date(status['lastLoopDate']) || new Date()
let loopInterval = (new Date()).getHours() - lastLoopDate.getHours()
let lastGenerate = `<br/><br/><br/>上次循环时间${lastLoopDate.toLocaleString()}, 间隔: ${loopInterval} 小时`
status['lastLoopDate'] = Date()
// status['lastLoopDate'] = Date()
if (!isFirstRun
&& !needSendList
&& newOffline.length == 0
......@@ -698,13 +674,6 @@ function genMail() {
emailContent += nowGenerate
emailContent += lastGenerate
log(`生成邮件内容: \n${emailContent}`)
// 清空临时栈
newOffline = []
newOnline = []
permissionChange = {}
failedApps = []
errorLog = []
newTopMonitorNames = {}
return `<div>${firstLine}</div><br/>${emailContent}<br/>version: ${version}`
}
......@@ -749,6 +718,71 @@ function aliveContent(date, lastSend) {
return emailContent
}
function clearLocalVariable() {
// 清除临时变量
newOffline = []
newOnline = []
permissionChange = {}
failedApps = []
errorLog = []
newTopMonitorNames = {}
hitDaichao = 0
hitOurs = 0
}
function outLink(name) {
return `<a href="${base_gp_url}${name}">
${getRegion(name)} - ${name}<br/>
名字: ${(status[name] && (status[name].appName || `(noName:这次更新数据里没有进前${requestTopAppNum})`))}
</a>`
}
function notifyOutside() {
// 通知外部人员
// 拿到有变动的 ourappids 列表, 拿到对应名字, 截取客户 ID,
// 判断是需要通知的客户, 就生成对应内容
// 根据这个, 遍历发送邮件
if (Object.keys(outsideNotifier).length == 0) return;
// 预先构建结构
let outsideNotifyDict = {}
for (var key in outsideNotifier) {
outsideNotifyDict[key] = {
mailTo: outsideNotifier[key].emails,
appIds: [],
content: ""
}
}
let ourDown = ourAppIds.filter(val => newOffline.includes(val)) // 拿到自己登记的下线的产品
ourDown.forEach(val => { // 组合数据结构: {customerID: { mailTo: [], appIds: []}
// 拿到客户 ID
let name = ourApps[val] || "None ID"
let customerID = name.split(' ')[0]
// 是否要通知
if (customerID in outsideNotifier) {
outsideNotifyDict[customerID].appIds = [...outsideNotifyDict[customerID].appIds, val]
}
})
let nowGenerate = `<br/><br/>邮件生成时间: <br/>${new Date().toLocaleString()}`
let lastLoopDate = status['lastLoopDate'] && new Date(status['lastLoopDate']) || new Date()
let loopInterval = (new Date()).getHours() - lastLoopDate.getHours()
let lastGenerate = `<br/><br/><br/>上次循环时间${lastLoopDate.toLocaleString()}, 间隔: ${loopInterval} 小时`
for (let key in outsideNotifyDict) {
if (outsideNotifyDict[key].appIds.length == 0) continue;
let emailContent = wrapSummary("观察到下线", outsideNotifyDict[key].appIds.map(val => outLink(val)), "red", true)
emailContent += nowGenerate
emailContent += lastGenerate
outsideNotifyDict[key].content = `<div>下线通知</div><br/>${emailContent}<br/>version: ${version}`
sendEmail(emailContent, outsideNotifyDict[key].mailTo)
}
}
function sendEmail(content, to = notifyEmail) {
if (content == null || content == undefined || content == '') {
log('没有生成内容, 检查心跳', true)
......@@ -776,13 +810,13 @@ function sendEmail(content, to = notifyEmail) {
return
}
log(`发送email: ${content.length}`, true)
// if (content.indexOf('Error') != -1) {
// to = developer
// } else {
// // to = [...to, 添加只对自己app监控的人]
// }
let myEmail = 'yingchen.nong@starwin.com'
// 有贷超下线才发送
let daichaoDown = daichaoApps.filter(val => newOffline.includes(val))
if (daichaoDown && daichaoDown.length > 0) {
to = [...to, ...daichaoNotifyEmail]
}
let emailTo = to.join(', ')
let trans = nodemailer.createTransport({
host: 'smtp.exmail.qq.com',
......@@ -813,11 +847,8 @@ function sendEmail(content, to = notifyEmail) {
})
dingDing(content, notifyDingding)
// 清空计数
hitDaichao = 0
hitOurs = 0
}
function dingDing(content, toDing = debugDingding) {
log(`发送钉钉~`)
content = `${crabName}\n` + content
......@@ -888,9 +919,9 @@ function judgePermissionChanged(name, newPermission) {
}
}
function wrapSummary(title, list, color = 'black') {
function wrapSummary(title, list, color = 'black', open = false) {
let emailContent = ''
emailContent += `<details style="color:${color}">`
emailContent += `<details style="color:${color}" ${open ? 'open' : ''}>`
emailContent += `<summary>${title}: </summary>`
emailContent += `<dl>`
list.forEach(l => {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment