通过邮件发送统计TiDB慢SQL的Python脚本

CREATE USER `export-slowsql-user`@`192.168.1.%` IDENTIFIED BY '****';
GRANT PROCESS ON INFORMATION_SCHEMA.* TO 'export-slowsql-user'@'192.168.1.%'
#!/usr/bin/python3
# -*- coding: UTF-8 -*-
import datetime
import smtplib
import os
from email import encoders
from email.header import Header
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import mysql.connector
import xlwt

# 获取大约多少秒的慢SQL
slowtime = 2
# 获取最近多少天之前到现在的慢SQL
slow_from_day = 7
# TiDB数据库地址
DB_HOST=""
# TiDB数据库端口
DB_PORT=""
# 用于查询慢SQL的用户
DB_USER=""
DB_PASSWORD=""
# 记录慢SQL变所在的Database
DB_DATABASE="INFORMATION_SCHEMA"
# SMTP服务器的地址
SMTP_HOST=""
# SMTP用于发信的用户名
SMTP_USER=""
# SMTP用于发信的密码
SMTP_USER_PASSWORD=""
# 用于记录慢SQL的EXCEL文件名
RECORDS_EXCEL_FILENAME="tidb-slowlogs.xls"
nt = datetime.datetime.now()
lastsomeday = (nt - datetime.timedelta(days=slow_from_day)).date()


def sendEmail(attachfilename):
    sender = SMTP_USER
    # 接收者邮件地址
    receivers = ['要邮件通知的邮箱地址', '要邮件通知的邮箱地址']

    message = MIMEMultipart()
    message['From'] = Header(SMTP_USER, 'utf-8')  # 发送者
    message['To'] = Header('; '.join(str(e) for e in receivers) + '; ', 'utf-8')
    # 邮件主题内容
    message['Subject'] = Header(nt.strftime('%Y%m%d') + "TiDB最近" +
                                str(slow_from_day) + "天(" +
                                lastsomeday.strftime('%Y%m%d') + "~" + nt.strftime('%Y%m%d') +
                                ")的慢SQL", 'utf-8')
    # 邮件正文内容
    message.attach(MIMEText("TiDB最近" + str(slow_from_day) + "天("
                            + lastsomeday.strftime('%Y%m%d') + "~" +
                            nt.strftime('%Y%m%d') +
                            "),查询时间超过" + str(slowtime) +
                            "秒的慢SQL。详情见附件Excel文件(排除了部分用户和主机客户端相关的SQL)", 'plain', 'utf-8'))
    # 附件内容
    attachment = MIMEBase('application', "octet-stream")
    attachment.set_payload(open(attachfilename, "rb").read())
    encoders.encode_base64(attachment)
    attachment.add_header('Content-Disposition',
                          'attachment; filename="' + lastsomeday.strftime('%Y%m%d') + "-" + nt.strftime(
                              '%m%d') + '-'+RECORDS_EXCEL_FILENAME+'"')
    message.attach(attachment)

    try:
        smtpObj = smtplib.SMTP(SMTP_HOST)
        smtpObj.login(SMTP_USER, SMTP_USER_PASSWORD)
        smtpObj.sendmail(sender, receivers, message.as_string())
        print("邮件发送成功")
    except smtplib.SMTPException:
        print("Error: 无法发送邮件")


def dbConnet(host, port, user, passwd, db):
    db = mysql.connector.connect(
        host=host,
        port=port,
        user=user,
        password=passwd,
        database=db
    )
    cursor = db.cursor(buffered=True, dictionary=True)
    return cursor, db


