From de81518b3fb5650975d0915beac03575603baad5 Mon Sep 17 00:00:00 2001 From: Michael Loewenstein Date: Mon, 26 Oct 2015 08:11:08 +0200 Subject: [PATCH] feature/9-historical --- redshift_console/app.py | 5 ++ redshift_console/queries.yaml | 10 +++ redshift_console/redshift.py | 9 +++ redshift_console/static/app/scripts/app.js | 1 + .../static/app/scripts/components/queries.js | 62 ++++++++++++++++++- 5 files changed, 85 insertions(+), 2 deletions(-) diff --git a/redshift_console/app.py b/redshift_console/app.py index 03940ef..a013156 100644 --- a/redshift_console/app.py +++ b/redshift_console/app.py @@ -47,6 +47,10 @@ def get(self): results = tables.get_schemas() self.write_json({'results': results}) +class QueriesHistoryHandler(BaseHandler): + def get(self): + self.write_json({'queries_history': queries.queries_history.values(), + 'updated_at': queries.queries_history_updated_at}) class QueriesInflightHandler(BaseHandler): def get(self): @@ -94,6 +98,7 @@ def create_app(debug): return tornado.web.Application([(r"/", MainHandler), (r"/api/queries/inflight$", QueriesInflightHandler), + (r"/api/queries/history$", QueriesHistoryHandler), (r"/api/queries/queue$", QueriesQueueHandler), (r"/api/queries/cancel/(.*)$", QueriesCancelHandler), (r"/api/schemas$", SchemasHandler), diff --git a/redshift_console/queries.yaml b/redshift_console/queries.yaml index 0eca584..aed5f78 100644 --- a/redshift_console/queries.yaml +++ b/redshift_console/queries.yaml @@ -8,6 +8,16 @@ inflight_queries: JOIN pg_user ON svv_query_inflight.userid = pg_user.usesysid ORDER BY id, SEQUENCE; +queries_history: + SELECT query AS id, + database as db, + querytxt as query, + endtime AS endtime + FROM stl_query + WHERE querytxt NOT LIKE '%stl_query%' + AND querytxt NOT LIKE '%stl_alert_event_log%' + AND querytxt NOT LIKE '%svv_query_inflight%' + ORDER BY starttime DESC LIMIT 20; queries_queue: SELECT position, start_time as timestamp, diff --git a/redshift_console/redshift.py b/redshift_console/redshift.py index b49169a..7dc66b8 100644 --- a/redshift_console/redshift.py +++ b/redshift_console/redshift.py @@ -133,6 +133,8 @@ def __init__(self, session, refresh_interval): self.queries_queue = [] self.queries_queue_updated_at = None self.alerts_updated_at = None + self.queries_history = {} + self.queries_history_updated_at = None def _set_cancellation_in_progres(self, pid): for q in chain(self.inflight_queries.values(), self.queries_queue): @@ -168,6 +170,7 @@ def refresh(self): yield self._fetch_inflight_queries() yield self._fetch_query_alerts() yield self._fetch_queries_queue() + yield self._fetch_queries_history() @coroutine def _fetch_inflight_queries(self): @@ -184,6 +187,12 @@ def _fetch_inflight_queries(self): self.inflight_queries_updated_at = datetime.datetime.utcnow() + @coroutine + def _fetch_queries_history(self): + queries_history = yield self.execute_query(sql_queries['queries_history']) + self.queries_history = {q['id']: q for q in _concat_query_text(queries_history)} + self.queries_history_updated_at = datetime.datetime.utcnow() + @coroutine def _fetch_query_alerts(self): if not self.inflight_queries: diff --git a/redshift_console/static/app/scripts/app.js b/redshift_console/static/app/scripts/app.js index c683f45..a237530 100644 --- a/redshift_console/static/app/scripts/app.js +++ b/redshift_console/static/app/scripts/app.js @@ -106,6 +106,7 @@ var routes = ( + diff --git a/redshift_console/static/app/scripts/components/queries.js b/redshift_console/static/app/scripts/components/queries.js index 8178d73..bb718d1 100644 --- a/redshift_console/static/app/scripts/components/queries.js +++ b/redshift_console/static/app/scripts/components/queries.js @@ -15,6 +15,10 @@ var QueriesPage = React.createClass({ queriesQueue: { queries: [], updatedAt: null + }, + queriesHistory: { + queries: [], + updatedAt: null } }; }, @@ -30,6 +34,15 @@ var QueriesPage = React.createClass({ } }); + fetch('/api/queries/history').then(function(response) { + return response.json(); + }).then(function(json) { + if (component.isMounted()) { + component.setState({queriesHistory: { queries: _.sortBy(json.queries_history, 'endtime'), updatedAt: json.updated_at}}); + setTimeout(component.refresh, 100000); + } + }); + fetch('/api/queries/queue').then(function(response) { return response.json(); }).then(function(json) { @@ -47,6 +60,10 @@ var QueriesPage = React.createClass({ name: In Flight {this.state.inflightQueries.queries.length}, route: 'inflight' }, + { + name: Queries History {this.state.queriesHistory.queries.length}, + route: 'queries_history' + }, { name: Queries Queue {this.state.queriesQueue.queries.length}, route: 'queries_queue' @@ -56,7 +73,7 @@ var QueriesPage = React.createClass({
- +
); @@ -119,6 +136,30 @@ var QueriesQueue = React.createClass({ } }) +var QueriesHistory = React.createClass({ + render: function() { + var createItem = function(query) { + return ; + }; + return ( +
+
Updated:
+ + + + + + + + + + {this.props.queriesHistory.queries.map(createItem)} + +
IDDBQuery
+
+ ); + } +}) var QueryExecutionTime = React.createClass({ componentWillMount: function() { @@ -222,8 +263,25 @@ var Query = React.createClass({ } }); +var QueryHistory = React.createClass({ + getInitialState: function() { + return {className: 'query collapsed'}; + }, + render: function() { + return ( + + {this.props.query.id} + {this.props.query.db} + {this.props.query.query} + + ); + } +}); + + module.exports = { 'QueriesPage': QueriesPage, 'InflightQueries': InflightQueries, - 'QueriesQueue': QueriesQueue + 'QueriesQueue': QueriesQueue, + 'QueriesHistory': QueriesHistory }