Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flask log entries duplicated when using Plotly dashboards

I'm seeing unexpected behavior when introducing Plotly dashboards into my Flask application. Each Plotly dashboard causes Flask log entries to be duplicated.

For example, if I attach two Plotly dashboards to my Flask application, log entries (e.g. current_app.logger.info('hi')) will appear three times in my logs. If I remove the Plotly dashboards, the log entry appears once, which is the expected behavior.

I've tried removing existing handlers in my logging config code via app.logger.handlers.clear() and by setting dictConfig's disable_existing_loggers to True, both of which result in nothing being logged. I've also tried using the singleton approach to configuring the logger (again, using dictConfig) and I still see the log entries repeated multiple times.

How can I prevent Plotly dashboards from causing duplicate log entries?

UPDATE:

Here's a simplified version of how Dash apps are being initialized:

def register_dashapp(app):
    from dashboards.dash_files.my_dash import (
        define_layout,
        define_callbacks,
    )
    my_dashapp = dash.Dash(__name__,
                         server=app,
                         url_base_pathname='/my_dash/',
                         assets_folder="../dashboards/foo/bar/assets",
                         )
    with app.app_context():
        my_dashapp.title = "Test"
        define_layout(my_dashapp)
        define_callbacks(my_dashapp)

def create_app():
    app = Flask(__name__, instance_relative_config=False)
    app.config.from_object('config.Config')

    with app.app_context():
        register_extensions(app)
        app.register_blueprint(main)
        register_dash_app(app)
        return app
like image 910
pdoherty926 Avatar asked Nov 24 '25 11:11

pdoherty926


2 Answers

I was having a log duplication issue and solved it using the same HasHandlers logic, however I call logs in a slight different way. This requires the python arrow library, which I find superior to datetime in most use cases.

I define the site_logger in my main app.py or _init_.py file.

# define logger
def site_logger(log_name):
    now = arrow.now('US/Eastern').format('YYYY_MM_DD')
    handler = logging.FileHandler('logs/' + log_name + '_' + now + '.log')
    formatter = logging.Formatter('%(asctime)s %(levelname)s %(name)s: %(message)s')
    handler.setFormatter(formatter)
    logger = logging.getLogger(log_name)
    logger.setLevel("DEBUG")
    if logger.hasHandlers():
        logger.handlers.clear()
    logger.addHandler(handler)
    logger.propagate = False
    return logger

I then call the logger in the following way in any views.py file or function, you can also pass the logger into a function you call in a views.py, keeping logs results of a function in the correct page file it was called from.

from app import site_logger
logger = site_logger('page_name')

I can then log events in the usual way. Two examples are below, and using f strings in logger is a great way to easily pass vars into log data.

logger.info(f'{user} logged in successfully')
logger.warning(f'{user} password failure!')

This will provide uniformly named log handlers and log files you can more easily trace back to the page or function call made. The date formatted files should auto rotate when the arrow.now('timezome') value rotates to the next day.

like image 112
Splix76 Avatar answered Nov 27 '25 00:11

Splix76


I was able to work around this by removing the logging handler added by the Dash library.

my_dash = dash.Dash(__name__,
    server=app,
    url_base_pathname='/my_dash/',
    assets_folder="../dashboards/foo/bar/assets"
)

if (my_dash.logger.hasHandlers()):
    my_dash.logger.handlers.clear()

There doesn't appear to be any downside to doing this, but it is possible I'm overlooking something and I'd be interested to see if anyone else has a better approach. I'll hold off on accepting my own answer for a few more days.

On a related note, I'd think this would be configurable via the Dash constructor. I'd also be curious to know if anyone has thoughts about that. I may open a ticket with the project to see what they think about the possibility.

like image 28
pdoherty926 Avatar answered Nov 26 '25 23:11

pdoherty926



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!