def createExcel(data, filename):
    # 创建excel工作表
    workbook = xlwt.Workbook(encoding='utf-8')
    worksheet = workbook.add_sheet('sheet1')
    # 设置表头
    worksheet.write(0, 0, label='UID')
    worksheet.write(0, 1, label='Count')
    worksheet.write(0, 2, label='数据库')
    worksheet.write(0, 3, label='执行耗时')
    worksheet.write(0, 4, label='扫描总Key个数')
    worksheet.write(0, 5, label='执行时间')
    worksheet.write(0, 6, label='执行用户')
    worksheet.write(0, 7, label='主机')
    worksheet.write(0, 8, label='返回结果行数')
    worksheet.write(0, 9, label='内存')
    worksheet.write(0, 10, label='Cop_time')
    worksheet.write(0, 11, label='Write_sql_response_total')
    worksheet.write(0, 12, label='Total_keys')
    worksheet.write(0, 13, label='Process_keys')
    worksheet.write(0, 14, label='SQL语句')
    ordered_list = ["UID",
                    "Count",
                    "数据库",
                    "执行耗时",
                    "扫描总Key个数",
                    "执行时间",
                    "执行用户",
                    "主机",
                    "返回结果行数",
                    "内存",
                    "Cop_time",
                    "Write_sql_response_total",
                    "Total_keys",
                    "Process_keys",
                    "SQL语句",
                    ]
    row = 1
    for player in data:
        for _key, _value in player.items():
            col = ordered_list.index(_key)
            worksheet.write(row, col, _value)
        row += 1
    workbook.save(filename)


def execute_sql(sql):
    mycursor, mydb = dbConnet(DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, DB_DATABASE)
    mycursor.execute(sql)
    sqlresults = mycursor.fetchall()
    mydb.commit()
    mycursor.close()
    mydb.close()
    if sqlresults:
        filename = 'prod-tidb-slowlogs.xls'
        createExcel(sqlresults, filename)
        sendEmail(filename)
        if os.path.exists(RECORDS_EXCEL_FILENAME):
            os.remove(RECORDS_EXCEL_FILENAME)
            print("已删除临时文件")
        else:
            print("临时文件不存在!")
    else:
        print(lastsomeday.strftime('%Y%m%d') + "至" + nt.strftime('%Y%m%d') + "没有相关的慢SQL")


def main():
    print("====" + nt.strftime('%Y%m%d %H:%M:%s') + "====")
    query = ("SELECT "
             "Digest AS 'UID',"
             "count( 1 ) AS 'Count',"
             "DB AS '数据库',"
             "CONCAT( CAST(( Query_time ) AS CHAR ( 4 )), 's' ) AS '执行耗时',"
             "Total_keys AS '扫描总Key个数',"
             "CONCAT('\\'',Time) AS '执行时间', "
             "User AS '执行用户',"
             "Host AS '主机',"
             "Result_rows AS '返回结果行数',"
             "CONCAT( CAST(( Mem_max / 1024 / 1024 ) AS CHAR ( 4 )), 'MB' ) AS '内存',"
             "CONCAT( CAST(( Cop_time ) AS CHAR ( 4 )), 's' ) AS 'Cop_time',"
             "CONCAT( CAST(( Write_sql_response_total ) AS CHAR ( 4 )), 's' ) AS 'Write_sql_response_total',"
             "Total_keys,"
             "Process_keys,"
             "Query AS 'SQL语句'"
             "FROM    INFORMATION_SCHEMA.CLUSTER_SLOW_QUERY "
             "WHERE "
             "Query_time >= '%s' "
             "AND Time >= DATE_SUB( '%s' , INTERVAL '%s' DAY )  "
             "AND db not in  ('','要排除的DB')"
             "AND host not in  ('要排除的客户端IP地址','要排除的客户端IP地址') "
             "AND user NOT IN ( '要排除的客户端用户名' , '要排除的客户端用户名', '要排除的客户端用户名')"
             "GROUP BY Digest "
             "ORDER BY Query_time DESC , Result_rows DESC, Count DESC "
             "LIMIT 1000;" % (slowtime, nt, slow_from_day)
             )
    execute_sql(query)


if __name__ == "__main__":
    main()
Copyright Curiouser all right reserved,powered by Gitbook该文件最后修改时间: 2023-02-07 18:13:48

results matching ""

    No results matching ""