flask-dashboard / Flask-MonitoringDashboard

Automatically monitor the evolving performance of Flask/Python web services.
http://flask-monitoringdashboard.readthedocs.io/
MIT License
781 stars 160 forks source link

DispatcherMiddleware support #339

Open alexander-arce opened 4 years ago

alexander-arce commented 4 years ago

Hi, When use FMD with two apps through DispatcherMiddleware, both apps using own configuration even forcing config parameters

To Reproduce Configure two apps and run through DispatcherMiddleware

  1. Run
  2. Check configuration
from werkzeug.middleware.dispatcher import DispatcherMiddleware
from werkzeug.serving import run_simple

from src.apps.api.main import factory as api_factory
from src.apps.admin.main import factory as admin_factory
api = api_factory()
admin = admin_factory()

from src import BASE_DIR

with admin.app_context():
    import flask_monitoringdashboard as admin_telemetry
    admin_telemetry.config.init_from(file=os.path.join(
    BASE_DIR, 'src', 'admin.monitoring.cfg'))
    admin_telemetry.config.link = 'telemetry'
    admin_telemetry.config.table_prefix = 'admin'
    admin_telemetry.config.version = 'Admin V1.0'
    admin_telemetry.bind(admin)

with api.app_context():
    import flask_monitoringdashboard as api_telemetry
    api_telemetry.config.init_from(file=os.path.join(
    BASE_DIR, 'src', 'api.monitoring.cfg'))
    api_telemetry.config.link = 'telemetry'
    api_telemetry.config.table_prefix = 'api'
    api_telemetry.config.version = 'App V1.1'
    api_telemetry.bind(api)

# merge
application = DispatcherMiddleware(
    api,
    { '/api/v1/admin': admin }
)

if __name__ == '__main__':
    run_simple(
        hostname='0.0.0.0',
        port=os.environ.get('PORT', 8081),
        application=application,
        use_reloader=True,
        use_debugger=True,
        use_evalex=True)

Expected behavior Two applications that run with their own FMD configuration in different urls

Screenshots

Api app

api

Admin app

admin

Desktop (please complete the following information):

alexander-arce commented 4 years ago

Hi, anyone?

mircealungu commented 4 years ago

Hi @Aletz-Arce,

Currently FMD does not support monitoring multiple Flask applications in the same process.

Thus, it won't work with DispatcherMiddleware.

If you want to have the endpoints of two applications to be monitored you can refactor them in blueprints as you can see in the following discussion:

https://stackoverflow.com/questions/15583671/flask-how-to-architect-the-project-with-multiple-apps

Then install the blueprints in one app and deploy the FMD on that app.

alexander-arce commented 4 years ago

@mircealungu First, thanks for your fantastic application is really awesome. Second, thanks for your reply i will work on pull-request for multi-app support

Best regards :)

bogdanp05 commented 4 years ago

Hi @mircealungu and @Aletz-Arce! I implemented a small proof of concept in this commit The idea is to use the factory pattern for FMD. Run the main.py file and you should see something like:

Scheduler started
Map([<Rule '/dashboard/logout' (GET, OPTIONS, HEAD) -> dashboard.logout>,
 <Rule '/dashboard/login' (GET, POST, OPTIONS, HEAD) -> dashboard.login>,
 <Rule '/dashboard/static/<filename>' (GET, OPTIONS, HEAD) -> dashboard.static>,
 <Rule '/dashboard/<path>' (GET, OPTIONS, HEAD) -> dashboard.index>,
 <Rule '/dashboard/' (GET, OPTIONS, HEAD) -> dashboard.index>,
 <Rule '/static/<filename>' (GET, OPTIONS, HEAD) -> static>])
Scheduler is already running
Map([<Rule '/dashboard_2/logout' (GET, OPTIONS, HEAD) -> dashboard_2.logout>,
 <Rule '/dashboard_2/login' (GET, POST, OPTIONS, HEAD) -> dashboard_2.login>,
 <Rule '/endpoint6' (GET, OPTIONS, HEAD) -> endpoint5>,
 <Rule '/app_2' (GET, OPTIONS, HEAD) -> to_dashboard_2>,
 <Rule '/dashboard_2/static/<filename>' (GET, OPTIONS, HEAD) -> dashboard_2.static>,
 <Rule '/dashboard_2/<path>' (GET, OPTIONS, HEAD) -> dashboard_2.index>,
 <Rule '/dashboard_2/' (GET, OPTIONS, HEAD) -> dashboard_2.index>,
 <Rule '/static/<filename>' (GET, OPTIONS, HEAD) -> static>])

So 2 different Flask apps with 2 different FMDs. If we agree on this approach, @Aletz-Arce can just take over from that commit.

alexander-arce commented 4 years ago

Hi @bogdanp05 cool, looks is the right approach instead singlenton current behaviour. Maybe taking advantage with this refactor, blueprint name will be configurable avoid name collision as reported in #330, #340 just here --> gef_blueprint. That add additional work to implement dynamic blueprint name in templates.

bogdanp05 commented 4 years ago

I already solved #330 with #340 :) So the templates already use the dynamic blueprint name. But yes, that's the reason I added the name argument to the get_blueprint() function.

Notice also this line. That's because currently, to use the FMD you only need to call the bind function:

dashboard.bind(app)

This should still be possible and only for advanced use cases like yours, get the blueprint:

blueprint = dashboard.get_blueprint("intuitive_name")
dashboard.bind(app, blueprint)
alexander-arce commented 4 years ago

@bogdanp05 Your code rocks! I try on my current project and get feedback