Merge flash log and gunicorn log

Posted by newbieaj on Tue, 01 Mar 2022 04:23:29 +0100

logging

The logging framework is mainly composed of four parts:

  • Loggers: interfaces that can be called directly by programs
  • Handlers: decide to assign log records to the correct destination
  • Filters: provides a more granular judgment of whether the log is output
  • Formatters: make the format layout of final record printing

Logging is introduced as a module. logging.debug uses the method of logging module. Logger is logging Generated by getlogger () is a log object, logger Debug calls the method of logger, the log object. In the following example, logging Debug and logger The effect of debug is exactly the same.

import logging
 
logging.debug('debug information')
 
logger = logging.getLogger()
 
logger.debug('debug information')

For the convenience of developers, the logging module provides a series of module methods, which can be used directly after the module is introduced. In this way, the developer does not need to concern the details of the log module and outputs the log like print.

When using the module method, logging actually creates a log object - root logger. Logging The call of debug is essentially a call to the logging method of root logger. Equivalent to that root logger will be used as the log processing object by default. The root logger object can be accessed through logging. Without parameters Getlogger () method.

  • Basic use
import logging
logging.basicConfig(level = logging.INFO,filename="path",filemode="a",format = '%(asctime)s %(message)s') #Global configuration
logging.info("")
logging.debuge("")
logging.warning("")
  • Advanced use
import logging
logger = logging.getLogger()  # Recorder
logger.setLevel(logging.INFO)

consoleHandler = logging.StreamHandler() # processor
consoleHandler.setLevel(logging.DEBUG)

fileHandler = logging.FileHandler("path") # processor

formatter = logging.Formatter('%(asctime)s %(message)s') # Output format

# Associate Handler with Formatter
consoleHandler.setFormatter(formatter)
fileHandler.setFormatter(formatter)

#Associate Handler with logger
logger.addHandler(consoleHandler)
logger.addHandler(fileHandler)

# Write log information using logger
logger.info("")
logger.debug("")

Flash log

Flash has its own logger, so you only need to use app Just call logger.

  • The flash log is displayed in the file.

    if __name__ == '__main__':
        fh = logging.FileHandler(filename='./log/flask_matting_head.log', encoding='utf-8')
        logging.basicConfig(level=logging.DEBUG,
                            format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                            datefmt='%a, %d, %b %Y %H:%M:%S',
                            handlers=[fh])
        app.debug = True
        app.run(host='0.0.0.0', port=7788, debug=True)
    
  • The flash log is displayed on the console

	if __name__ == '__main__':
        logger = logging.getLogger()
		logger.setLevel('DEBUG')
		BASIC_FORMAT = '%(asctimie)s:%(levelname)s:%(message)s'
		DATE_FORMAT = '%y-%m-%d %H:%M:%S'
		formatter = logging.Formatter(BASIC_FORMAT, DATE_FORMAT)
		chlr = logging.StreamHandler()
		chlr.setFormatter(formatter)
		logger.addHandler(chlr)
		logger.setLevel('DEBUG')
	    app.run(host='0.0.0.0', port=7788, debug=True)

gunicorn log

gunicorn can use logging Config for complete configuration.
Configuration of logs in gunicorn.

```python
# !/usr/bin/env python
# -*- coding: utf-8 -*-
#
# @Author: xxx
# @Date  : 1/17/22 9:09 AM
# @File  : config.py

# config.py
import os
import gevent.monkey
gevent.monkey.patch_all()
import multiprocessing

#debug = True
bind = '0.0.0.0:7788'
pidfile = 'log/gunicorn.pid'

logconfig_dict = {
    'version':1,
    'disable_existing_loggers': False,
    'loggers':{
        "gunicorn.error": {
            "level": "WARNING",# The level of logging can be changed. The same is true for the following
            "handlers": ["error_file"], # Corresponding to the following key
            "propagate": 1,
            "qualname": "gunicorn.error"
        },

        "gunicorn.access": {
            "level": "DEBUG",
            "handlers": ["access_file"],
            "propagate": 0,
            "qualname": "gunicorn.access"
        }
    },
    'handlers':{
        "error_file": {
            "class": "logging.handlers.RotatingFileHandler",
            "maxBytes": 1024*1024*1024,# The size of the log is 1 G
            "backupCount": 1,# How many copies to back up, after testing, at least write 1, otherwise you can't control the size
            "formatter": "generic",# Corresponding to the following key
            # 'mode': 'w+',
            "filename": "./log/gunicorn.error.log"# Log path
        },
        "access_file": {
            "class": "logging.handlers.RotatingFileHandler",
            "maxBytes": 1024*1024*1024,
            "backupCount": 1,
            "formatter": "generic",
            "filename": "./log/gunicorn.access.log",
        }
    },
    'formatters':{
        "generic": {
            "format": "'[%(process)d] [%(asctime)s] %(levelname)s [%(filename)s:%(lineno)s] %(message)s'", # Format of printing log
            "datefmt": "[%Y-%m-%d %H:%M:%S %z]",# Time display method
            "class": "logging.Formatter"
        },
        "access": {
            "format": "'[%(process)d] [%(asctime)s] %(levelname)s [%(filename)s:%(lineno)s] %(message)s'",
            "class": "logging.Formatter"
        }
    }
}

capture_output = True
#loglevel = 'warning'
loglevel = 'debug'


daemon = True #Background start
reload = True

#workers = multiprocessing.cpu_count()
workers = 1
worker_class = 'gevent'
x_forwarded_for_header = 'X-FORWARDED-FOR'

```

If you need to merge the logger of Flask and the log of Gunicorn, you need to add such a piece of code to Flask. That is, when Flask is not self started, it is started by Gunicorn, then Gunicorn is obtained Error's logger, which will app The handler of the logger is assigned Gunicorn error. handler. Add app Logger of logger The level is set to the same level as the Gunicorn configuration.

if __name__ != '__main__':
    gunicorn_logger = logging.getLogger('gunicorn.error')
    app.logger.handlers = gunicorn_logger.handlers
    app.logger.setLevel(gunicorn_logger.level)

reference material
Understanding and using of logging
Flag and Gunicorn's logger
log processing of gunicorn deployment flash
gunicorn log problem
Artifact logging, do you really understand?
Basic use of logging

Topics: Flask logging