Repository: ambari Updated Branches: refs/heads/trunk 2c362fd0f -> a51532ac3
AMBARI-19582. Hive View 2.0: Show query logs (pallavkul) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/a51532ac Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/a51532ac Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/a51532ac Branch: refs/heads/trunk Commit: a51532ac3c713906b956471bc54fd3d90df5ca7e Parents: 2c362fd Author: pallavkul <pallav....@gmail.com> Authored: Fri Jan 20 15:49:24 2017 +0530 Committer: pallavkul <pallav....@gmail.com> Committed: Fri Jan 20 15:51:25 2017 +0530 ---------------------------------------------------------------------- .../src/main/resources/ui/app/adapters/query.js | 6 + .../ui/app/components/query-result-log.js | 28 ++++ .../main/resources/ui/app/models/worksheet.js | 5 +- .../resources/ui/app/routes/queries/query.js | 150 +++++++++++++++---- .../src/main/resources/ui/app/services/jobs.js | 17 ++- .../src/main/resources/ui/app/services/query.js | 14 +- .../templates/components/query-result-log.hbs | 23 +++ .../ui/app/templates/queries/query.hbs | 58 +++++-- 8 files changed, 245 insertions(+), 56 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/a51532ac/contrib/views/hive20/src/main/resources/ui/app/adapters/query.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/app/adapters/query.js b/contrib/views/hive20/src/main/resources/ui/app/adapters/query.js index a666b09..ccda9d4 100644 --- a/contrib/views/hive20/src/main/resources/ui/app/adapters/query.js +++ b/contrib/views/hive20/src/main/resources/ui/app/adapters/query.js @@ -39,6 +39,12 @@ export default ApplicationAdapter.extend({ } return this.ajax(url, 'GET') + }, + + retrieveQueryLog(logFile){ + let url = ''; + url = this.buildURL().replace('/jobs','') + '/files' + logFile; + return this.ajax(url, 'GET') } }); http://git-wip-us.apache.org/repos/asf/ambari/blob/a51532ac/contrib/views/hive20/src/main/resources/ui/app/components/query-result-log.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/app/components/query-result-log.js b/contrib/views/hive20/src/main/resources/ui/app/components/query-result-log.js new file mode 100644 index 0000000..9f8fbe1 --- /dev/null +++ b/contrib/views/hive20/src/main/resources/ui/app/components/query-result-log.js @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Ember from 'ember'; + +export default Ember.Component.extend({ + logResults:'', + + selectedDatabase: Ember.computed('logResults', function() { + return this.get('logResults'); + }), + +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/a51532ac/contrib/views/hive20/src/main/resources/ui/app/models/worksheet.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/app/models/worksheet.js b/contrib/views/hive20/src/main/resources/ui/app/models/worksheet.js index 59395e6..23f16b0 100644 --- a/contrib/views/hive20/src/main/resources/ui/app/models/worksheet.js +++ b/contrib/views/hive20/src/main/resources/ui/app/models/worksheet.js @@ -33,5 +33,8 @@ export default DS.Model.extend({ hidePreviousButton: DS.attr('boolean', { defaultValue: true}), selectedTablesModels: DS.attr(), selectedMultiDb: DS.attr(), - queryFile: DS.attr('string', {defaultValue: ""}) + queryFile: DS.attr('string', {defaultValue: ""}), + logFile: DS.attr('string', {defaultValue: ""}), + logResults: DS.attr('string', {defaultValue: ""}) + }); http://git-wip-us.apache.org/repos/asf/ambari/blob/a51532ac/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query.js b/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query.js index 606b71a..2ecf967 100644 --- a/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query.js +++ b/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query.js @@ -81,10 +81,17 @@ export default Ember.Route.extend({ controller.set('queryResult', model.get('queryResult')); controller.set('currentJobId', null); + controller.set('isJobSuccess', false); + controller.set('isExportResultSuccessMessege', false); controller.set('isExportResultFailureMessege', false); controller.set('showSaveHdfsModal', false); + controller.set('logResults', model.get('logResults') || ''); + controller.set('showQueryEditorLog', true); + controller.set('showQueryEditorResult', !controller.get('showQueryEditorLog')); + + }, @@ -160,20 +167,66 @@ export default Ember.Route.extend({ "globalSettings":""}; this.get('query').createJob(payload).then(function(data) { - // applying a timeout otherwise it goes for status code 409, although that condition is also handled in the code. - setTimeout(function(){ - self.get('controller.model').set('currentJobData', data); - self.get('controller.model').set('queryFile', data.job.queryFile); - self.get('controller').set('currentJobId', data.job.id); + self.get('controller.model').set('currentJobData', data); + self.get('controller.model').set('queryFile', data.job.queryFile); + self.get('controller.model').set('logFile', data.job.logFile); + self.get('controller').set('currentJobId', data.job.id); + + self.get('jobs').waitForJobToComplete(data.job.id, 5 * 1000) + .then((status) => { + Ember.run.later(() => { + self.get('controller').set('isJobSuccess', true); + self.send('getJob', data); + + //Last log + self.send('fetchLogs'); + + //Open result tab and hide log tab + self.send('showQueryEditorResult'); + }, 2 * 1000); + }, (error) => { + Ember.run.later(() => { + // TODO: handle error + }, 2 * 1000); + }); + + self.send('getLogsTillJobSuccess', data.job.id); - self.send('getJob', data); - }, 2000); }, function(reason) { console.log(reason); }); }, + getLogsTillJobSuccess(jobId){ + let self = this; + this.get('jobs').waitForJobStatus(jobId) + .then((status) => { + console.log('status', status); + if(status !== "succeeded"){ + self.send('fetchLogs'); + Ember.run.later(() => { + self.send('getLogsTillJobSuccess',jobId ) + }, 5 * 1000); + } else { + self.send('fetchLogs'); + } + }, (error) => { + console.log('error',error); + }); + }, + + fetchLogs(){ + let self = this; + + let logFile = this.get('controller.model').get('logFile'); + this.get('query').retrieveQueryLog(logFile).then(function(data) { + self.get('controller.model').set('logResults', data.file.fileContent); + }, function(error){ + console.log('error', error); + }); + }, + getJob(data){ var self = this; @@ -206,6 +259,16 @@ export default Ember.Route.extend({ console.log('reason' , reason); if( reason.errors[0].status == 409 ){ setTimeout(function(){ + + //Put the code here for changing the log content. + let logFile = self.get('controller.model').get('logFile'); + self.get('query').retrieveQueryLog(logFile).then(function(data) { + self.get('controller.model').set('logResults', data.file.fileContent); + }, function(error){ + console.log('error', error); + }); + + self.send('getJob',data); }, 2000); } @@ -255,12 +318,12 @@ export default Ember.Route.extend({ } }); } else { //Pages from cache object - this.get('controller.model').set('currentPage', currentPage+1); - this.get('controller.model').set('previousPage', previousPage + 1 ); - this.get('controller.model').set('nextPage', nextPage + 1); - this.get('controller.model').set('hidePreviousButton', false); - this.get('controller').set('queryResult', this.get('controller.model').get("jobData")[this.get('controller.model').get('currentPage')-1] ); - this.get('controller.model').set('queryResult', this.get('controller.model').get("jobData")[this.get('controller.model').get('currentPage')-1] ); + this.get('controller.model').set('currentPage', currentPage+1); + this.get('controller.model').set('previousPage', previousPage + 1 ); + this.get('controller.model').set('nextPage', nextPage + 1); + this.get('controller.model').set('hidePreviousButton', false); + this.get('controller').set('queryResult', this.get('controller.model').get("jobData")[this.get('controller.model').get('currentPage')-1] ); + this.get('controller.model').set('queryResult', this.get('controller.model').get("jobData")[this.get('controller.model').get('currentPage')-1] ); } }, @@ -303,7 +366,6 @@ export default Ember.Route.extend({ } }, - openWorksheetModal(){ this.get('controller').set('showWorksheetModal', true); }, @@ -316,12 +378,14 @@ export default Ember.Route.extend({ let selectedDb = this.get('controller.model').get('selectedDb'); let owner = this.get('controller.model').get('owner'); let queryFile = this.get('controller.model').get('queryFile'); + let logFile = this.get('controller.model').get('logFile'); let payload = {"title" : newTitle, - "dataBase": selectedDb, - "owner" : owner, - "shortQuery" : (currentQuery.length > 0) ? currentQuery : ";", - "queryFile" : queryFile }; + "dataBase": selectedDb, + "owner" : owner, + "shortQuery" : (currentQuery.length > 0) ? currentQuery : ";", + "queryFile" : queryFile, + "logFile" : logFile}; this.get('savedQueries').saveQuery(payload) .then((data) => { @@ -351,25 +415,25 @@ export default Ember.Route.extend({ console.log('saveToHDFS query route with path == ', path); this.get('query').saveToHDFS(jobId, path) - .then((data) => { - console.log('successfully saveToHDFS', data); - this.get('controller').set('isExportResultSuccessMessege', true); - this.get('controller').set('isExportResultFailureMessege', false); + .then((data) => { + console.log('successfully saveToHDFS', data); + this.get('controller').set('isExportResultSuccessMessege', true); + this.get('controller').set('isExportResultFailureMessege', false); - Ember.run.later(() => { - this.get('controller').set('showSaveHdfsModal', false); - }, 2 * 1000); + Ember.run.later(() => { + this.get('controller').set('showSaveHdfsModal', false); + }, 2 * 1000); - }, (error) => { - console.log("Error encountered", error); - this.get('controller').set('isExportResultFailureMessege', true); - this.get('controller').set('isExportResultSuccessMessege', false); + }, (error) => { + console.log("Error encountered", error); + this.get('controller').set('isExportResultFailureMessege', true); + this.get('controller').set('isExportResultSuccessMessege', false); - Ember.run.later(() => { - this.get('controller').set('showSaveHdfsModal', false); - }, 2 * 1000); + Ember.run.later(() => { + this.get('controller').set('showSaveHdfsModal', false); + }, 2 * 1000); - }); + }); }, downloadAsCsv(jobId, path){ @@ -382,6 +446,26 @@ export default Ember.Route.extend({ this.get('controller').set('showDownloadCsvModal', false); window.open(downloadAsCsvUrl); + }, + + showQueryEditorLog(){ + this.get('controller').set('showQueryEditorLog', true); + this.get('controller').set('showQueryEditorResult', false); + + $('.log-list-anchor').addClass('active'); + $('.log-list').addClass('active'); + $('.editor-result-list-anchor').removeClass('active'); + $('.editor-result-list').removeClass('active'); + }, + + showQueryEditorResult(){ + this.get('controller').set('showQueryEditorLog', false); + this.get('controller').set('showQueryEditorResult', true); + + $('.log-list-anchor').removeClass('active'); + $('.log-list').removeClass('active'); + $('.editor-result-list-anchor').addClass('active'); + $('.editor-result-list').addClass('active'); } } }); http://git-wip-us.apache.org/repos/asf/ambari/blob/a51532ac/contrib/views/hive20/src/main/resources/ui/app/services/jobs.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/app/services/jobs.js b/contrib/views/hive20/src/main/resources/ui/app/services/jobs.js index 723953c..ca058f2 100644 --- a/contrib/views/hive20/src/main/resources/ui/app/services/jobs.js +++ b/contrib/views/hive20/src/main/resources/ui/app/services/jobs.js @@ -33,10 +33,9 @@ export default Ember.Service.extend({ .then((job) => { let status = job.get('status').toLowerCase(); if (status === 'succeeded') { - this._fetchDummyResult(jobId); - resolve(); + resolve(status); } else if (status === 'error') { - reject() + reject(status) } else { resolve(this.waitForJobToComplete(jobId, after)); } @@ -47,8 +46,16 @@ export default Ember.Service.extend({ }); }, - _fetchDummyResult(jobId) { - this.get('store').adapterFor('job').fetchResult(jobId); + waitForJobStatus: function (jobId) { + return new Ember.RSVP.Promise((resolve, reject) => { + this.get('store').findRecord('job', jobId, {reload: true}) + .then((job) => { + let status = job.get('status').toLowerCase(); + resolve(status); + }, (error) => { + reject(error); + }); + }); } }); http://git-wip-us.apache.org/repos/asf/ambari/blob/a51532ac/contrib/views/hive20/src/main/resources/ui/app/services/query.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/app/services/query.js b/contrib/views/hive20/src/main/resources/ui/app/services/query.js index 400f78b..1799f71 100644 --- a/contrib/views/hive20/src/main/resources/ui/app/services/query.js +++ b/contrib/views/hive20/src/main/resources/ui/app/services/query.js @@ -53,10 +53,22 @@ export default Ember.Service.extend({ }); }, - downloadAsCsv(jobId, path){ let self = this; return this.get('store').adapterFor('job').downloadAsCsv(jobId, path); + }, + + retrieveQueryLog(logFile){ + + let self = this; + return new Promise( (resolve, reject) => { + this.get('store').adapterFor('query').retrieveQueryLog(logFile).then(function(data) { + resolve(data); + }, function(err) { + reject(err); + }); + }); + } http://git-wip-us.apache.org/repos/asf/ambari/blob/a51532ac/contrib/views/hive20/src/main/resources/ui/app/templates/components/query-result-log.hbs ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/components/query-result-log.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/components/query-result-log.hbs new file mode 100644 index 0000000..3903473 --- /dev/null +++ b/contrib/views/hive20/src/main/resources/ui/app/templates/components/query-result-log.hbs @@ -0,0 +1,23 @@ +{{! +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +}} + +<div style="height: 70vh"> + <pre class="prettyprint">{{logResults}}</pre> +</div> + +{{yield}} http://git-wip-us.apache.org/repos/asf/ambari/blob/a51532ac/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query.hbs ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query.hbs index 2138356..950e4f3 100644 --- a/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query.hbs +++ b/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query.hbs @@ -35,23 +35,49 @@ {{/if}} </div> </div> - <div class="clearfix row query-editor-results" style="position: relative"> - {{query-result-table - queryResult=queryResult - jobId=currentJobId - updateQuery='updateQuery' - previousPage=worksheet.previousPage - hidePreviousButton=hidePreviousButton - goNextPage='goNextPage' - goPrevPage='goPrevPage' - expandQueryResultPanel='expandQueryResultPanel' - saveToHDFS='saveToHDFS' - downloadAsCsv='downloadAsCsv' - isExportResultSuccessMessege=isExportResultSuccessMessege - isExportResultFailureMessege=isExportResultFailureMessege - showSaveHdfsModal=showSaveHdfsModal - }} + + + <div> + <ul class="row nav nav-tabs inverse"> + <li class="log-list active"> + <a href="javascript:void(0)" class="log-list-anchor active" {{action 'showQueryEditorLog' }}> + <i id="ember855" aria-hidden="true" class="fa fa-list"><!----></i> LOG + </a> + </li> + <li class="editor-result-list"> + <a href="javascript:void(0)" class="editor-result-list-anchor" {{action 'showQueryEditorResult' }}> + <i id="ember866" aria-hidden="true" class="fa fa-file-text-o"><!----></i> RESULT + </a> + </li> + </ul> </div> + + {{#if showQueryEditorLog}} + <div class="clearfix row query-editor-log" > + {{query-result-log logResults=worksheet.logResults }} + </div> + {{/if}} + + {{#if showQueryEditorResult}} + <div class="clearfix row query-editor-results" > + {{query-result-table + queryResult=queryResult + jobId=currentJobId + updateQuery='updateQuery' + previousPage=worksheet.previousPage + hidePreviousButton=hidePreviousButton + goNextPage='goNextPage' + goPrevPage='goPrevPage' + expandQueryResultPanel='expandQueryResultPanel' + saveToHDFS='saveToHDFS' + downloadAsCsv='downloadAsCsv' + isExportResultSuccessMessege=isExportResultSuccessMessege + isExportResultFailureMessege=isExportResultFailureMessege + showSaveHdfsModal=showSaveHdfsModal + }} + </div> + {{/if}} + </div> </div>