Flask + flask_apscheduler + logging 定时获取阿里云 elasticsearch 慢查询日志

需求:每天定时获取阿里云上 elasticsearch 上的慢查询日志,通过钉钉发送消息到群里并提供下载 xlsx 文件。

目录结构

创建一个 Python Package 名为 operate 文件夹,在该文件夹下创建两个 py 文件,elasticsearch.py 和 dingtalk.py
elasticsearch.py 内容为:

from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.request import CommonRequest
from config import CurrentConfig as Config
import json
import time
from datetime import datetime, date, timedelta
import openpyxl
from operate import dingtalk
import logging


accessKeyId = Config.accessKeyId
accessSecret = Config.accessSecret
folder = Config.folder

client = AcsClient(accessKeyId, accessSecret, 'cn-shenzhen')

request = CommonRequest()
request.set_accept_format('json')
request.set_method('GET')
request.set_protocol_type('https') # https | http
request.set_domain('elasticsearch.cn-shenzhen.aliyuncs.com')
request.set_version('2017-06-13')

yesterday = (date.today() + timedelta(days=-1)).strftime("%Y-%m-%d")


def get_elastic_slow_log(begin_time, end_time, type):
    request.add_query_param('type', type)
    request.add_query_param('query', "level:warn")
    request.add_query_param('beginTime', begin_time)
    request.add_query_param('endTime', end_time)
    request.add_query_param('size', "50")
    request.add_header('Content-Type', 'application/json')
    request.set_uri_pattern('/openapi/instances/es-cn-xxxxxxxxxxxxxx/search-log')
    body = '''{}'''
    request.set_content(body.encode('utf-8'))

    response = client.do_action_with_exception(request)

    result_json = json.loads(str(response, encoding='utf-8'))

    return result_json['Headers']['X-Total-Count'], result_json['Result']


def generate_xlsx(result_count, result_json, type):
    if result_json and result_count != 0:
        filename = folder + "elasticsearch_slow_sql_" + type + "_" + yesterday + ".xlsx"
        workbook = openpyxl.Workbook()
        sheet = workbook.active

        for i in range(result_count):
            timestamp = result_json[i]['timestamp']
            instanceId = result_json[i]['instanceId']
            host = result_json[i]['host']
            level = result_json[i]['contentCollection']['level']
            mytime = result_json[i]['contentCollection']['time']
            content = result_json[i]['contentCollection']['content']

            data = [timestamp, mytime, instanceId, host, level, content]
            sheet.append(data)

        workbook.save(filename=filename)

        # 发送钉钉消息
        msg = "http://192.168.0.200:81" + filename
        dingtalk.send_msg(msg)


def main():
    end_time = int(round(time.time() * 1000))
    begin_time = end_time - 86400 * 1000

    from app import app      # 把 app 作为变量公开,在函数中导入
    app.logger.warning('program is running: %s', datetime.now())

    # searching 慢查询日志
    result_count1, result_json1 = get_elastic_slow_log(begin_time, end_time, 'SEARCHSLOW')
    generate_xlsx(result_count1, result_json1, 'searching')

    # indexing 慢查询日志
    result_count2, result_json2 = get_elastic_slow_log(begin_time, end_time, 'INDEXINGSLOW')
    generate_xlsx(result_count2, result_json2, 'indexing')

dingtalk.py 内容为:

import json
import requests

# 定义环境
from config import CurrentConfig as Config

url = Config.DINGTALK_URL


def send_msg(msg):
    parameter = {
        "msgtype": "text",
        "text": {
            "content": "云服务 -- 线上 elasticsearch 慢查询日志已生成,下载请点击:%s ,请及时查看(该链接只可以在公司内网打开)~" % msg
        },
    }
    headers = {
        'Content-Type': 'application/json'
    }
    requests.post(url, data=json.dumps(parameter), headers=headers)

app.py 内容为

from flask import Flask
from flask_apscheduler import APScheduler
from operate import elasticsearch
import logging

app = Flask(__name__)


@app.route('/')
def hello_world():
    return 'aliyun elasticsearch slow log is running!'


