122 lines
5.0 KiB
JSON
122 lines
5.0 KiB
JSON
{
|
||
"name": "告警去重與抑制機制",
|
||
"nodes": [
|
||
{
|
||
"parameters": {
|
||
"httpMethod": "POST",
|
||
"path": "alert-receiver",
|
||
"options": {}
|
||
},
|
||
"id": "webhook",
|
||
"name": "告警接收器",
|
||
"type": "n8n-nodes-base.webhook",
|
||
"typeVersion": 2,
|
||
"position": [240, 300]
|
||
},
|
||
{
|
||
"parameters": {
|
||
"jsCode": "const alert = $input.first().json;\nconst now = Date.now();\nconst alertKey = `${alert.environment}_${alert.alertType}_${alert.service}`;\n\n// 從 static data 讀取告警歷史\nconst alertHistory = $getWorkflowStaticData('global');\nif (!alertHistory.alerts) {\n alertHistory.alerts = {};\n}\n\nconst lastAlert = alertHistory.alerts[alertKey];\nconst cooldownMinutes = {\n 'critical': 5, // 嚴重告警:5 分鐘內不重複\n 'warning': 15, // 警告:15 分鐘內不重複\n 'info': 60 // 資訊:1 小時內不重複\n};\n\nconst cooldown = (cooldownMinutes[alert.severity] || 15) * 60 * 1000;\nconst shouldSend = !lastAlert || (now - lastAlert.timestamp > cooldown);\n\nif (shouldSend) {\n alertHistory.alerts[alertKey] = {\n timestamp: now,\n count: (lastAlert?.count || 0) + 1\n };\n}\n\n// 清理超過 24 小時的歷史\nObject.keys(alertHistory.alerts).forEach(key => {\n if (now - alertHistory.alerts[key].timestamp > 24 * 60 * 60 * 1000) {\n delete alertHistory.alerts[key];\n }\n});\n\nreturn [{\n json: {\n ...alert,\n shouldSend,\n suppressReason: shouldSend ? null : `冷卻中 (${cooldownMinutes[alert.severity]}分鐘)`,\n repeatCount: alertHistory.alerts[alertKey]?.count || 1\n }\n}];"
|
||
},
|
||
"id": "dedup",
|
||
"name": "告警去重邏輯",
|
||
"type": "n8n-nodes-base.code",
|
||
"typeVersion": 2,
|
||
"position": [460, 300]
|
||
},
|
||
{
|
||
"parameters": {
|
||
"conditions": {
|
||
"options": {
|
||
"caseSensitive": true,
|
||
"leftValue": "",
|
||
"typeValidation": "strict"
|
||
},
|
||
"conditions": [
|
||
{
|
||
"id": "should-send",
|
||
"leftValue": "={{ $json.shouldSend }}",
|
||
"rightValue": true,
|
||
"operator": {
|
||
"type": "boolean",
|
||
"operation": "equals"
|
||
}
|
||
}
|
||
],
|
||
"combinator": "and"
|
||
},
|
||
"options": {}
|
||
},
|
||
"id": "if-send",
|
||
"name": "是否發送?",
|
||
"type": "n8n-nodes-base.if",
|
||
"typeVersion": 2,
|
||
"position": [680, 300]
|
||
},
|
||
{
|
||
"parameters": {
|
||
"jsCode": "const alert = $input.first().json;\nconst now = new Date().toLocaleString('zh-TW', { timeZone: 'Asia/Taipei' });\n\nconst severityEmoji = {\n 'critical': '🔴',\n 'warning': '🟠',\n 'info': '🔵'\n};\n\nconst envEmoji = {\n 'UAT': '🟦',\n 'GCP': '🟥'\n};\n\nlet message = `${severityEmoji[alert.severity] || '⚪'} <b>${envEmoji[alert.environment] || ''} ${alert.title}</b>\\n\\n`;\nmessage += `📍 環境: ${alert.environment}\\n`;\nmessage += `🔧 服務: ${alert.service}\\n`;\nmessage += `📝 詳情: ${alert.description}\\n`;\n\nif (alert.repeatCount > 1) {\n message += `🔄 重複次數: ${alert.repeatCount}\\n`;\n}\n\nmessage += `⏰ 時間: ${now}`;\n\nreturn [{ json: { message } }];"
|
||
},
|
||
"id": "format",
|
||
"name": "格式化訊息",
|
||
"type": "n8n-nodes-base.code",
|
||
"typeVersion": 2,
|
||
"position": [900, 200]
|
||
},
|
||
{
|
||
"parameters": {
|
||
"url": "https://api.telegram.org/bot<TELEGRAM_BOT_TOKEN>/sendMessage",
|
||
"sendBody": true,
|
||
"specifyBody": "json",
|
||
"jsonBody": "={\n \"chat_id\": \"5619078117\",\n \"parse_mode\": \"HTML\",\n \"text\": \"{{ $json.message }}\"\n}",
|
||
"options": {}
|
||
},
|
||
"id": "telegram",
|
||
"name": "發送 Telegram",
|
||
"type": "n8n-nodes-base.httpRequest",
|
||
"typeVersion": 4.2,
|
||
"position": [1120, 200]
|
||
},
|
||
{
|
||
"parameters": {
|
||
"jsCode": "// 記錄被抑制的告警(供分析用)\nconst alert = $input.first().json;\nconsole.log(`告警被抑制: ${alert.alertType} - ${alert.suppressReason}`);\nreturn [{ json: { suppressed: true, reason: alert.suppressReason } }];"
|
||
},
|
||
"id": "log-suppressed",
|
||
"name": "記錄抑制",
|
||
"type": "n8n-nodes-base.code",
|
||
"typeVersion": 2,
|
||
"position": [900, 400]
|
||
}
|
||
],
|
||
"connections": {
|
||
"告警接收器": {
|
||
"main": [
|
||
[{ "node": "告警去重邏輯", "type": "main", "index": 0 }]
|
||
]
|
||
},
|
||
"告警去重邏輯": {
|
||
"main": [
|
||
[{ "node": "是否發送?", "type": "main", "index": 0 }]
|
||
]
|
||
},
|
||
"是否發送?": {
|
||
"main": [
|
||
[{ "node": "格式化訊息", "type": "main", "index": 0 }],
|
||
[{ "node": "記錄抑制", "type": "main", "index": 0 }]
|
||
]
|
||
},
|
||
"格式化訊息": {
|
||
"main": [
|
||
[{ "node": "發送 Telegram", "type": "main", "index": 0 }]
|
||
]
|
||
}
|
||
},
|
||
"settings": {
|
||
"executionOrder": "v1"
|
||
},
|
||
"staticData": null,
|
||
"tags": [],
|
||
"triggerCount": 0,
|
||
"updatedAt": "2026-02-07T17:00:00.000Z",
|
||
"versionId": "1"
|
||
}
|