blob: 5ec87a32e05c58162eaa8e8275ceb7fb4fd916f9 [file] [log] [blame]
/**
* 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.
*/
var App = require('app');
var dateUtils = require('utils/date/date');
App.LogTailView = Em.View.extend(App.InfiniteScrollMixin, {
startIndex: 0,
selectedTailCount: 50,
autoResize: false,
logRows: Em.A([]),
totalCount: 0,
totalItems: 0,
lastLogTime: 0,
isDataReady: false,
refreshEnd: true,
pollLogs: true,
pollLogInterval: 2000,
pollLogTimeoutId: null,
oldLogsAvailable: false,
oldLogsIsFetching: false,
templateName: require('templates/common/log_tail'),
content: null,
isVisible: Em.computed.not('App.isClusterUser'),
/**
* elements size are:
* .modal margin 40px x 2
* .modal inner padding 15px x 2
* .top-wrap-header height + margin 60px
* .modal-footer 60px
* .log-tail-popup-info 45px
*
* @property {number} resizeDelta
*/
resizeDelta: 15*2 + 60 + 60 + 40 + 45,
didInsertElement: function() {
var self = this;
this.infiniteScrollInit(this.$('.log-tail-content'), {
appendHtml: '<span id="empty-span"></span>'
});
this.fetchRows({
startIndex: 0
}).then(function(data) {
var logs = self.fetchRowsSuccess(data);
self.infiniteScrollSetDataAvailable(true);
self.appendLogRows(logs.reverse());
self.saveLastTimestamp(logs);
self.set('isDataReady', true);
self.scrollToBottom();
self.startLogPolling();
});
this.subscribeResize();
},
scrollToBottom: function() {
Em.run.next(this, function() {
this.$('.log-tail-content').scrollTop(this.$('.log-tail-content').prop('scrollHeight'));
});
},
_infiniteScrollHandler: function(e) {
var self = this;
this._super(e);
if ($(e.target).scrollTop() === 0) {
if (this.get('noOldLogs') && !this.get('oldLogsIsFetching')) return;
self.set('oldLogsIsFetching', true);
this.fetchRows(this.oldestLogs()).then(function(data) {
var oldestLog = self.get('logRows.0.logtime');
var logRows = self.fetchRowsSuccess(data).filter(function(i) {
return parseInt(i.get('logtime'), 10) < parseInt(oldestLog, 10);
});
if (logRows.length) {
self.get('logRows').unshiftObjects(logRows.reverse());
} else {
self.set('noOldLogs', true);
}
self.set('oldLogsIsFetching', false);
});
}
},
willDestroyElement: function() {
this._super();
this.stopLogPolling();
this.unsubscribeResize();
this.get('logRows').clear();
},
resizeHandler: function() {
// window.innerHeight * 0.1 = modal popup top 5% from both sides = 10%
if (this.get('state') === 'destroyed') return;
var newSize = $(window).height() - this.get('resizeDelta') - window.innerHeight*0.08;
this.$().find('.log-tail-content.pre-styled').css('maxHeight', newSize + 'px');
},
unsubscribeResize: function() {
if (!this.get('autoResize')) return;
$(window).off('resize', this.resizeHandler.bind(this));
},
subscribeResize: function() {
if (!this.get('autoResize')) return;
this.resizeHandler();
$(window).on('resize', this.resizeHandler.bind(this));
},
fetchRows: function(opts) {
var options = $.extend({}, true, {
startIndex: this.get('startIndex'),
pageSize: this.get('selectedTailCount')
}, opts || {});
return App.ajax.send({
sender: this,
name: 'logtail.get',
data: {
hostName: this.get('content.hostName'),
logComponentName: this.get('content.logComponentName'),
pageSize: "" + options.pageSize,
startIndex: "" + options.startIndex
},
error: 'fetchRowsError'
});
},
fetchRowsSuccess: function(data) {
var logRows = Em.getWithDefault(data, 'logList', []).map(function(logItem, i) {
var item = App.keysUnderscoreToCamelCase(App.permit(logItem, ['log_message', 'logtime', 'level', 'id']));
item.logtimeFormatted = dateUtils.dateFormat(parseInt(item.logtime, 10), 'YYYY-MM-DD HH:mm:ss,SSS');
return Em.Object.create(item);
});
if (logRows.length === 0) {
this.infiniteScrollSetDataAvailable(false);
return [];
}
return logRows;
},
fetchRowsError: function() {},
/** actions **/
openInLogSearch: function() {},
refreshContent: function() {
var self = this,
allIds;
if (!this.get('refreshEnd')) {
return $.Deferred().resolve().promise();
}
this.set('refreshEnd', false);
//this.infiniteScrollSetDataAvailable(true);
allIds = this.get('logRows').mapProperty('id');
return this.fetchRows(this.currentPage()).then(function(data) {
var logRows = self.fetchRowsSuccess(data).filter(function(i) {
return parseInt(i.logtime, 10) > parseInt(self.get('lastLogTime'), 10) && !allIds.contains(i.get('id'));
});
if (logRows.length) {
self.appendLogRows(logRows.reverse());
self.saveLastTimestamp(logRows);
}
self.set('refreshEnd', true);
});
},
appendLogRows: function(logRows) {
this.get('logRows').pushObjects(logRows);
},
saveLastTimestamp: function(logRows) {
this.set('lastLogTime', Em.getWithDefault(logRows, '0.logtime', 0));
return this.get('lastLogTime');
},
currentPage: function() {
return {
startIndex: 0,
pageSize: this.get('selectedTailCount')
};
},
nextPage: function() {
var newIndex = this.get('startIndex') + this.get('selectedTailCount');
if (newIndex < 0) {
newIndex = 0;
}
this.set('startIndex', newIndex);
return {
startIndex: newIndex,
pageSize: this.get('selectedTailCount')
};
},
oldestLogs: function() {
return {
startIndex: this.get('logRows.length'),
pageSize: this.get('selectedTailCount')
};
},
startLogPolling: function() {
var self = this;
if (!this.get('pollLogs') || this.get('state') === 'destroyed') return;
this.set('pollLogTimeoutId', setTimeout(function() {
self.stopLogPolling();
self.refreshContent().then(self.startLogPolling.bind(self));
}, this.get('pollLogInterval')));
},
stopLogPolling: function() {
if (!this.get('pollLogs') || this.get('pollLogTimeoutId') === null) return;
clearTimeout(this.get('pollLogTimeoutId'));
}
});