通过Python实现对SQL Server 数据文件大小的监控告警功能

1.需求背景

系统程序突然报错,报错信息如下:

The transaction log for database '@dbname' is full. To find out why space in the log cannot be reused, see the log_reuse_wait_desc column in sys.databases

此时查看log文件,已达2T。

当时的紧急处理方案是,移除掉镜像,修改数据库恢复模式(由full修改为simple),收缩日志。

为了防止类似问题再次发生,需对log 文件的大小进行监控,当到达阈值后,触发告警。

2.主要基础组件(类)

配置文件qqmssqltest_db_server_conf.ini

同过此配置文件获取DB Server信息、DB信息、UID信息、邮件服务器信息等。

[sqlserver]
db_user = XXXXXX
db_pwd = XXXXXXX

[sqlserver_qq]
db_host = 110.119.120.114
db_port = 1433

[windows]
user =
pwd = 

[mail]
host = zheshiceshidemail.qq.com
port = 25
user =
pwd =
sender = zhejiushiceshidebuyaodangzhen@qq.com

获取连接串的组件mssql_get_db_connect.py

# -*- coding: utf-8 -*-

import sys
import os
import datetime
import configparser
import pymssql
# pip3 install pymssql-2.1.4-cp37-cp37m-win_amd64.whl
# pip3 install pymssql -i https://pypi.doubanio.com/simple

# 获取连接串信息
def mssql_get_db_connect(db_host, db_port):
    db_host = db_host
    db_port = db_port

    db_ps_file = os.path.join(sys.path[0], "qqmssqltest_db_server_conf.ini")
    config = configparser.ConfigParser()
    config.read(db_ps_file, encoding="utf-8")
    db_user = config.get('sqlserver', 'db_user')
    db_pwd = config.get('sqlserver', 'db_pwd')

    conn = pymssql.connect(host=db_host, port=db_port, user=db_user, password=db_pwd, charset="utf8", login_timeout=5, timeout=600, autocommit=True)

    return conn

执行SQL语句的组件mysql_exec_sql.py

# -*- coding: utf-8 -*-

import mysql_get_db_connect

def mysql_exec_dml_sql(db_host, db_port, exec_sql):
    conn = mysql_get_db_connect.mysql_get_db_connect(db_host, db_port)
    with conn.cursor() as cursor_db:
        cursor_db.execute(exec_sql)
        conn.commit()

def mysql_exec_select_sql(db_host, db_port, exec_sql):
    conn = mysql_get_db_connect.mysql_get_db_connect(db_host, db_port)
    with conn.cursor() as cursor_db:
        cursor_db.execute(exec_sql)
        sql_rst = cursor_db.fetchall()

    return sql_rst

def mysql_exec_select_sql_include_colnames(db_host, db_port, exec_sql):
    conn = mysql_get_db_connect.mysql_get_db_connect(db_host, db_port)
    with conn.cursor() as cursor_db:
        cursor_db.execute(exec_sql)
        sql_rst = cursor_db.fetchall()
        col_names = cursor_db.description
    return sql_rst, col_names

发邮件的功能send_monitor_mail.py

# -*- coding: utf-8 -*-

# pip3 install PyEmail
import smtplib
from email.mime.text import MIMEText
import configparser
import os
import sys

# 发送告警邮件
def send_monitor_mail(mail_subject, mail_body, mail_receivers="testwukongbaigujing@qq.com"):
    db_ps_file = os.path.join(sys.path[0], "qqmssqltest_db_server_conf.ini")
    config = configparser.ConfigParser()
    config.read(db_ps_file, encoding="utf-8")
    mail_host = config.get('mail', 'host')
    mail_port = config.get('mail', 'port')
    # mail_user = config.get('mail', 'user')
    # mail_pwd = config.get('mail', 'pwd')
    sender = config.get('mail', 'sender')
    # receivers = config.get('mail', 'receivers')

    # 发送HTML格式邮件
    message = MIMEText(mail_body, 'html', 'utf-8')
    # message = MIMEText(mail_body, 'plain', 'utf-8')
    message['subject'] = mail_subject
    message['From'] = sender
    message['To'] = mail_receivers

    try:
        smtpObj = smtplib.SMTP()
        smtpObj.connect(mail_host, mail_port)          # 25 为 SMTP 端口号
        # SMTP AUTH extension not supported by server.
        # https://github.com/miguelgrinberg/microblog/issues/76
        # smtpObj.ehlo()
        # smtpObj.starttls()
        # smtpObj.login(mail_user, mail_pwd)
        smtpObj.sendmail(sender, mail_receivers, message.as_string())
        smtpObj.quit()
        print("邮件发送成功")
    except Exception as e:
        print(e)
    # except smtplib.SMTPException:
        # print("Error: 无法发送邮件")

