原创作者:运维工程师 谢晋
钉钉告警推送@多人脚本
-
钉钉脚本编写
vi /usr/lib/zabbix/alertscripts/dingding.py
#!/usr/bin/python3
-- coding: utf-8 --
import requests
import json
import sys
import time
import hmac
import hashlib
import base64
import urllib.parse
import logging
import os
from datetime import datetime配置日志系统
def setup_logging():
log_file = '/var/log/zabbix/dingding.log'# 创建日志目录(如果不存在) log_dir = os.path.dirname(log_file) if not os.path.exists(log_dir): try: os.makedirs(log_dir, mode=0o755, exist_ok=True) logging.info(f"创建日志目录: {log_dir}") except Exception as e: print(f"无法创建日志目录 {log_dir}: {e}") sys.exit(1) # 配置日志格式和级别 logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler(log_file), logging.StreamHandler(sys.stdout) # 同时输出到控制台 ] ) # 设置日志文件权限(如果文件已存在) try: if os.path.exists(log_file): os.chmod(log_file, 0o644) except Exception as e: print(f"无法设置日志文件权限: {e}")def msg(content, at_mobiles=None, is_at_all=False):
# 记录发送的消息
logging.info(f"准备发送消息: {content}")
logging.info(f"@人员: {at_mobiles}, @所有人: {is_at_all}")# 钉钉机器人地址 dingding_url = "https://oapi.dingtalk.com/robot/send?access_token=9c1cbf04a1f37bd44ce736664b6f2f5f2a488fff3c8fbb65538278987aaad8c2" # 钉钉的加签 secret = 'SECf654831ae1d4d4ab32cbd93e7d11e491113c96c986f2110beb29e2e32dacd324' try: # 加签算法 timestamp = str(round(time.time() * 1000)) secret_enc = secret.encode('utf-8') string_to_sign = '{}\n{}'.format(timestamp, secret) string_to_sign_enc = string_to_sign.encode('utf-8') hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest() sign = urllib.parse.quote_plus(base64.b64encode(hmac_code)) headers = {'Content-Type': 'application/json;charset=utf-8'} api_url = dingding_url + "×tamp={}&sign={}".format(timestamp, sign) # 构建@人信息 at_info = {} if at_mobiles: at_info["atMobiles"] = at_mobiles if is_at_all: at_info["isAtAll"] = True # 在消息内容中添加@信息 formatted_content = content if at_mobiles: for mobile in at_mobiles: # 在消息内容中添加 @手机号 formatted_content += f" @{mobile}" json_text = { "msgtype": "markdown", "markdown": { "title": "zabbix告警", "text": formatted_content # 使用包含@信息的格式化内容 }, "at": at_info } # 记录请求详情(隐藏敏感信息) logging.info(f"请求URL: {dingding_url.split('?')[0]}...") logging.info(f"请求数据: {json.dumps(json_text, ensure_ascii=False)}") # 发送请求 start_time = time.time() response = requests.post(api_url, json.dumps(json_text), headers=headers, timeout=30) response_time = round((time.time() - start_time) * 1000, 2) # 记录响应 logging.info(f"响应状态码: {response.status_code}") logging.info(f"响应时间: {response_time}ms") logging.info(f"响应内容: {response.text}") # 检查响应 if response.status_code == 200: result = response.json() if result.get('errcode') == 0: logging.info("消息发送成功") return True else: error_msg = result.get('errmsg', '未知错误') logging.error(f"消息发送失败: {error_msg}") return False else: logging.error(f"HTTP请求失败: {response.status_code}") return False except requests.exceptions.Timeout: logging.error("请求超时:30秒内未收到响应") return False except requests.exceptions.ConnectionError: logging.error("网络连接错误:无法连接到钉钉服务器") return False except requests.exceptions.RequestException as e: logging.error(f"网络请求异常: {str(e)}") return False except Exception as e: logging.error(f"发送消息时发生未知异常: {str(e)}") return Falsedef main():
# 设置日志
setup_logging()# 记录脚本启动 logging.info("=" * 60) logging.info("钉钉通知脚本启动") logging.info(f"执行时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") logging.info(f"命令行参数数量: {len(sys.argv)}") # 解析参数 at_mobiles = None is_at_all = False message_content = "" # 解析参数 i = 1 while i < len(sys.argv): if sys.argv[i] == "--at" and i + 1 < len(sys.argv): at_mobiles = sys.argv[i + 1].split(',') i += 2 elif sys.argv[i] == "--at-all": is_at_all = True i += 1 else: # 处理带空格的消息内容 if message_content: message_content += " " + sys.argv[i] else: message_content = sys.argv[i] i += 1 # 默认@多个人(这里设置多个手机号) if at_mobiles is None: at_mobiles = ["13800138000", "13900139000", "15000150000", "15100151000"] # 替换为实际的多个手机号 logging.info(f"使用默认@多人: {at_mobiles}") try: if not message_content.strip(): logging.error("错误: 消息内容为空") print("错误: 消息内容为空") sys.exit(1) # 发送消息 success = msg(message_content, at_mobiles, is_at_all) if success: logging.info("钉钉通知脚本执行成功") print("消息发送成功") sys.exit(0) else: logging.error("钉钉通知脚本执行失败") print("消息发送失败") sys.exit(1) except KeyboardInterrupt: logging.warning("脚本被用户中断") print("\n操作已取消") sys.exit(1) except Exception as e: logging.exception("脚本执行过程中发生未预期的异常") print(f"错误: {str(e)}") sys.exit(1)if name == 'main':
main()