algairim commented on a change in pull request #249:
URL: https://github.com/apache/brooklyn-ui/pull/249#discussion_r671172890
##########
File path: ui-modules/utils/logbook/logbook.js
##########
@@ -39,168 +39,249 @@ export function logbook() {
const DEFAULT_NUMBER_OF_ITEMS = 1000;
- $scope.isAutoScroll = true; // Auto-scroll by default.
- $scope.isLatest = true; // Indicates whether to query tail (last
number of lines) or head (by default).
- $scope.autoUpdate = false;
- $scope.waitingResponse = false;
-
- $scope.logtext = '';
- $scope.logEntries = [];
-
let vm = this;
let refreshFunction = null;
- let autoScrollableElements =
Array.from($element.find('pre')).filter(item =>
item.classList.contains('auto-scrollable'));
- let dateTimeToAutoUpdateFrom = ''; // TODO: use this date to optimize
'tail' queries to reduce the network traffic.
-
- // Set up cancellation of auto-scrolling on scrolling up.
- autoScrollableElements.forEach(item => {
- if (item.addEventListener) {
- let wheelHandler = () => {
- $scope.$apply(() => {
- $scope.isAutoScroll = (item.scrollTop +
item.offsetHeight) >= item.scrollHeight;
- });
- }
- // Chrome, Safari, Opera
- item.addEventListener("mousewheel", wheelHandler, false);
- // Firefox
- item.addEventListener("DOMMouseScroll", wheelHandler, false);
- }
- });
-
- vm.queryTail = () => {
- let autoUpdate = !$scope.autoUpdate; // Calculate new value.
-
- if (autoUpdate) {
- $scope.isAutoScroll = true;
- resetQueryParameters();
- doQuery();
+ let autoScrollableElement = Array.from($element.find('pre')).find(item
=> item.classList.contains('auto-scrollable'));
+ let isNewQueryParameters = true; // Fresh start, new parameters!
+ let dateTimeToAutoRefreshFrom = '';
+ let datetimeToScrollTo = null;
+
+ // Set up cancellation of auto-scrolling down.
+ if (autoScrollableElement.addEventListener) {
+ let wheelHandler = () => {
+ $scope.$apply(() => {
+ $scope.isAutoScrollDown = (autoScrollableElement.scrollTop
+ autoScrollableElement.offsetHeight) >= autoScrollableElement.scrollHeight;
+ });
}
-
- $scope.autoUpdate = autoUpdate; // Set new value.
+ // Chrome, Safari, Opera
+ autoScrollableElement.addEventListener("mousewheel", wheelHandler,
false);
+ // Firefox
+ autoScrollableElement.addEventListener("DOMMouseScroll",
wheelHandler, false);
}
- vm.queryHead = () => {
- $scope.waitingResponse = true;
- $scope.autoUpdate = false;
- $scope.isLatest = false;
- $scope.logtext = 'Loading...';
- doQuery();
- }
-
- $scope.$watch('allLevels', (value) => {
- if (!value) {
- if (getCheckedBoxes($scope.logLevels).length === 0) {
- $scope.allLevels = true;
- } else {
- return;
- }
- }
- for (let i = 0; i < $scope.logLevels.length; ++i) {
- $scope.logLevels[i].selected = false;
- }
- });
+ $scope.isAutoScrollDown = true; // Auto-scroll down, by default.
+ $scope.autoRefresh = false;
+ $scope.waitingResponse = false;
+ $scope.logtext = '';
+ $scope.wordwrap = true;
+ $scope.logEntries = [];
+ $scope.minNumberOfItems = 1;
+ $scope.maxNumberOfItems = 10000;
+
+ // Initialize search parameters.
+ $scope.search = {
+ logLevels: [
+ {name: 'Info', value: 'INFO', selected: true},
+ {name: 'Warn', value: 'WARN', selected: true},
+ {name: 'Error', value: 'ERROR', selected: true},
+ {name: 'Fatal', value: 'FATAL', selected: true},
+ {name: 'Debug', value: 'DEBUG', selected: true},
+ ],
+ latest: true,
+ dateTimeFrom: '',
+ dateTimeTo: '',
+ numberOfItems: DEFAULT_NUMBER_OF_ITEMS,
+ phrase: ''
+ };
+
+ // Define search result filters.
+ $scope.fieldsToShow = ['datetime', 'class', 'message']
+ $scope.logFields = [
+ {name: 'Timestamp', value: 'datetime', selected: true},
+ {name: 'Task ID', value: 'taskId', selected: false},
+ {name: 'Entity IDs', value: 'entityIds', selected: false},
+ {name: 'Log level', value: 'level', selected: true},
+ {name: 'Bundle ID', value: 'bundleId', selected: false},
+ {name: 'Class', value: 'class', selected: true},
+ {name: 'Thread name', value: 'threadName', selected: false},
+ {name: 'Message', value: 'message', selected: true},
+ ];
- $scope.$watch('logLevels', (newVal, oldVal) => {
- let selected = newVal.reduce(function (s, c) {
- return s + (c.selected ? 1 : 0);
- }, 0);
- if (selected === newVal.length || selected === 0) {
- $scope.allLevels = true;
- } else if (selected > 0) {
- $scope.allLevels = false;
+ // Watch for search parameters changes.
+ $scope.$watch('search', () => {
+ // Restart the auto-refresh.
+ if ($scope.autoRefresh) {
+ stopAutoRefresh();
+ vm.singleQuery();
+ startAutoRefresh();
}
}, true);
- $scope.$watch('logFields', (newVal, oldVal) => {
- if ($scope.logEntries !== "") {
- $scope.logtext = covertLogEntriesToString($scope.logEntries);
+ $scope.$watch('search.latest', () => {
+ datetimeToScrollTo = null;
+ if ($scope.search.latest) {
+ scrollToMostRecentLogEntry();
+ } else {
+ scrollToFirstLogEntry();
}
}, true);
- $scope.$watch('autoUpdate', ()=> {
- if ($scope.autoUpdate) {
- refreshFunction = $interval(doQuery, 1000);
+ // Watch for auto-update events.
+ $scope.$watch('autoRefresh', () => {
+ if ($scope.autoRefresh) {
+ startAutoRefresh();
} else {
- cancelAutoUpdate();
+ stopAutoRefresh();
}
});
- $scope.$on('$destroy', cancelAutoUpdate);
+ $scope.$on('$destroy', stopAutoRefresh);
+
+ /**
+ * @returns {boolean} True if number of items is a number and within a
supported range, false otherwise.
+ */
+ vm.isValidNumber =() => {
+ return $scope.search.numberOfItems >= $scope.minNumberOfItems &&
$scope.search.numberOfItems <= $scope.maxNumberOfItems;
+ }
+
+ /**
+ * Handles the click event on the log entry.
+ *
+ * @param {Object} logEntry The clicked log entry data.
+ */
+ vm.logEntryOnClick = (logEntry) => {
+ pinLogEntry(logEntry);
+ };
+
+ /**
+ * Starts an auto-query. Performs new query each time search
parameters change.
+ */
+ vm.autoQuery = () => {
+ let autoRefresh = !$scope.autoRefresh; // Calculate new value
first.
- // Watch the 'isAutoScroll' and auto-scroll down if enabled.
- $scope.$watch('isAutoScroll', () => {
- if ($scope.isAutoScroll) {
- scrollToMostRecentRecords();
+ if (autoRefresh) {
+ $scope.isAutoScrollDown = true;
+ doQuery();
}
- });
- // Initialize query parameters, reset them.
- resetQueryParameters();
-
- // Initialize the reset of search parameters.
- $scope.allLevels = true
- $scope.logLevels = [
- {"name": "Info", "value": "INFO", "selected": false},
- {"name": "Warn", "value": "WARN", "selected": false},
- {"name": "Error", "value": "ERROR", "selected": false},
- {"name": "Fatal", "value": "FATAL", "selected": false},
- {"name": "Debug", "value": "DEBUG", "selected": false},
- ];
- $scope.searchPhrase = '';
+ $scope.autoRefresh = autoRefresh; // Now, set the new value.
+ };
- // Initialize filters.
- $scope.fieldsToShow = ['datetime', 'class', 'message']
- $scope.logFields = [
- {"name": "Timestamp", "value": "datetime", "selected": true},
- {"name": "Task ID", "value": "taskId", "selected": false},
- {"name": "Entity IDs", "value": "entityIds", "selected": false},
- {"name": "Log level", "value": "level", "selected": true},
- {"name": "Bundle ID", "value": "bundleId", "selected": false},
- {"name": "Class", "value": "class", "selected": true},
- {"name": "Thread name", "value": "threadName", "selected": false},
- {"name": "Message", "value": "message", "selected": true},
- ];
+ /**
+ * Performs a single query with search parameters selected.
+ */
+ vm.singleQuery = () => {
+ isNewQueryParameters = true;
+ $scope.waitingResponse = true;
+ $scope.logtext = 'Loading...';
+ $scope.logEntries = [];
+ doQuery();
+ };
+
+ /**
+ * Converts log entry to string.
+ *
+ * @param {Object} entry The log entry to convert.
+ * @returns {String} log entry converted to string.
+ */
+ vm.covertLogEntryToString = (entry) => {
+ let fieldsToShow = getCheckedBoxes($scope.logFields);
+ let outputLine = [];
+ if (fieldsToShow.includes('datetime') && entry.timestamp)
+ outputLine.push(entry.timestamp);
+ if (fieldsToShow.includes('taskId') && entry.taskId)
+ outputLine.push(entry.taskId);
+ if (fieldsToShow.includes('entityIds') && entry.entityIds)
+ outputLine.push(entry.entityIds);
+ if (fieldsToShow.includes('level') && entry.level)
+ outputLine.push(entry.level);
+ if (fieldsToShow.includes('bundleId') && entry.bundleId)
+ outputLine.push(entry.bundleId);
+ if (fieldsToShow.includes('class') && entry.class)
+ outputLine.push(entry.class);
+ if (fieldsToShow.includes('threadName') && entry.threadName)
+ outputLine.push(entry.threadName);
+ if (fieldsToShow.includes('message') && entry.message)
+ outputLine.push(entry.message);
+
+ return outputLine.join(' ');
+ };
+
+ /**
+ * Caches the datetime of the first item in the visible area of the
query result.
+ */
+ function cacheDatetimeToScrollTo() {
+ let element = Array.from($element.find('pre')).find(item =>
item.offsetTop > (autoScrollableElement.scrollTop +
autoScrollableElement.offsetTop - 1));
+ let firstLogEntryInTheVisibleArea = $scope.logEntries.find(item =>
item.id === element.id);
+ if (firstLogEntryInTheVisibleArea) {
+ datetimeToScrollTo = firstLogEntryInTheVisibleArea.datetime;
+ }
+ }
+
+ /**
+ * @returns {boolean} true if current query is a tail request, false
otherwise.
+ */
+ function isTail() {
+ return $scope.search.latest && !$scope.search.dateTimeTo;
+ }
/**
* Performs a logbook query.
*/
function doQuery() {
- const levels = $scope.allLevels ? ['ALL'] :
getCheckedBoxes($scope.logLevels);
+
+ if (!vm.isValidNumber()) {
+ console.error('number of items is invalid',
$scope.search.numberOfItems)
+ return;
+ }
+
+ const levels = getCheckedBoxes($scope.search.logLevels);
const params = {
levels: levels,
- tail: $scope.isLatest,
- searchPhrase: $scope.searchPhrase,
- numberOfItems: $scope.numberOfItems,
- dateTimeFrom: $scope.isLatest ? dateTimeToAutoUpdateFrom :
$scope.dateTimeFrom,
- dateTimeTo: $scope.isLatest ? '' : $scope.dateTimeTo,
+ tail: $scope.search.latest,
+ searchPhrase: $scope.search.phrase,
+ numberOfItems: $scope.search.numberOfItems,
+ dateTimeFrom: isTail() && !isNewQueryParameters ?
dateTimeToAutoRefreshFrom : $scope.search.dateTimeFrom,
+ dateTimeTo: $scope.search.dateTimeTo,
}
+ cacheDatetimeToScrollTo();
+
logbookApi.logbookQuery(params, true).then((logEntries) => {
- if ($scope.isLatest && $scope.logEntries.length !== 0) {
- if (logEntries.length > 0) {
+ // Assign unique IDs for new log entries.
+ logEntries.forEach(item => item.id = generateLogEntryId());
+
+ if (logEntries.length > 0 && isTail() && $scope.autoRefresh &&
!isNewQueryParameters) {
- // Calculate date-time to display up to. Note,
calendar does not take into account milliseconds,
- // round down to seconds.
- let latestDateTimeToDisplay =
Math.floor(logEntries.slice(-1)[0].datetime / DEFAULT_NUMBER_OF_ITEMS) *
DEFAULT_NUMBER_OF_ITEMS;
+ // Calculate date-time to display up to. Note, calendar
does not take into account milliseconds, round down to seconds.
+ let dateTimeOfLastLogEntry =
Math.floor(logEntries.slice(-1)[0].datetime / DEFAULT_NUMBER_OF_ITEMS) *
DEFAULT_NUMBER_OF_ITEMS;
+ let dateTimeFrom = new
Date($scope.search.dateTimeFrom).getTime();
+
+ if (dateTimeOfLastLogEntry > dateTimeFrom) {
// Display new log entries.
- let newLogEntries = logEntries.filter(entry =>
entry.datetime <= latestDateTimeToDisplay);
+ let newLogEntries = logEntries.filter(({datetime}) =>
datetime <= dateTimeOfLastLogEntry);
$scope.logEntries =
$scope.logEntries.concat(newLogEntries).slice(-DEFAULT_NUMBER_OF_ITEMS);
- // Cache next date-time to query tail from.
- dateTimeToAutoUpdateFrom = new
Date(latestDateTimeToDisplay);
+ // Optimize auto-refresh: cache next date-time to
query tail from, if it is still a tail.
+ dateTimeToAutoRefreshFrom = dateTimeOfLastLogEntry;
+
} else {
- // Or re-set the cache.
- dateTimeToAutoUpdateFrom = '';
+ // Or re-set the cached value.
+ dateTimeToAutoRefreshFrom = '';
}
} else {
$scope.logEntries = logEntries;
}
- $scope.logtext = covertLogEntriesToString($scope.logEntries);
- scrollToMostRecentRecords();
+ // Auto-scroll.
+ if ($scope.logEntries.length > 0) {
+ if ($scope.isAutoScrollDown) {
+ scrollToMostRecentLogEntry();
+ } else if (datetimeToScrollTo && datetimeToScrollTo >=
$scope.logEntries[0].datetime) {
+ scrollToLogEntryWithDateTime(datetimeToScrollTo);
+ }
+ }
+
+ // Re-set marker for search parameters changes after
auto-scroll.
+ isNewQueryParameters = false;
+
+ if ($scope.logEntries.length === 0) {
Review comment:
No, `isNewQueryParameters` must be reset before that, regardless of
query result.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]