实现思路:全文件扫描,匹配对应时间开始的日志,获取该匹配行之后的内容 。
# -*- coding: utf-8 -*-
import os
import re
import requests
import subprocess
from datetime import datetime
def send_zabbix_alert(zabbix_key, value, host):
"""
使用 zabbix_sender 向 Zabbix Server 发送告警信息。
参数:
- zabbix_server: Zabbix Server 的地址。
- zabbix_port: Zabbix Server 的端口号。
- zabbix_key: Zabbix 中的 Item Key。
- value: 要发送的值,通常为 1 表示告警,0 表示正常。
- host: Zabbix 中定义的主机名。
返回:
- zabbix_sender 的执行结果。
"""
# 构建 zabbix_sender 命令
# 注意:这里的 zabbix_sender 路径需要根据你的系统环境进行替换
zabbix_sender_path = '/usr/bin/zabbix_sender'
# 使用 -z 指定 Zabbix Server,-p 指定端口,-s 指定主机名,-k 指定 Item Key,-o 指定值
command = [
zabbix_sender_path,
'-z', "zabbix.com",
'-p', str(10051),
'-s', host,
'-k', zabbix_key,
'-o', str(value)
]
# 执行命令并获取输出
try:
#result = subprocess.run(command, capture_output=True, text=True, check=True)
result = subprocess.check_output(command, stderr=subprocess.STDOUT)
print("告警发送成功:", result.stdout)
return result.stdout
except subprocess.CalledProcessError as e:
print("告警发送失败:", e.stderr)
return e.stderr
def push_report(web_hook,content):
# 使用正则表达式去除所有只包含空白字符(包括换行符)的行
cleaned_content = re.sub(r'^\s*$\n?', '', content, flags=re.MULTILINE)
header = {
"Content-Type": "application/json;charset=UTF-8"
}
message_body = {
"msg_type": "text",
"content": {
"text": cleaned_content
}
}
ChatRob = requests.post(url=web_hook, json=message_body, headers=header)
opener = ChatRob.json()
if opener["StatusMessage"] == "success":
print(u"%s 通知消息发送成功!" % opener)
else:
print(u"通知消息发送失败,原因:{}".format(opener))
def load_last_scan_timestamp():
try:
with open(last_scan_timestamp_file, 'r') as f:
return datetime.strptime(f.read().strip(), '%Y-%m-%dT%H:%M:%S')
except FileNotFoundError:
return None
def save_last_scan_timestamp(timestamp):
with open(last_scan_timestamp_file, 'w') as f:
f.write(timestamp.strftime('%Y-%m-%dT%H:%M:%S'))
def read_file_line_by_line(path):
with open(path, 'r') as file:
for line in file:
yield line.strip()
def parse_slow_query_log(path, start_timestamp):
new_queries = []
current_query = []
in_query = False
for line in read_file_line_by_line(path):
# 查找时间戳行,这标志着新查询的开始
if line.startswith('# Time:'):
timestamp_str = line.split()[2].replace('T', ' ').split('.')[0]
timestamp = datetime.strptime(timestamp_str, '%Y-%m-%d %H:%M:%S')
# 如果当前不在查询中,并且时间戳大于开始时间戳,则开始新查询
# 注意:这里不再跳过当前行,而是将其添加到current_query中
if not in_query and (start_timestamp is None or timestamp > start_timestamp):
in_query = True
current_query = ["P5数据库"] # 将# Time:行作为查询的第一行
last_timestamp = timestamp # 记录时间戳
else:
# 如果已经在查询中,但遇到了新的# Time:行,可能是日志格式问题或连续查询
# 这里可以记录一个错误或警告,但在这个示例中,我们只处理第一个查询
# 你可以根据需要调整这个行为
if in_query:
# 结束前一个查询并可能开始新的(这里我们不开始新的,只是记录并继续当前查询)
full_query = '\n'.join(current_query)
new_queries.append((last_timestamp, full_query))
in_query = False # 理论上这里不应该设置为False,除非你确定要结束当前查询
# 但由于我们假设每个# Time:都对应一个新的查询,这里不执行结束逻辑
# 更新上一个时间戳(对于处理日志突然结束的情况,但在这个逻辑中可能不是必需的)
# 因为我们已经将时间戳与查询内容一起记录了
# last_timestamp = timestamp # 注释掉,因为不再需要单独记录last_timestamp
# 如果当前在处理查询,则继续收集所有行
if in_query:
current_query.append(line.strip())
# 处理最后一个查询(如果有的话)
# 由于我们不再跳过# Time:行,并且每次遇到# Time:都可能开始新查询,
# 因此最后一个查询(如果有)应该已经在上面的循环中被处理了
# 但是,为了安全起见,我们可以再次检查current_query(尽管在正常情况下它应该是空的)
if in_query and current_query:
# 这通常不应该发生,除非日志以查询开始但缺少结束的时间戳
# 我们可以选择记录一个错误,或者像之前一样使用datetime.now()作为时间戳
full_query = '\n'.join(current_query)
# 假设我们使用当前时间作为时间戳(尽管这通常不是最佳实践)
new_queries.append((datetime.now(), full_query))
# 或者,更安全的做法是抛出一个异常,指出日志格式可能有问题
# raise ValueError("Unexpected end of log file while parsing a query.")
return new_queries
# 主程序
if __name__ == '__main__':
last_scan_timestamp_file = '/hskj/script/last_scan_timestamp.txt'
slow_query_log_path = '/hadata/mysql/slow_query.log'
last_scan_timestamp = load_last_scan_timestamp()
new_queries = parse_slow_query_log(slow_query_log_path, last_scan_timestamp)
# webhook 来自于 获取机器人webhook:复制webhook 中的那个值
webhook = "https://"
if not new_queries:
print("No new slow queries detected.")
# 更新上次扫描的时间戳为最后一个查询的时间戳(或更精确的处理方式)
if new_queries:
save_last_scan_timestamp(max(timestamp for timestamp, _ in new_queries))
# 处理新查询(例如,打印)
for timestamp, query in new_queries:
#print(f"New Slow Query Detected at {timestamp}:")
push_report(webhook,query)
query = re.sub(r"^\s*$\n?","",query, flags=re.MULTILINE)
#send_zabbix_alert("slowsqlstr",query,"mjq-")
print(query)
print("="*80)
告警内容样例:
如果对你有帮助,一块也是爱