(二)Flask记录日志

关联文章:项目进度记录

关于Flask日志记录,网上的文章大多都已过时,我在项目开发过程中,结合实际情况,初步采用以下日志方案,后续遇到问题会不断进行优化,并更新文章内容。

日志记录的总体思路如下:

  1. 在 Flask 工厂函数中,利用钩子函数,将接口每次的请求参数和响应内容写入到日志文件中,并利用flask_sqlalchemy提供的get_debug_queries方法,实现当执行时间超过阈值时,将查询信息按照指定的格式写入到日志文件中;
  2. 接入Sentry SDK,收集项目错误日志,然后在Sentry Dashboard查看异常信息;(点击查看官方文档)

工厂函数相关内容如下,注释已经写得很清楚了:

from pathlib import Path
from logging.handlers import RotatingFileHandler

from flask import Flask
from flask_sqlalchemy import get_debug_queries
import sentry_sdk
from sentry_sdk.integrations.flask import FlaskIntegration


from .config import config

# 递归创建日志存放目录
basedir = Path(__file__).parent.parent  # 项目根目录
logdir = basedir.joinpath(r'rethink/logs')
if not logdir.is_dir():
    os.makedirs(logdir)

# 初始化Sentry, 必须在工厂函数之前
sentry_sdk.init(
    dsn="官网注册账号后会给出",
    integrations=[FlaskIntegration()]
)

def make_app(config_name=None):
    if config_name is None:
        config_name = os.getenv("FLASK_CONFIG", "development")

    # 加载配置文件
    app = Flask(__name__)
    app.config.from_object(config[config_name])

    register_logger(app)  # 注册日志处理器

    # 如果没有未处理的异常抛出,会在每个请求结束后运行
    # 必须接受一个响应类对象作为参数,并返回同一个或更新后的响应对象
    @app.after_request
    def response_logger(response):
        # 获取接口响应数据
        api_path = request.full_path
        api_method = request.method
        ip_addr = request.remote_addr
        # 获取接口请求数据
        try:
            request_data = request.get_json(force=True)
        except Exception as e:
            request_data = request.form.to_dict()

        request_data, response_data = str(request_data), str(response.json)

        with open(logdir.joinpath('runtime.log'), 'a+', encoding="utf-8") as f:
            asctime = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            f.write(
                asctime + " " + ip_addr + " " + api_method + " " + api_path + '->' + request_data + '\n' + response_data + '\n')

        # 记录慢查询日志,在日志处理器函数中会将其写入到文件中
        for query in get_debug_queries():
            if query.duration >= app.config['FLASK_SLOW_DB_QUERY_TIME']:
                app.logger.warning(
                    'Slow query: %s\n Parameters: %s\n Duration: %fs\n Context: %s'
                    % (query.statement, query.parameters, query.duration, query.context))

        return response

    return app


def register_logger(app):
    app.logger.setLevel(logging.INFO)
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    # 设置日志文件最大尺寸和备份数量
    # 最大尺寸为10M,当超过10M产生备份文件,最多产生10个备份文件,10个备份文件全部存满后,会开始覆盖之前的文件
    file_handler = RotatingFileHandler(logdir.joinpath('runtime.log'), maxBytes=10 * 1024 * 1024, backupCount=10)
    file_handler.setFormatter(formatter)
    file_handler.setLevel(logging.INFO)
    
    app.logger.addHandler(file_handler)
    app.logger.info('Autoline Startup...')  # 这里额外在日志文件中记录下每次应用服务的启动时间

config.py是项目配置文件,相关内容如下:

class BaseConfig(object):
    # 启用慢查询记录功能(调试模式下自动启用), 为了在生产环境下可用,必须手动配置此项为True
    SQLALCHEMY_RECORD_QUERIES = True
    # 慢查询阈值
    FLASK_SLOW_DB_QUERY_TIME = 0.001
    
class DevelopmentConfig(BaseConfig):
    SQLALCHEMY_DATABASE_URI = os.getenv("DB_DEVELOPMENT_URI")

class TestingConfig(BaseConfig):
    SQLALCHEMY_DATABASE_URI = os.getenv("DB_Testing_URI")


class ProductionConfig(BaseConfig):
    SQLALCHEMY_DATABASE_URI = os.getenv('DB_PRODUCTION_URI')

config = {
    'development': DevelopmentConfig,
    'testing': TestingConfig,
    'production': ProductionConfig
}

在配置文件中,为了测试慢查询日志记录,特意将FLASK_SLOW_DB_QUERY_TIME设置为0.001s. 在本地开发环境下请求下flask接口,在控制台可以看到有相关的日志输出,如下:

查看runtime.log,可以看到接口请求日志和慢查询日志都已经被写入了:

当接口出现异常时,在Sentry Dashboard中可以看到非常详细的日志信息。

【To Be Continued...】

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章