|
|
@ -32,6 +32,8 @@ no value is present in the message record. |
|
|
|
|
|
|
|
import logging |
|
|
|
|
|
|
|
from flask import has_request_context, request |
|
|
|
|
|
|
|
__version_info__ = ('0', '0', '1') |
|
|
|
__version__ = '.'.join(__version_info__) |
|
|
|
__author__ = 'Gergely Polonkai' |
|
|
@ -40,7 +42,8 @@ __copyright__ = '(c) 2015 GT2' |
|
|
|
|
|
|
|
class FlaskExtraLogger(logging.getLoggerClass()): |
|
|
|
""" |
|
|
|
A logger class that is capable of adding extra keywords to log formatters |
|
|
|
A logger class that is capable of adding extra keywords to log |
|
|
|
formatters and logging the blueprint name |
|
|
|
|
|
|
|
Usage: |
|
|
|
|
|
|
@ -55,8 +58,14 @@ class FlaskExtraLogger(logging.getLoggerClass()): |
|
|
|
|
|
|
|
app = Flask(__name__) |
|
|
|
app.config['FLASK_LOGGING_EXTRAS_KEYWORDS'] = {'category': '<unset>'} |
|
|
|
app.config['FLASK_LOGGING_EXTRAS_BLUEPRINT'] = ('blueprint', |
|
|
|
'<APP>', |
|
|
|
'<NOT REQUEST>') |
|
|
|
app.logger.init_app() |
|
|
|
|
|
|
|
bp = Blueprint('my_blueprint', __name__) |
|
|
|
app.register_blueprint(bp) |
|
|
|
|
|
|
|
formatter = logging.Formatter( |
|
|
|
'[%(asctime)s] [%(levelname)s] [%(category)s] %(message)s') |
|
|
|
handler = logging.FileHandler('app.log', mode='a') |
|
|
@ -68,9 +77,38 @@ class FlaskExtraLogger(logging.getLoggerClass()): |
|
|
|
app.logger.info('The message', category='my category') |
|
|
|
|
|
|
|
# This will produce something like this in app.log: |
|
|
|
# [TIMESTAMP2017-01-16 08:44:48.944] [INFO] [my category] The message |
|
|
|
# [2017-01-16 08:44:48.944] [INFO] [my category] The message |
|
|
|
|
|
|
|
formatter = logging.Formatter('[%(blueprint)s] %(message)s') |
|
|
|
handler = logging.FileHandler('other.log', mode='a') |
|
|
|
handler.setFormatter(formatter) |
|
|
|
handler.setLevel(logging.INFO) |
|
|
|
|
|
|
|
app.logger.addHandler(handler) |
|
|
|
|
|
|
|
@app.route('/1/') |
|
|
|
def route_1(): |
|
|
|
# This will produce this log message: |
|
|
|
# [<APP>] Message |
|
|
|
current_app.logger.info('Message') |
|
|
|
|
|
|
|
return '' |
|
|
|
|
|
|
|
@bp.route('/2') |
|
|
|
def route_2(): |
|
|
|
# This will produce this log message: |
|
|
|
# [my blueprint] Message |
|
|
|
current_app.logger.info('Message') |
|
|
|
|
|
|
|
return '' |
|
|
|
|
|
|
|
# This will produce this log message: |
|
|
|
[<NOT REQUEST>] Message |
|
|
|
app.logger.info('Message') |
|
|
|
""" |
|
|
|
|
|
|
|
_RESERVED_KEYWORDS = ('exc_info', 'extra', 'stack_info') |
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs): |
|
|
|
if 'app' in kwargs: |
|
|
|
if kwargs['app'] is not None: |
|
|
@ -84,6 +122,9 @@ class FlaskExtraLogger(logging.getLoggerClass()): |
|
|
|
|
|
|
|
self.app = None |
|
|
|
self._valid_keywords = [] |
|
|
|
self._blueprint_var = None |
|
|
|
self._blueprint_app = None |
|
|
|
self._blueprint_norequest = None |
|
|
|
|
|
|
|
super(FlaskExtraLogger, self).__init__(*args, **kwargs) |
|
|
|
|
|
|
@ -91,6 +132,13 @@ class FlaskExtraLogger(logging.getLoggerClass()): |
|
|
|
if 'extra' not in kwargs: |
|
|
|
kwargs['extra'] = {} |
|
|
|
|
|
|
|
# If we were asked to log the blueprint name, add it to the extra list |
|
|
|
if self._blueprint_var is not None: |
|
|
|
if has_request_context(): |
|
|
|
kwargs['extra'][self._blueprint_var] = request.blueprint or self._blueprint_app |
|
|
|
else: |
|
|
|
kwargs['extra'][self._blueprint_var] = self._blueprint_norequest |
|
|
|
|
|
|
|
for kw in self._valid_keywords: |
|
|
|
if kw in kwargs: |
|
|
|
kwargs['extra'][kw] = kwargs[kw] |
|
|
@ -100,6 +148,13 @@ class FlaskExtraLogger(logging.getLoggerClass()): |
|
|
|
|
|
|
|
super(FlaskExtraLogger, self)._log(*args, **kwargs) |
|
|
|
|
|
|
|
def _check_reserved_word(self, word): |
|
|
|
if word in self._RESERVED_KEYWORDS: |
|
|
|
raise ValueError( |
|
|
|
'"{keyword}" cannot be used as an extra keyword, as it is ' |
|
|
|
'reserved for internal use.' |
|
|
|
.format(keyword=word)) |
|
|
|
|
|
|
|
def init_app(self, app): |
|
|
|
""" |
|
|
|
Intialize the logger class with a Flask application |
|
|
@ -118,14 +173,21 @@ class FlaskExtraLogger(logging.getLoggerClass()): |
|
|
|
""" |
|
|
|
|
|
|
|
app.config.setdefault('FLASK_LOGGING_EXTRAS_KEYWORDS', {}) |
|
|
|
app.config.setdefault('FLASK_LOGGING_EXTRAS_BLUEPRINT', |
|
|
|
(None, '<app>', '<not a request>')) |
|
|
|
|
|
|
|
for kw in app.config['FLASK_LOGGING_EXTRAS_KEYWORDS']: |
|
|
|
if kw in ['exc_info', 'extra', 'stack_info']: |
|
|
|
raise ValueError( |
|
|
|
'"{keyword}" member of FLASK_LOGGING_EXTRAS_KEYWORDS is ' |
|
|
|
'reserved for internal use.') |
|
|
|
self._check_reserved_word(kw) |
|
|
|
|
|
|
|
self._check_reserved_word( |
|
|
|
app.config['FLASK_LOGGING_EXTRAS_BLUEPRINT'][0]) |
|
|
|
|
|
|
|
self._valid_keywords = app.config['FLASK_LOGGING_EXTRAS_KEYWORDS'] |
|
|
|
( |
|
|
|
self._blueprint_var, |
|
|
|
self._blueprint_app, |
|
|
|
self._blueprint_norequest, |
|
|
|
) = app.config['FLASK_LOGGING_EXTRAS_BLUEPRINT'] |
|
|
|
|
|
|
|
|
|
|
|
def register_logger_class(cls=FlaskExtraLogger): |
|
|
|