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: {
|
logs: {
|
||||||
method: 'GET', params: { id: '@id', action: 'logs' },
|
method: 'GET', params: { id: '@id', action: 'logs' },
|
||||||
timeout: 4500, ignoreLoadingBar: true,
|
timeout: 4500, ignoreLoadingBar: true,
|
||||||
transformResponse: logsHandler, isArray: true
|
transformResponse: logsHandler
|
||||||
},
|
},
|
||||||
stats: {
|
stats: {
|
||||||
method: 'GET', params: { id: '@id', stream: false, action: '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.
|
// The Docker API returns the logs as a single string.
|
||||||
// This handler will return an array with each line being an entry.
|
// This handler wraps the data in a JSON object under the "logs" property.
|
||||||
// It will also strip the 8 first characters of each line and remove any ANSI code related character sequences.
|
|
||||||
function logsHandler(data) {
|
function logsHandler(data) {
|
||||||
var logs = data;
|
return {
|
||||||
logs = logs.substring(8);
|
logs: data
|
||||||
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');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Image delete API returns an array on success (Docker 1.9 -> Docker 1.12).
|
// Image delete API returns an array on success (Docker 1.9 -> Docker 1.12).
|
||||||
|
|
|
@ -17,7 +17,7 @@ angular.module('portainer.docker')
|
||||||
logs: {
|
logs: {
|
||||||
method: 'GET', params: { id: '@id', action: 'logs' },
|
method: 'GET', params: { id: '@id', action: 'logs' },
|
||||||
timeout: 4500, ignoreLoadingBar: true,
|
timeout: 4500, ignoreLoadingBar: true,
|
||||||
transformResponse: logsHandler, isArray: true
|
transformResponse: logsHandler
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}]);
|
}]);
|
||||||
|
|
|
@ -10,7 +10,7 @@ angular.module('portainer.docker')
|
||||||
logs: {
|
logs: {
|
||||||
method: 'GET', params: { id: '@id', action: 'logs' },
|
method: 'GET', params: { id: '@id', action: 'logs' },
|
||||||
timeout: 4500, ignoreLoadingBar: true,
|
timeout: 4500, ignoreLoadingBar: true,
|
||||||
transformResponse: logsHandler, isArray: true
|
transformResponse: logsHandler
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}]);
|
}]);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
angular.module('portainer.docker')
|
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';
|
'use strict';
|
||||||
var service = {};
|
var service = {};
|
||||||
|
|
||||||
|
@ -131,7 +132,9 @@ angular.module('portainer.docker')
|
||||||
return deferred.promise;
|
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 = {
|
var parameters = {
|
||||||
id: id,
|
id: id,
|
||||||
stdout: stdout || 0,
|
stdout: stdout || 0,
|
||||||
|
@ -140,7 +143,16 @@ angular.module('portainer.docker')
|
||||||
tail: tail || 'all'
|
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) {
|
service.containerStats = function(id) {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
angular.module('portainer.docker')
|
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';
|
'use strict';
|
||||||
var service = {};
|
var service = {};
|
||||||
|
|
||||||
|
@ -59,6 +60,8 @@ angular.module('portainer.docker')
|
||||||
};
|
};
|
||||||
|
|
||||||
service.logs = function(id, stdout, stderr, timestamps, tail) {
|
service.logs = function(id, stdout, stderr, timestamps, tail) {
|
||||||
|
var deferred = $q.defer();
|
||||||
|
|
||||||
var parameters = {
|
var parameters = {
|
||||||
id: id,
|
id: id,
|
||||||
stdout: stdout || 0,
|
stdout: stdout || 0,
|
||||||
|
@ -67,7 +70,16 @@ angular.module('portainer.docker')
|
||||||
tail: tail || 'all'
|
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;
|
return service;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
angular.module('portainer.docker')
|
angular.module('portainer.docker')
|
||||||
.factory('TaskService', ['$q', 'Task', function TaskServiceFactory($q, Task) {
|
.factory('TaskService', ['$q', 'Task', 'LogHelper',
|
||||||
|
function TaskServiceFactory($q, Task, LogHelper) {
|
||||||
'use strict';
|
'use strict';
|
||||||
var service = {};
|
var service = {};
|
||||||
|
|
||||||
|
@ -36,6 +37,8 @@ angular.module('portainer.docker')
|
||||||
};
|
};
|
||||||
|
|
||||||
service.logs = function(id, stdout, stderr, timestamps, tail) {
|
service.logs = function(id, stdout, stderr, timestamps, tail) {
|
||||||
|
var deferred = $q.defer();
|
||||||
|
|
||||||
var parameters = {
|
var parameters = {
|
||||||
id: id,
|
id: id,
|
||||||
stdout: stdout || 0,
|
stdout: stdout || 0,
|
||||||
|
@ -44,7 +47,16 @@ angular.module('portainer.docker')
|
||||||
tail: tail || 'all'
|
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;
|
return service;
|
||||||
|
|
|
@ -11,7 +11,7 @@ function ($scope, $transition$, $interval, ContainerService, Notifications) {
|
||||||
if (!logCollectionStatus) {
|
if (!logCollectionStatus) {
|
||||||
stopRepeater();
|
stopRepeater();
|
||||||
} else {
|
} else {
|
||||||
setUpdateRepeater();
|
setUpdateRepeater(!$scope.container.Config.Tty);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -31,10 +31,10 @@ function ($scope, $transition$, $interval, ContainerService, Notifications) {
|
||||||
$scope.logs = logs;
|
$scope.logs = logs;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setUpdateRepeater() {
|
function setUpdateRepeater(skipHeaders) {
|
||||||
var refreshRate = $scope.state.refreshRate;
|
var refreshRate = $scope.state.refreshRate;
|
||||||
$scope.repeater = $interval(function() {
|
$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) {
|
.then(function success(data) {
|
||||||
$scope.logs = data;
|
$scope.logs = data;
|
||||||
})
|
})
|
||||||
|
@ -45,11 +45,11 @@ function ($scope, $transition$, $interval, ContainerService, Notifications) {
|
||||||
}, refreshRate * 1000);
|
}, refreshRate * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
function startLogPolling() {
|
function startLogPolling(skipHeaders) {
|
||||||
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) {
|
.then(function success(data) {
|
||||||
$scope.logs = data;
|
$scope.logs = data;
|
||||||
setUpdateRepeater();
|
setUpdateRepeater(skipHeaders);
|
||||||
})
|
})
|
||||||
.catch(function error(err) {
|
.catch(function error(err) {
|
||||||
stopRepeater();
|
stopRepeater();
|
||||||
|
@ -60,8 +60,9 @@ function ($scope, $transition$, $interval, ContainerService, Notifications) {
|
||||||
function initView() {
|
function initView() {
|
||||||
ContainerService.container($transition$.params().id)
|
ContainerService.container($transition$.params().id)
|
||||||
.then(function success(data) {
|
.then(function success(data) {
|
||||||
$scope.container = data;
|
var container = data;
|
||||||
startLogPolling();
|
$scope.container = container;
|
||||||
|
startLogPolling(!container.Config.Tty);
|
||||||
})
|
})
|
||||||
.catch(function error(err) {
|
.catch(function error(err) {
|
||||||
Notifications.error('Failure', err, 'Unable to retrieve container information');
|
Notifications.error('Failure', err, 'Unable to retrieve container information');
|
||||||
|
|
Loading…
Reference in New Issue