| /** |
| * 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')); |
| } |
| }); |