class SchedulerConfig(object):
    JOBS = [
        {
            'id': 'elasticsearch',                       # 任务id
            'func': 'operate.elasticsearch:main',        # 任务执行程序
            'args': None,                                # 执行程序参数
            'trigger': 'interval',                       # 任务执行类型
            'seconds': 60
        }
    ]
    SCHEDULER_TIMEZONE = 'Asia/Shanghai'                 # 设定时区


app.config.from_object(SchedulerConfig())                # 为实例化的flask引入定时任务配置
scheduler = APScheduler()                                # 实例化APScheduler
scheduler.init_app(app)                                  # 把任务列表载入实例flask
scheduler.start()                                        # 启动任务计划

handler = logging.FileHandler('flask.log', encoding='UTF-8')   # 设置日志字符集和存储路径名字
logging_format = logging.Formatter('%(asctime)s - %(levelname)s - %(filename)s - %(funcName)s - %(lineno)s - %(message)s')  # 设置日志格式
handler.setFormatter(logging_format)
app.logger.addHandler(handler)


if __name__ == '__main__':
    app.run()

配置文件 config.py 的内容:


class ProductionConfig:
    accessKeyId = 'xxxxxxxxxxxxxxxx'
    accessSecret = 'xxxxxxxxxxxxxxxx'
    folder = '/elasticsearch_xlsx/'
    DINGTALK_URL = 'https://oapi.dingtalk.com/robot/send?access_token=xxxxxxxxxxxxxxxx' # 运维组


class DevConfig:
    accessKeyId = 'xxxxxxxxxxxxxxxx'
    accessSecret = 'xxxxxxxxxxxxxxxx'
    folder = 'D:\\flask_projects\\alarm4aliyun_elasticsearch_slowlog\\elasticsearch_xlsx\\'
    DINGTALK_URL = 'https://oapi.dingtalk.com/robot/send?access_token=xxxxxxxxxxxxxxxx' # 运维组


class CurrentConfig(DevConfig):
    pass

在 PyCharm 中 使用命令导出依赖

pip freeze > requirements.txt

把程序打包到 docker 镜像

# 代码上传到 /data/alarm4slow_elasticsearch

# 拷贝时区文件到目录下
cp /usr/share/zoneinfo/Asia/Shanghai .

# 编辑 Dockerfile  内容为
FROM python:3.6
WORKDIR /data

RUN echo "Asia/Shanghai" > /etc/timezone
RUN mkdir /elasticsearch_xlsx/
COPY Shanghai /etc/localtime
COPY requirements.txt ./
RUN pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/

COPY . .

CMD ["gunicorn", "-w", "1", "-b", "0.0.0.0:8888", "app:app"]

# 打包成 docker 镜像

docker build -t alarm4aliyun_elasticsearch_slow_log:0.0.1 ./

创建 docker-compose.yml

# 创建目录保存 xlsx 文件
mkdir -p /data/elasticsearch_xlsx

# 编辑 docker-compose.yml 
version: '3.4'
services:
  alarm4aliyun_elasticsearch_slow_log: 
    image: alarm4aliyun_elasticsearch_slow_log:0.0.1
    volumes:
      - /data/elasticsearch_xlsx:/elasticsearch_xlsx

# 启动
docker-compose up -d

在这台机器上启动一个 nginx 提供下载 xlsx 服务

vi docker-compose.yml
version: '3.4'
services:
  nginx: 
    image: nginx:1.19
    ports:
      - 81:80
    volumes:
      - /data/elasticsearch_xlsx:/usr/share/nginx/html/elasticsearch_xlsx

# 启动
docker-compose up -d

若需要在镜像中调试,需要在容器中安装 vim

sed -i 's#http://deb.debian.org#https://mirrors.163.com#g' /etc/apt/sources.list
apt-get update
apt-get install vim

参考:https://github.com/viniciuschiele/flask-apscheduler/issues/16

posted @ 2020-11-11 17:59  klvchen  阅读(628)  评论(0)    收藏  举报