lordlabakdas
lordlabakdas

Reputation: 1193

Flask logging across multiple modules

I have the following directory structure in Flask and I am trying to add logging to this system. My APIs are defined in main.py and backend.py provides some backend logic to the APIs.

├── README.md
├── __init__.py
├── main.py
├── module
│   ├── __init__.py
│   └── backend.py

My APIs are defined in main.py and logging related components in the file are as below:

from logging.config import dictConfig
import logging
from module import backend

log_level = "DEBUG"
LOGFILENAME = "flask.log"
dictConfig({
    'version': 1,
    'formatters': {'default': {
        'format': '[%(asctime)s] {%(pathname)s:%(funcName)s:%(lineno)d} %(levelname)s - %(message)s',
    }},
    'handlers': {'default': {
                'level': 'DEBUG',
                'formatter': 'default',
                'class': 'logging.handlers.RotatingFileHandler',
                'filename': LOGFILENAME,
                'maxBytes': 5000000,
                'backupCount': 10
            }},
    'root': {
        'level': log_level,
        'handlers': ['default']
    }
})

app = Flask(__name__)
logger = logging.getLogger(__name__)

@app.route('/')
def hello():
    logger.debug("DEBUG: Inside the home function")
    logger.info("INFO: Inside the home function")
    backend.test()
    return "Welcome"

Logging works as expected in main.py. Depending on the log_level, logs get written to LOGFILENAME.

Problems occur when I try to enable logging via the below steps inside of backend.py.

import logging
logger = logging.getLogger(__name__)

def test():
    logger.info("info test")
    logger.debug("debug test")

I do not see any logs from backend.py getting written to flask.log. I sense I am missing something but do not understand what. Any help appreciated.

Upvotes: 2

Views: 5069

Answers (2)

lordlabakdas
lordlabakdas

Reputation: 1193

I think I found the fix to my problem. Given below is my updated main.py and backend.py and is comfirmed working

main.py

import logging
from module import backend

log_level = "DEBUG"
LOGFILENAME = "flask.log"
class LoggerConfig:
    dictConfig = {
        'version': 1,
        'formatters': {'default': {
            'format': '[%(asctime)s] {%(pathname)s:%(funcName)s:%(lineno)d} %(levelname)s - %(message)s',
        }},
        'handlers': {'default': {
                    'level': 'DEBUG',
                    'formatter': 'default',
                    'class': 'logging.handlers.RotatingFileHandler',
                    'filename': LOGFILENAME,
                    'maxBytes': 5000000,
                    'backupCount': 10
                }},
        'root': {
            'level': log_level,
            'handlers': ['default']
        },
    }

app = Flask(__name__)

logging.config.dictConfig(LoggerConfig.dictConfig)

@app.route('/')
def hello():
    app.logger.debug("DEBUG: Inside the home function")
    app.logger.info("INFO: Inside the home function")
    backend.test()
    return "Welcome"

backend.py

import logging
logger = logging.getLogger()

def test():
    logger.info("info test")
    logger.debug("debug test")

If you notice, the second line of backend.py is basically logging.getLogger() without a name. This did the trick on the backend side.

Also, app.logger on the API side (main.py side) helped.

Overall, I was able to get both the main.py and backend.py to write to the same file given in dictConfig.

Upvotes: 2

M.Rau
M.Rau

Reputation: 1044

Your library does have a different logger name. For both you need to have the same logger name. See for example the logging cookbook.

The best practice is that you create your own logging hierarchy, for example "myapp" in main.py (logger = logging.getLogger("myapp")) and attach to this in backend.py with for example myapp.backend (logger = logging.getLogger(".".join("myapp", __name__)).

Find below a slightly modified version of your main.py and backend.py. I have removed the Flask part. I guess this does not affect the logging mechanics.

main.py

import logging.config

from module import backend

dict_config = {
    'version': 1,
    'formatters': {
        'default': {
            'format': '[%(asctime)s] {%(pathname)s:%(funcName)s:%(lineno)d} %(levelname)s - %(message)s',
        }
    },
    'handlers': {'default': {
        'level': 'DEBUG',
        'formatter': 'default',
        'class': 'logging.handlers.RotatingFileHandler',
        'filename': "test.log",
        'maxBytes': 5000000,
        'backupCount': 10
    },
        'console': {
            'class': 'logging.StreamHandler',
            'level': 'DEBUG',
            'formatter': 'default',
        },
    },
    'loggers': {
        'myapp': {
            'handlers': ["default"],
            'level': 'DEBUG',
        },
    },
    'root': {
        'handlers': ["console"],
        'level': 'DEBUG',
    },
}

print(__name__)
logger = logging.getLogger("myapp")
logging.config.dictConfig(dict_config)


def hello():
    logger.debug("DEBUG: Inside the home function")
    logger.info("INFO: Inside the home function")
    backend.test()
    return "Welcome"


print(hello())

backend.py

import logging
logger = logging.getLogger("myapp")

def test():
    logger.info("info test")
    logger.debug("debug test")

Upvotes: 4

Related Questions