How to use Flask's Logger in Multi-Page App?

Dear Community Members -

Per
1. What is the advantage of using Flasks app.logger?
2. How to share logger instance among Flask app and other classes
3. Logging - debug messages suppressed in callbacks?
I found using Flask’s app.logger recommendable.

Following the guidance Multi-Page Apps and URL Support to create a multi-page app, however,
I do not see a reasonable way to access the app object in callbacks defined on individual pages stored in the folder pages/.

I have tried to import it from the parent folder with

from ..app import app

but this resulted in the

ValueError: attempted relative import beyond top-level package

If @chriddyp , @nedned , or anyone else here uses Flask’s logger in multi-page apps I would be extremely grateful for a note on an approach to making this work that you could recommend?

Thanks in advance!
Thomas

It looks like you’re working in a Pacakge… might be worth checking the version of Dash you’re running. There was a bug that meant relative package imports from inside modules in your pages folder would break: [BUG] Dash Pages does not support relative package imports within page modules · Issue #2263 · plotly/dash · GitHub. That bug was fixed in Dash 2.9.0.

Another way to get access to the Flask server instance of your Dash app that means you don’t have to thread app imports all throughout your modules is Flask’s current_app: The Application Context — Flask Documentation (2.3.x). The only limitation is that you can only access flask.current_app from inside an application context, which, practically, I think amounts to making sure you only access it inside a callback.

Thank you so much for your feedback!

I have installed version: 2.7.0 of the dash package and use a Windows 10 box.

  1. I have no __init__.py in my app’s root folder, the folder pages/ should be the only package in this setup, rf. item 3.
  2. app.py has the contents
    import dash, dash_bootstrap_components
    import logging           # Do I still need this when using app.logger instead of creating my own logger?
    
    logging.config.fileConfig('logging.conf')
    # create logger
    logger = logging.getLogger('root')
    
    PORT_NUMBER=8052
    app = dash.Dash(         # How to use app.logger on the registered pages contained in package pages/?
             __name__,
             suppress_callback_exceptions=True,
             use_pages=True,
             external_stylesheets = [ dbc.themes.BOOTSTRAP, 'https://codepen.io/chriddyp/pen/bWLwgP.css' ]
    )
    navbar = dbc.NavbarSimple( dbc.DropdownMenu( [
            dbc.DropdownMenuItem(page["name"], href=page["path"])
                for page in dash.page_registry.values() if page["module"] != "pages.not_found_404"
        ], nav=True, label="More Pages" )
        brand="Multipage App", color="primary", dark=True, className="bg-dark text-center text-warning",
    )
    app.layout = dbc.Container( [navbar, dash.page_container], fluid=True )
    
    if __name__ == '__main__':
        app.logger.info('Starting ...')    # This is logged as expected but further log messages are missing!
        app.run_server(debug=True, port=PORT_NUMBER)
        app.logger.info('Finished')
    
  3. I collected the following contents of pages/__init__.py online but I’m no longer exactly sure why:
    from dash import html as _html
    
    def page_not_found(pathname):
        return _html.P("No page '{}'".format(pathname))
    
  4. It was in pages/some page.py where I had tried adding
    from ..app import app
    
    before
    # **Creating a new logger like this seems to interfere with app.logger so I wanted to use app.logger on this page, too**
    logger = logging.getLogger(__name__)
    #
    dash.register_page(__name__, path="/"+Path(__file__).stem)
    def layout(**kwargs):
        dash_components = [ dbc.Row(...) ]
        dash_components += dcc.Markdown(...)
        return html.Div( dash_components )
    
    @callback(
        Output('label', 'children'),
        Input('input-text', 'value')
    )
    def handle(text : str):
        logger.info(f'sending {text=} to label')        # How to use app.logger instead of logger here?
        return html.Div(text)
    
    as mentioned above.

In the end I found out I had set up everything in the right way but forgotten while pursuing other projects that my app is already started automatically since I configured a batch file starting it for
NSSM - the Non-Sucking Service Manager
Obviously, logging in a second instance started from CLI following the original routine necessarily interfered with the service whose log messages are shown as intended by the log file viewer of your choice.
I’m sorry for the confusion!

Although I’m ok now and would close this for my own purposes I’d just like to add that the question is not answered in the strict sense because the the code for each page - let’s say pages/any page.py - is still defining a separate logger in the line

logger = logging.getLogger(__name__)

which is the standard AFAIK. So I’m not following the recommendation to use Flask’s app.logger mentioning which I started my original question with. Whether this would make more sense or not the question how it could be done is still open.