Skip to content

Bug 1427289 - Fix log updates when switching containers #1310

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 1, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
202 changes: 106 additions & 96 deletions app/scripts/directives/logViewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ angular.module('openshiftConsole')
'$timeout',
'$window',
'$filter',
'$q',
'AuthService',
'APIService',
'APIDiscovery',
Expand All @@ -19,6 +20,7 @@ angular.module('openshiftConsole')
$timeout,
$window,
$filter,
$q,
AuthService,
APIService,
APIDiscovery,
Expand Down Expand Up @@ -299,9 +301,15 @@ angular.module('openshiftConsole')
// since the user can (potentially) swap between multiple containers
var streamer;
var stopStreaming = function(keepContent) {
var deferred = $q.defer();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already set to null at line 401 below

if (streamer) {
streamer.onClose(function() {
deferred.resolve();
});
streamer.stop();
streamer = null;
} else {
// Resolve immediately if no active stream.
deferred.resolve();
}

if (!keepContent) {
Expand All @@ -310,117 +318,119 @@ angular.module('openshiftConsole')
cachedLogNode && (cachedLogNode.innerHTML = '');
buffer = document.createDocumentFragment();
}

return deferred.promise;
};

var streamLogs = function() {
// Stop any active streamer.
stopStreaming();

if(!$scope.run) {
return;
}

angular.extend($scope, {
loading: true,
autoScrollActive: true,
limitReached: false,
showScrollLinks: false
});

var options = angular.extend({
follow: true,
tailLines: 5000,
// Limit log size to 10 MiB. Note: This can't be more than 500 MiB,
// otherwise save log will break because we'll exceed the max Blob
// size for some browsers.
// https://github.com/eligrey/FileSaver.js#supported-browsers
limitBytes: 10 * 1024 * 1024
}, $scope.options);

streamer = DataService.createStream(logSubresource, name, $scope.context, options);

var lastLineNumber = 0;
var addLine = function(text) {
lastLineNumber++;
// Append the line to the document fragment buffer.
buffer.appendChild(buildLogLineNode(lastLineNumber, text));
update();
};

streamer.onMessage(function(msg, raw, cumulativeBytes) {
// ensures the digest loop will catch the state change.
stopStreaming().then(function() {
$scope.$evalAsync(function() {
$scope.empty = false;
if($scope.state !== 'logs') {
$scope.state = 'logs';
resizeWhenVisible();
if(!$scope.run) {
return;
}
});

// Completely empty messages (without even a newline character) should not add lines
if (!msg) {
return;
}

if (options.limitBytes && cumulativeBytes >= options.limitBytes) {
$scope.$evalAsync(function() {
$scope.limitReached = true;
$scope.loading = false;
angular.extend($scope, {
loading: true,
autoScrollActive: true,
largeLog: false,
limitReached: false,
showScrollLinks: false,
state: ''
});
stopStreaming(true);
}

addLine(msg);
var options = angular.extend({
follow: true,
tailLines: 5000,
// Limit log size to 10 MiB. Note: This can't be more than 500 MiB,
// otherwise save log will break because we'll exceed the max Blob
// size for some browsers.
// https://github.com/eligrey/FileSaver.js#supported-browsers
limitBytes: 10 * 1024 * 1024
}, $scope.options);

streamer = DataService.createStream(logSubresource, name, $scope.context, options);

var lastLineNumber = 0;
var addLine = function(text) {
lastLineNumber++;
// Append the line to the document fragment buffer.
buffer.appendChild(buildLogLineNode(lastLineNumber, text));
update();
};

streamer.onMessage(function(msg, raw, cumulativeBytes) {
// ensures the digest loop will catch the state change.
$scope.$evalAsync(function() {
$scope.empty = false;
if($scope.state !== 'logs') {
$scope.state = 'logs';
resizeWhenVisible();
}
});

// Completely empty messages (without even a newline character) should not add lines
if (!msg) {
return;
}

// Warn the user if we might be showing a partial log.
if (!$scope.largeLog && lastLineNumber >= options.tailLines) {
$scope.$evalAsync(function() {
$scope.largeLog = true;
});
}
});
if (options.limitBytes && cumulativeBytes >= options.limitBytes) {
$scope.$evalAsync(function() {
$scope.limitReached = true;
$scope.loading = false;
});
stopStreaming(true);
}

streamer.onClose(function() {
streamer = null;
$scope.$evalAsync(function() {
$scope.autoScrollActive = false;
// - if no logs, they have already been archived.
// - if emptyStateMessage has already been set, it means the onError
// callback has already fired. onError message takes priority in severity.
// - at present we are using the same error message in both onError and onClose
// because we dont have enough information to give the user something better.
if((lastLineNumber === 0) && (!$scope.emptyStateMessage)) {
$scope.state = 'empty';
$scope.emptyStateMessage = 'The logs are no longer available or could not be loaded.';
}
});
addLine(msg);

// Wrap in a timeout so that content displays before we remove the loading ellipses.
$timeout(function() {
$scope.loading = false;
}, 100);
});
// Warn the user if we might be showing a partial log.
if (!$scope.largeLog && lastLineNumber >= options.tailLines) {
$scope.$evalAsync(function() {
$scope.largeLog = true;
});
}
});

streamer.onError(function() {
streamer = null;
$scope.$evalAsync(function() {
angular.extend($scope, {
loading: false,
autoScrollActive: false
streamer.onClose(function() {
streamer = null;
$scope.$evalAsync(function() {
$scope.loading = false;
$scope.autoScrollActive = false;
// - if no logs, they have already been archived.
// - if emptyStateMessage has already been set, it means the onError
// callback has already fired. onError message takes priority in severity.
// - at present we are using the same error message in both onError and onClose
// because we dont have enough information to give the user something better.
if((lastLineNumber === 0) && (!$scope.emptyStateMessage)) {
$scope.state = 'empty';
$scope.emptyStateMessage = 'The logs are no longer available or could not be loaded.';
}
});
});
// if logs err before we get anything, will show an empty state message
if(lastLineNumber === 0) {
$scope.state = 'empty';
$scope.emptyStateMessage = 'The logs are no longer available or could not be loaded.';
} else {
// if logs were running but something went wrong, will
// show what we have & give option to retry
$scope.errorWhileRunning = true;
}

streamer.onError(function() {
streamer = null;
$scope.$evalAsync(function() {
angular.extend($scope, {
loading: false,
autoScrollActive: false
});
// if logs err before we get anything, will show an empty state message
if(lastLineNumber === 0) {
$scope.state = 'empty';
$scope.emptyStateMessage = 'The logs are no longer available or could not be loaded.';
} else {
// if logs were running but something went wrong, will
// show what we have & give option to retry
$scope.errorWhileRunning = true;
}
});
});

streamer.start();
});
});

streamer.start();
};

// Kibana archives -------------------------------------------------
Expand Down
Loading