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...】

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