From fd84fd89ce12388d4aa4c98bc3d0d1257d355168 Mon Sep 17 00:00:00 2001 From: Beto Dealmeida Date: Thu, 12 Apr 2018 21:48:17 -0700 Subject: [PATCH] RFC: add logger that logs into browser console (#4702) * Option for logging into browser console * Move import * Add lint req * Add docs, use Flask logger --- CONTRIBUTING.md | 13 +++++++++++ requirements-dev.txt | 1 + setup.py | 1 + superset/__init__.py | 4 +++- superset/cli.py | 49 +++++++++++++++++++++++++++++++++++------- superset/views/core.py | 6 ++++-- 6 files changed, 63 insertions(+), 11 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a47aefbc93..10d82d1142 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -200,6 +200,19 @@ Check the [OS dependencies](https://superset.incubator.apache.org/installation.h superset runserver -d +### Logging to the browser console + +When debugging your application, you can have the server logs sent directly to the browser console: + + superset runserver -d --console-log + +You can log anything to the browser console, including objects: + + from superset import app + app.logger.error('An exception occurred!') + app.logger.info(form_data) + + ## Setting up the node / npm javascript environment `superset/assets` contains all npm-managed, front end assets. diff --git a/requirements-dev.txt b/requirements-dev.txt index 3ca7ffbe54..7f9616395e 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -5,3 +5,4 @@ psycopg2==2.7.4 redis==2.10.6 statsd==3.2.2 tox==2.9.1 +console_log==0.2.10 diff --git a/setup.py b/setup.py index 43f0c4abaa..c24d6f2bc5 100644 --- a/setup.py +++ b/setup.py @@ -93,6 +93,7 @@ setup( ], extras_require={ 'cors': ['flask-cors>=2.0.0'], + 'console_log': ['console_log==0.2.10'], }, author='Maxime Beauchemin', author_email='maximebeauchemin@gmail.com', diff --git a/superset/__init__.py b/superset/__init__.py index 83154cabc5..929fcfe621 100644 --- a/superset/__init__.py +++ b/superset/__init__.py @@ -78,7 +78,9 @@ for bp in conf.get('BLUEPRINTS'): if conf.get('SILENCE_FAB'): logging.getLogger('flask_appbuilder').setLevel(logging.ERROR) -if not app.debug: +if app.debug: + app.logger.setLevel(logging.DEBUG) +else: # In production mode, add log handler to sys.stderr. app.logger.addHandler(logging.StreamHandler()) app.logger.setLevel(logging.INFO) diff --git a/superset/cli.py b/superset/cli.py index dc11e2cc69..a40f062968 100755 --- a/superset/cli.py +++ b/superset/cli.py @@ -14,6 +14,7 @@ from colorama import Fore, Style from flask_migrate import MigrateCommand from flask_script import Manager from pathlib2 import Path +import werkzeug.serving import yaml from superset import app, data, db, dict_import_export_util, security_manager, utils @@ -32,9 +33,43 @@ def init(): security_manager.sync_role_definitions() +def debug_run(app, port, use_reloader): + return app.run( + host='0.0.0.0', + port=int(port), + threaded=True, + debug=True, + use_reloader=use_reloader) + + +def console_log_run(app, port, use_reloader): + from console_log import ConsoleLog + from gevent import pywsgi + from geventwebsocket.handler import WebSocketHandler + + app.wsgi_app = ConsoleLog(app.wsgi_app, app.logger) + + def run(): + server = pywsgi.WSGIServer( + ('0.0.0.0', int(port)), + app, + handler_class=WebSocketHandler) + server.serve_forever() + + if use_reloader: + from gevent import monkey + monkey.patch_all() + run = werkzeug.serving.run_with_reloader(run) + + run() + + @manager.option( '-d', '--debug', action='store_true', help='Start the web server in debug mode') +@manager.option( + '--console-log', action='store_true', + help='Create logger that logs to the browser console (implies -d)') @manager.option( '-n', '--no-reload', action='store_false', dest='use_reloader', default=config.get('FLASK_USE_RELOAD'), @@ -57,9 +92,9 @@ def init(): help='Path to a UNIX socket as an alternative to address:port, e.g. ' '/var/run/superset.sock. ' 'Will override the address and port values. [DEPRECATED]') -def runserver(debug, use_reloader, address, port, timeout, workers, socket): +def runserver(debug, console_log, use_reloader, address, port, timeout, workers, socket): """Starts a Superset web server.""" - debug = debug or config.get('DEBUG') + debug = debug or config.get('DEBUG') or console_log if debug: print(Fore.BLUE + '-=' * 20) print( @@ -68,12 +103,10 @@ def runserver(debug, use_reloader, address, port, timeout, workers, socket): Fore.YELLOW + ' mode') print(Fore.BLUE + '-=' * 20) print(Style.RESET_ALL) - app.run( - host='0.0.0.0', - port=int(port), - threaded=True, - debug=True, - use_reloader=use_reloader) + if console_log: + console_log_run(app, port, use_reloader) + else: + debug_run(app, port, use_reloader) else: logging.info( "The Gunicorn 'superset runserver' command is deprecated. Please " diff --git a/superset/views/core.py b/superset/views/core.py index 6629dbd308..19885dcee3 100755 --- a/superset/views/core.py +++ b/superset/views/core.py @@ -746,8 +746,10 @@ class R(BaseSupersetView): obj = models.Url(url=url) db.session.add(obj) db.session.commit() - return('http://{request.headers[Host]}/{directory}?r={obj.id}'.format( - request=request, directory=directory, obj=obj)) + return Response( + 'http://{request.headers[Host]}/{directory}?r={obj.id}'.format( + request=request, directory=directory, obj=obj), + mimetype='text/plain') @expose('/msg/') def msg(self):