2019年1月27日 星期日

[Flask] Logging


 Python   Flask    Logging



Introduction


We are going to apply logging to Flask app.
The loggers will include:
1.  Application-level logger
2.  Custom logger





Environment

Python 3.6.5
Flask 1.0.2
Flask-SocketIO 3.1.2
Socket.IO 2.2.0
Vue.js 2.5.21
Vue-Socket.io 3.0.4


Implement



Create logger and its handlers

Logger object

Loggers are never instantiated directly.
The proper way is get/create it by using module-level function: logging.getLogger(name).
Multiple calls to getLogger() with the same name will always return a reference to the same Logger object.

import logging
my_logger = logging.getLogger("myLoggerName")


File handler

logging_format = logging.Formatter('%(asctime)s - %(thread)s - %(levelname)s - %(module)s.%(funcName)s(%(filename)s, %(lineno)s) - %(message)s')
 logfiles_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "logs"))
 handler = logging.FileHandler('{0}\\mylog.log'.format(logfiles_path), encoding='UTF-8')
 handler.setLevel(logging.DEBUG) # Set handler's log level
 handler.setFormatter(logging_format) # Set format
 my_logger.addHandler(handler)

The above code created a logging.FileHandler object which was set log level and format.
Then we can add the handler to our logger.

Here are the log levels and their representative numeric value.
In the example, the handler will deal with the logs with levels whose numeric value are equals or higher than “DEBUG”.

Level
Numeric value
CRITICAL
50
ERROR
40
WARNING
30
INFO
20
DEBUG
10
NOTSET
0
(Reference: Logging Levels)


For logger, we can set the log level as well like following.
The logs with non-scoped levels will be ignored.

 my_ogger.setLevel(logging.INFO)


Start logging

my_logger.debug("[Debug]..")
my_logger.info("[INFO]...")
my_logger.warning("[WARNING]...")
my_logger.error("[ERROR]...")
my_logger.critical("[CRITICAL]...")


Result

The logs will be keeped in to logs/mylog.log




And the logs,

2019-01-27 12:13:08,750 - 13660 - DEBUG - main.<module>(main.py, 35) - [Debug]..
2019-01-27 12:13:08,750 - 13660 - INFO - main.<module>(main.py, 36) - [INFO]...
2019-01-27 12:13:08,750 - 13660 - WARNING - main.<module>(main.py, 37) - [WARNING]...
2019-01-27 12:13:08,751 - 13660 - ERROR - main.<module>(main.py, 38) - [ERROR]...
2019-01-27 12:13:08,751 - 13660 - CRITICAL - main.<module>(main.py, 39) - [CRITICAL]...



(Optional) Create a module to add handlers for logger

Since we can have multiple file handers to handle different levels, formatted logs.
Here is an sample code for writing a module for this,

logger_config.py

import sys
import os
import logging
from datetime import date

def init_logging(logger, min_logging_level):
     # Add DEBUG handler
     add_handler(logger, logging.DEBUG)
     # Add ERROR handler
     add_handler(logger, logging.ERROR)
     # Set level for this logger
     logger.setLevel(min_logging_level)

def add_handler(logger:logging.Logger, level):
     level_name = logging.getLevelName(level).lower()
     logging_format = logging.Formatter('[%(asctime)s][%(thread)s][%(levelname)s][%(module)s.%(funcName)s(%(filename)s, %(lineno)s)]%(message)s')
     logfiles_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "logs", str(date.today()))
     create_log_dir(logfiles_path)
     handler = logging.FileHandler('{0}\\mylog.{1}.log'.format(logfiles_path, level_name), encoding='UTF-8')
     handler.setLevel(level) # Set handler's log level
     handler.setFormatter(logging_format) # Set format
     logger.addHandler(handler)

def create_log_dir(directory):
     if not os.path.exists(directory):
         os.makedirs(directory)


So when I call the init_logging method, the application will stores the logs as:

logs/2019-01-27/mylog.bug.log
logs/2019-01-27/mylog.error.log


Flask application logger

Flask uses standard Python logging.
We can get the Flask application-level logger by app.logger as following,

from flask import Flask, render_template, request, jsonify
 from modules.logger_config import init_logging

app = Flask(__name__)
init_logging(app.logger, logging.DEBUG)


and logs like this,

app.logger.error("[ERROR]...")


Notice that the app.logger’s logs will also be shown on the console window.
So if you don’t want to show the Flask app.logger’s logs on console, you can disable it by setting the log levels to a number greater than 50 (CRITICAL) :

app.logger.setLevel(100)


Sample code





Reference






沒有留言:

張貼留言