mirror of https://github.com/portainer/portainer
fix(log-viewer): strip headers in container logs when TTY is disabled (#1861)
parent
1e55ada6af
commit
e0cf088428
|
@ -0,0 +1,22 @@
|
|||
angular.module('portainer.docker')
|
||||
.factory('LogHelper', [function LogHelperFactory() {
|
||||
'use strict';
|
||||
var helper = {};
|
||||
|
||||
// Return an array with each line being an entry.
|
||||
// It will also remove any ANSI code related character sequences.
|
||||
// If the skipHeaders param is specified, it will strip the 8 first characters of each line.
|
||||
helper.formatLogs = function(logs, skipHeaders) {
|
||||
logs = logs.replace(
|
||||
/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, '');
|
||||
|
||||
if (skipHeaders) {
|
||||
logs = logs.substring(8);
|
||||
logs = logs.replace(/\n(.{8})/g, '\n\r');
|
||||
}
|
||||
|
||||
return logs.split('\n');
|
||||
};
|
||||
|
||||
return helper;
|
||||
}]);
|
|
@ -16,7 +16,7 @@ angular.module('portainer.docker')
|
|||
logs: {
|
||||
method: 'GET', params: { id: '@id', action: 'logs' },
|
||||
timeout: 4500, ignoreLoadingBar: true,
|
||||
transformResponse: logsHandler, isArray: true
|
||||
transformResponse: logsHandler
|
||||
},
|
||||
stats: {
|
||||
method: 'GET', params: { id: '@id', stream: false, action: 'stats' },
|
||||
|
|
|
@ -45,15 +45,11 @@ function genericHandler(data) {
|
|||
}
|
||||
|
||||
// The Docker API returns the logs as a single string.
|
||||
// This handler will return an array with each line being an entry.
|
||||
// It will also strip the 8 first characters of each line and remove any ANSI code related character sequences.
|
||||
// This handler wraps the data in a JSON object under the "logs" property.
|
||||
function logsHandler(data) {
|
||||
var logs = data;
|
||||
logs = logs.substring(8);
|
||||
logs = logs.replace(/\n(.{8})/g, '\n\r');
|
||||
logs = logs.replace(
|
||||
/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, '');
|
||||
return logs.split('\n');
|
||||
return {
|
||||
logs: data
|
||||
};
|
||||
}
|
||||
|
||||
// Image delete API returns an array on success (Docker 1.9 -> Docker 1.12).
|
||||
|
|
|
@ -17,7 +17,7 @@ angular.module('portainer.docker')
|
|||
logs: {
|
||||
method: 'GET', params: { id: '@id', action: 'logs' },
|
||||
timeout: 4500, ignoreLoadingBar: true,
|
||||
transformResponse: logsHandler, isArray: true
|
||||
transformResponse: logsHandler
|
||||
}
|
||||
});
|
||||
}]);
|
||||
|
|
|
@ -10,7 +10,7 @@ angular.module('portainer.docker')
|
|||
logs: {
|
||||
method: 'GET', params: { id: '@id', action: 'logs' },
|
||||
timeout: 4500, ignoreLoadingBar: true,
|
||||
transformResponse: logsHandler, isArray: true
|
||||
transformResponse: logsHandler
|
||||
}
|
||||
});
|
||||
}]);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
angular.module('portainer.docker')
|
||||
.factory('ContainerService', ['$q', 'Container', 'ResourceControlService', function ContainerServiceFactory($q, Container, ResourceControlService) {
|
||||
.factory('ContainerService', ['$q', 'Container', 'ResourceControlService', 'LogHelper',
|
||||
function ContainerServiceFactory($q, Container, ResourceControlService, LogHelper) {
|
||||
'use strict';
|
||||
var service = {};
|
||||
|
||||
|
@ -131,7 +132,9 @@ angular.module('portainer.docker')
|
|||
return deferred.promise;
|
||||
};
|
||||
|
||||
service.logs = function(id, stdout, stderr, timestamps, tail) {
|
||||
service.logs = function(id, stdout, stderr, timestamps, tail, stripHeaders) {
|
||||
var deferred = $q.defer();
|
||||
|
||||
var parameters = {
|
||||
id: id,
|
||||
stdout: stdout || 0,
|
||||
|
@ -140,7 +143,16 @@ angular.module('portainer.docker')
|
|||
tail: tail || 'all'
|
||||
};
|
||||
|
||||
return Container.logs(parameters).$promise;
|
||||
Container.logs(parameters).$promise
|
||||
.then(function success(data) {
|
||||
var logs = LogHelper.formatLogs(data.logs, stripHeaders);
|
||||
deferred.resolve(logs);
|
||||
})
|
||||
.catch(function error(err) {
|
||||
deferred.reject(err);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
service.containerStats = function(id) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
angular.module('portainer.docker')
|
||||
.factory('ServiceService', ['$q', 'Service', 'ServiceHelper', 'TaskService', 'ResourceControlService', function ServiceServiceFactory($q, Service, ServiceHelper, TaskService, ResourceControlService) {
|
||||
.factory('ServiceService', ['$q', 'Service', 'ServiceHelper', 'TaskService', 'ResourceControlService', 'LogHelper',
|
||||
function ServiceServiceFactory($q, Service, ServiceHelper, TaskService, ResourceControlService, LogHelper) {
|
||||
'use strict';
|
||||
var service = {};
|
||||
|
||||
|
@ -59,6 +60,8 @@ angular.module('portainer.docker')
|
|||
};
|
||||
|
||||
service.logs = function(id, stdout, stderr, timestamps, tail) {
|
||||
var deferred = $q.defer();
|
||||
|
||||
var parameters = {
|
||||
id: id,
|
||||
stdout: stdout || 0,
|
||||
|
@ -67,7 +70,16 @@ angular.module('portainer.docker')
|
|||
tail: tail || 'all'
|
||||
};
|
||||
|
||||
return Service.logs(parameters).$promise;
|
||||
Service.logs(parameters).$promise
|
||||
.then(function success(data) {
|
||||
var logs = LogHelper.formatLogs(data.logs, true);
|
||||
deferred.resolve(logs);
|
||||
})
|
||||
.catch(function error(err) {
|
||||
deferred.reject(err);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
return service;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
angular.module('portainer.docker')
|
||||
.factory('TaskService', ['$q', 'Task', function TaskServiceFactory($q, Task) {
|
||||
.factory('TaskService', ['$q', 'Task', 'LogHelper',
|
||||
function TaskServiceFactory($q, Task, LogHelper) {
|
||||
'use strict';
|
||||
var service = {};
|
||||
|
||||
|
@ -36,6 +37,8 @@ angular.module('portainer.docker')
|
|||
};
|
||||
|
||||
service.logs = function(id, stdout, stderr, timestamps, tail) {
|
||||
var deferred = $q.defer();
|
||||
|
||||
var parameters = {
|
||||
id: id,
|
||||
stdout: stdout || 0,
|
||||
|
@ -44,7 +47,16 @@ angular.module('portainer.docker')
|
|||
tail: tail || 'all'
|
||||
};
|
||||
|
||||
return Task.logs(parameters).$promise;
|
||||
Task.logs(parameters).$promise
|
||||
.then(function success(data) {
|
||||
var logs = LogHelper.formatLogs(data.logs, true);
|
||||
deferred.resolve(logs);
|
||||
})
|
||||
.catch(function error(err) {
|
||||
deferred.reject(err);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
return service;
|
||||
|
|
|
@ -11,7 +11,7 @@ function ($scope, $transition$, $interval, ContainerService, Notifications) {
|
|||
if (!logCollectionStatus) {
|
||||
stopRepeater();
|
||||
} else {
|
||||
setUpdateRepeater();
|
||||
setUpdateRepeater(!$scope.container.Config.Tty);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -31,10 +31,10 @@ function ($scope, $transition$, $interval, ContainerService, Notifications) {
|
|||
$scope.logs = logs;
|
||||
}
|
||||
|
||||
function setUpdateRepeater() {
|
||||
function setUpdateRepeater(skipHeaders) {
|
||||
var refreshRate = $scope.state.refreshRate;
|
||||
$scope.repeater = $interval(function() {
|
||||
ContainerService.logs($transition$.params().id, 1, 1, $scope.state.displayTimestamps ? 1 : 0, $scope.state.lineCount)
|
||||
ContainerService.logs($transition$.params().id, 1, 1, $scope.state.displayTimestamps ? 1 : 0, $scope.state.lineCount, skipHeaders)
|
||||
.then(function success(data) {
|
||||
$scope.logs = data;
|
||||
})
|
||||
|
@ -45,11 +45,11 @@ function ($scope, $transition$, $interval, ContainerService, Notifications) {
|
|||
}, refreshRate * 1000);
|
||||
}
|
||||
|
||||
function startLogPolling() {
|
||||
ContainerService.logs($transition$.params().id, 1, 1, $scope.state.displayTimestamps ? 1 : 0, $scope.state.lineCount)
|
||||
function startLogPolling(skipHeaders) {
|
||||
ContainerService.logs($transition$.params().id, 1, 1, $scope.state.displayTimestamps ? 1 : 0, $scope.state.lineCount, skipHeaders)
|
||||
.then(function success(data) {
|
||||
$scope.logs = data;
|
||||
setUpdateRepeater();
|
||||
setUpdateRepeater(skipHeaders);
|
||||
})
|
||||
.catch(function error(err) {
|
||||
stopRepeater();
|
||||
|
@ -60,8 +60,9 @@ function ($scope, $transition$, $interval, ContainerService, Notifications) {
|
|||
function initView() {
|
||||
ContainerService.container($transition$.params().id)
|
||||
.then(function success(data) {
|
||||
$scope.container = data;
|
||||
startLogPolling();
|
||||
var container = data;
|
||||
$scope.container = container;
|
||||
startLogPolling(!container.Config.Tty);
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to retrieve container information');
|
||||
|
|
Loading…
Reference in New Issue