3.主要功能代码

收集到的DB数据文件的信息保存到表mssql_dblogsize中,其建表的脚本如下:

CREATE TABLE [dbo].[mssql_dblogsize](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [createtime] [datetime] NULL,
    [vip] [nvarchar](100) NULL,
    [port] [nvarchar](100) NULL,
    [Environment] [nvarchar](200) NULL,
    [Dbname] [varchar](200) NULL,
    [Logical_Name] [varchar](200) NULL,
    [Physical_Name] [varchar](1500) NULL,
    [Size] [bigint] NULL,
PRIMARY KEY CLUSTERED
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[mssql_dblogsize] ADD  DEFAULT (getdate()) FOR [createtime]
GO

为了方便对表mssql_dblogsize的数据进行管理和展示,在其基础上抽象加工出了一个视图v_mssql_dblogsize,注意Size大小的转换(Size/128/1024 as SizeGB)

创建视图的脚本如下:

CREATE view [dbo].[v_mssql_dblogsize]
as
SELECT [id]
      ,[createtime]
      ,[vip]
      ,[port]
      ,[Environment]
      ,[Dbname]
      ,[Logical_Name]
      ,[Physical_Name]
      ,Size/128/1024 as SizeGB
  FROM [dbo].[mssql_dblogsize]
where size >50*128*1024
and Physical_Name like '%ldf%'
GO

本测试实例使用的数据库为qqDB,监控的各个DB Server保存在了表QQDBServer中,注意Port 不一定为标准端口1433.

collect_mssql_dblogsize_info.py

# -*- coding: utf-8 -*-

import sys
import os
import configparser
import pymssql
import mssql_get_db_connect
import mssql_exec_sql
from datetime import datetime

def collect_mssql_dblogsize_info():

    db_ps_file = os.path.join(sys.path[0], "qqmssqltest_db_server_conf.ini")
    config = configparser.ConfigParser()
    config.read(db_ps_file, encoding="utf-8")
    m_db_host = config.get('sqlserver_qq', 'db_host')
    m_db_port = config.getint('sqlserver_qq', 'db_port')

    # 获取需要遍历的DB列表
    exec_sql_1 = """
SELECT IP, case Port when '1444,1433' then '1433' else Port end as Port, Environment
FROM qqDB.dbo.QQDBServer
where InUse =1 AND ServerType IN ('SQL')
and IP=VIP ;
    """
    sql_rst_1 = mssql_exec_sql.mssql_exec_select_sql(m_db_host, m_db_port, exec_sql_1)
    for j in sql_rst_1:
        db_host_2 = j[0]
        db_port_2 = j[1]
        db_Environment = j[2]
        exec_sql_2 = """
        select '""" + db_host_2 + """' as vip, '""" + db_port_2 + """' as port, '""" + db_Environment + """' as Environment,DB_NAME(database_id) AS DatabaseName,
Name AS Logical_Name,
Physical_Name, size
FROM master.sys.master_files;
        """
        try:
           sql_rst_2 = mssql_exec_sql.mssql_exec_select_sql(db_host_2, db_port_2, exec_sql_2)
        except Exception as e:
           print(e)

        for k in sql_rst_2:
           exec_sql_3 = """
           insert into qqDB..mssql_dblogsize([vip], [port], [Environment], [Dbname], [Logical_Name], [Physical_Name], [Size])
           values('%s', '%s', '%s', '%s', '%s', '%s', '%s');
           """
           conn = mssql_get_db_connect.mssql_get_db_connect(m_db_host, m_db_port)
           with conn.cursor() as cursor_db:
               cursor_db.execute(exec_sql_3 % (k[0], k[1], k[2], k[3], k[4], k[5], k[6] ))
               conn.commit()
collect_mssql_dblogsize_info()

告警邮件的功能实现为mssql_alert_dblogsize.py,此份代码的告警阈值设置的为50G,数据来自于视图v_mssql_dblogsize。

# -*- coding: utf-8 -*-

import sys
import os
import configparser
import pymssql
import mssql_get_db_connect
import mssql_exec_sql
import datetime
import send_monitor_mail
import pandas as pd

def mssql_alert_dblogsize():
    mail_subject = "SQL Server DB Log Size Greater than 50G, please check!!! "
    mail_receivers = "testDBAgrp@qtiantianq.com"

    db_ps_file = os.path.join(sys.path[0], "qqmssqltest_db_server_conf.ini")
    config = configparser.ConfigParser()
    config.read(db_ps_file, encoding="utf-8")
    m_db_host = config.get('sqlserver_qq', 'db_host')
    m_db_port = config.getint('sqlserver_qq', 'db_port')

    # 获取需要遍历的DB列表

    exec_sql_4 = """
        SELECT [vip] as IP,[port],[Environment],[Dbname]
      ,[Logical_Name],[Physical_Name],[SizeGB],[createtime]
  FROM qqDB.[dbo].[v_mssql_dblogsize]
  order by VIP,Dbname;
    """
    sql_rst_4, col_name = mssql_exec_sql.mssql_exec_select_sql_include_colnames(m_db_host, m_db_port, exec_sql_4)
    # print(sql_rst_4)

    if len(sql_rst_4):
        mail_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')

        columns = []
        for i in range(len(col_name)):
            columns.append(col_name[i][0])

        df = pd.DataFrame(columns=columns)
        for i in range(len(sql_rst_4)):
            df.loc[i] = list(sql_rst_4[i])

        mail_body = df.to_html(index=False, justify="left").replace('<th>', '<th style = "color:red; text-align:left; background-color: yellow">')
        mail_html = "<html><body><h4>" + "Deal All : " + "<br><h4>" + "以下数据库的db log文件,已大于50G.请及时检查,谢谢! " + "<br><h4>" + mail_body + "</body></html>"

        send_monitor_mail.send_monitor_mail(mail_subject=mail_subject, mail_body=mail_html, mail_receivers=mail_receivers)

mssql_alert_dblogsize()

4.实现

定时任务是通过windows的计划任务来实现的,在此不做过多的叙述。告警邮件的部分截图如下:

5.附录

1.报错定位,判断是不是log文件过大

https://blog.csdn.net/weixin_30785593/article/details/99912405

2.关于为什么数据库log文件过大,我们可以参考以下分享的文章

https://blog.csdn.net/chinadm123/article/details/44941275

到此这篇关于通过Python实现对SQL Server 数据文件大小的监控告警的文章就介绍到这了,更多相关PythonSQL Server 数据监控告警内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 用pushplus+python监控亚马逊到货动态推送微信

    xbox series和ps5发售以来,国内黄牛价格一直居高不下.虽然海外amazon上ps5补货很少而且基本撑不过一分钟,但是xbox series系列明显要好抢很多. 日亚.德亚的xbox series x/s都可以直邮中国大陆,所以我们只需要借助脚本,监控相关网页的动态,在补货的第一时刻通过微信告知我们,然后迅速人工购买即可! 需求:pushplus(需要微信关注公众号).python3 一.pushplus相关介绍 pushplus提供了免费的微信消息推送api,具体内容可以参考他的官网

  • python实现的web监控系统

    完整项目地址: https://github.com/zsjtoby/DevOpsCloud 欢迎使用极云监控系统 极云监控系统实现了跳板机应有的功能.基于ssh协议来管理,客户端无需安装agent. 支持常见系统: CentOS, RedHat, Fedora, Amazon Linux Debian SUSE, Ubuntu FreeBSD 其他ssh协议硬件设备 首页 WebTerminal: Web批量执行命令 录像回放 跳转和批量命令 命令统计 安装 cd /opt git clone

  • python使用Windows的wmic命令监控文件运行状况,如有异常发送邮件报警

       使用Windows的wmic命令,获取可执行文件的运行状况.文件路径.PID,如果可执行文件挂掉,就重启并邮件告警. 因为监控的可执行文件的文件名一样,不好区分,所以我使用文件的绝对路径为标准来判断是否正常运行,代码及详细解释如下: # -*- coding: utf-8 -*- import os import win32api import smtplib from email.mime.text import MIMEText def get_pidWay(file_name): e

  • python实时监控logstash日志代码

    实时读取logstash日志,有异常错误keywork即触发报警. # /usr/bin/env python3 # -*- coding: utf-8 -*- # __author__ = caozhi # create_time 2018-11-12,update_time 2018-11-15 # version = 1.0 # 录像高可用报警 # 1 读取日志 使用游标移动 # 2 线上业务日志文件会切割,切割后,读取上一个切割的日志 import os import sys impor

  • 如何基于Python和Flask编写Prometheus监控

    介绍 Prometheus 的基本原理是通过 HTTP 周期性抓取被监控组件的状态. 任意组件只要提供对应的 HTTP 接口并且符合 Prometheus 定义的数据格式,就可以接入 Prometheus 监控. Prometheus Server 负责定时在目标上抓取 metrics(指标)数据并保存到本地存储.它采用了一种 Pull(拉)的方式获取数据,不仅降低客户端的复杂度,客户端只需要采集数据,无需了解服务端情况,也让服务端可以更加方便地水平扩展. 如果监控数据达到告警阈值,Promet

  • python 自动监控最新邮件并读取的操作

    我就废话不多说了,大家还是直接看代码吧~ #zmail库:可以用几行代码帮我们收取一封邮件 import zmail #输入账号和密码 server=zmail.server('13163964546@qq.com','jie110341') #获取最新的一封邮件 mail=server.get_latest() #读取邮件 #zmail.show(mail) #读取邮件的部分内容 print(mail['subject']) ...... #读取附件 邮件 存放路径 如果有同名文件则覆盖 zm

  • 用python监控服务器的cpu,磁盘空间,内存,超过邮件报警

    监控Linux服务器嘛,脚本逻辑基本上是用os.popen模块,然后把获取到的结果通过split切分成一个list,再拿目标list值和我阈值对比,超过就邮件报警: 邮件是通过Linux的mailx发出去的,可自行搜索安装该模块,关键字:"Linux使用mailx发邮件",脚本如下: 一.cpu ideal值,不小于20% #!/usr/bin/python # -*- coding: utf-8 -*-   import datetime import os     f = os.p

  • Python实时监控网站浏览记录实现过程详解

    需求: (1) 获取你对象chrome前一天的浏览记录中的所有网址(url)和访问时间,并存在一个txt文件中 (2)将这个txt文件发送给指定的邮箱地址(你的邮箱) (3)建立例行任务,每天定时自动完成这些操作,你就可以通过邮件查看你对象每天看啥了 准备 macOS Sierra Python3.6 Chrome 发送邮件的qq邮箱地址 qq邮箱授权码 SMTP服务器地址 : smtp.qq.com 接受邮件的邮箱地址 执行: (1) 首先我们用DB Browser for SQLite来看下

  • python使用pynput库操作、监控你的鼠标和键盘

    楔子 python是一门很神奇的语言,原因在于它有很多的库可以实现各种意想不到的功能.当然我们这次介绍的库所实现的功能却是已经很常见了,就是操作.监控你的鼠标和键盘.如果你写过游戏,那么即使不用下面即将介绍的库也可以实现对鼠标.键盘的操作以及监控. 当然我们下面介绍库:pynput,是专门针对鼠标和键盘的,至于pygame.pyglet等游戏框架虽然也提供了鼠标.键盘的监控事件,但它们毕竟是用来开发游戏的,还提供了创建窗口.图形绘制.物体的碰撞检测等等很多复杂的功能.如果只是单纯的操作鼠标和键盘

  • python自动统计zabbix系统监控覆盖率的示例代码

    脚本主要功能: 1)通过zabbix api接口采集所有监控主机ip地址: 2)通过cmdb系统(蓝鲸)接口采集所有生产主机IP地址.主机名.操作系统.电源状态: 3)以上2步返回数据对比,找出未监控主机ip地址,生成csv文件: 4)发送邮件. 脚本如下: #!/usr/bin/python #coding:utf-8 import requests import json import re import time import csv from collections import Cou

  • python基于watchdog库全自动化监控目录文件

    楔子 有些时候我们需要对一个目录进行监控,检测其内部是否有文件的新增.删除.以及每个文件的内容是否发生变化,这个时候如果是你的话,你会选择怎么做呢? 显然也是一个比较麻烦的工作,倒不是说难,主要是比较繁杂.但万幸的是,已经有一个第三方包watchdog帮我们完美地实现了这一点,所以这就是Python啊,想做什么都有现成的. 那么下面就来看一下它的用法,当然要先安装.直接:pip install watchdog即可. 使用方法 在我的桌面上有一个空目录test,一会儿我们对这个目录做的操作都会体

随机推荐