logger.py 3.58 KB
Newer Older
Weizhi Cui's avatar
Weizhi Cui committed
1 2 3 4 5 6 7 8 9 10 11 12
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version     : Python 3.11.4
# @Software    : Sublime Text 4
# @Author      : StudentCWZ
# @Email       : StudentCWZ@outlook.com
# @Date        : 2023/10/28 17:44
# @File        : logger.py
# @Description :
"""

崔为之's avatar
崔为之 committed
13
import os
Weizhi Cui's avatar
Weizhi Cui committed
14 15 16 17 18 19
import sys

from flask import Flask, request, g
from loguru import logger

from .format import patching
崔为之's avatar
崔为之 committed
20
from application.libs.helper import ConfigHelper
Weizhi Cui's avatar
Weizhi Cui committed
21 22 23 24


class FlaskLoguru:
    def __init__(self, app=None):
崔为之's avatar
崔为之 committed
25
        """
崔为之's avatar
崔为之 committed
26 27 28
        Construct a new FlaskLoguru instance.

        :param app: Optional Flask app to initialize this FlaskLoguru instance for.
崔为之's avatar
崔为之 committed
29
        """
Weizhi Cui's avatar
Weizhi Cui committed
30 31 32
        if app is not None:
            self.init_app(app)

崔为之's avatar
崔为之 committed
33
    def init_app(self, app: Flask) -> None:
崔为之's avatar
崔为之 committed
34
        """
崔为之's avatar
崔为之 committed
35 36 37
        Initialize the given Flask app for logging.

        :param app: The Flask app to initialize.
崔为之's avatar
崔为之 committed
38 39
        """

崔为之's avatar
崔为之 committed
40
        # Initialize ConfigHelper
崔为之's avatar
崔为之 committed
41 42 43 44
        config_helper = ConfigHelper(app)
        # Fetch the logging configuration from the app's config
        cfg = config_helper.Logger

崔为之's avatar
崔为之 committed
45 46 47 48 49 50 51 52 53
        # Configure logger based on provided config
        log_type = cfg.get('Type', 'terminal')
        level = cfg.get('Level', 'DEBUG')
        path = cfg.get('Path')
        name = cfg.get('Name')
        _format = cfg.get('Format') or patching
        rotation = cfg.get('Rotation', '1 day')
        enqueue = cfg.get('Enqueue', False)
        retention = cfg.get('Retention', '10 days')
崔为之's avatar
崔为之 committed
54

崔为之's avatar
崔为之 committed
55 56
        # Remove any existing handlers from the logger
        logger.remove()
崔为之's avatar
崔为之 committed
57

崔为之's avatar
崔为之 committed
58 59 60 61
        # If the logger type is 'both' or 'file' and a path and a name are provided, add a file logger
        if self._should_add_file_logger(log_type, path, name):
            full_path = os.path.join(path, name)
            logger.add(full_path, level=level, format=_format, rotation=rotation, retention=retention, enqueue=enqueue)
Weizhi Cui's avatar
Weizhi Cui committed
62

崔为之's avatar
崔为之 committed
63 64 65
        # If the logger type is 'both' or 'terminal', add a terminal logger
        if self._should_add_terminal_logger(log_type):
            logger.add(sys.stderr, level=level, format=_format)
崔为之's avatar
崔为之 committed
66

崔为之's avatar
崔为之 committed
67 68
        # Register this logger with the app
        app.extensions.setdefault('loguru', {})
崔为之's avatar
崔为之 committed
69
        app.extensions['loguru'][self] = logger
Weizhi Cui's avatar
Weizhi Cui committed
70

崔为之's avatar
崔为之 committed
71
        # Add logger to Flask's before, after and teardown request handlers
Weizhi Cui's avatar
Weizhi Cui committed
72
        @app.before_request
崔为之's avatar
崔为之 committed
73
        def _log_request_start():
崔为之's avatar
崔为之 committed
74
            """
崔为之's avatar
崔为之 committed
75
            Log the start of the request.
崔为之's avatar
崔为之 committed
76
            """
崔为之's avatar
崔为之 committed
77
            data = dict(url=request.url, method=request.method, ip=request.remote_addr, request_body=request.get_json())
Weizhi Cui's avatar
Weizhi Cui committed
78 79 80 81
            g.logger = logger.bind(data=data)
            g.logger.info('Request started')

        @app.after_request
崔为之's avatar
崔为之 committed
82
        def _log_request_completion(response):
崔为之's avatar
崔为之 committed
83
            """
崔为之's avatar
崔为之 committed
84
            Log the end of the request.
崔为之's avatar
崔为之 committed
85
            """
Weizhi Cui's avatar
Weizhi Cui committed
86 87 88 89
            g.logger.info('Request completed')
            return response

        @app.teardown_request
崔为之's avatar
崔为之 committed
90
        def _log_request_teardown(exception=None):
崔为之's avatar
崔为之 committed
91
            """
崔为之's avatar
崔为之 committed
92
            Log any exception that occurred during the request.
崔为之's avatar
崔为之 committed
93
            """
Weizhi Cui's avatar
Weizhi Cui committed
94
            if exception:
崔为之's avatar
崔为之 committed
95
                data = dict(exception=str(exception))
Weizhi Cui's avatar
Weizhi Cui committed
96 97
                g.logger = logger.bind(data=data)
                g.logger.exception('An error occurred during the request')
崔为之's avatar
崔为之 committed
98 99 100 101 102 103 104 105 106 107 108 109 110 111

    @staticmethod
    def _should_add_file_logger(log_type: str, path: str, name: str) -> bool:
        """
        Determine if a file logger should be added.
        """
        return log_type in ['both', 'file'] and path and name

    @staticmethod
    def _should_add_terminal_logger(log_type: str) -> bool:
        """
        Determine if a terminal logger should be added.
        """
        return log_type in ['both', 'terminal']