diff --git a/webadmin/src/index.html b/webadmin/src/index.html index e1db892c5..5cd479e3c 100644 --- a/webadmin/src/index.html +++ b/webadmin/src/index.html @@ -66,6 +66,9 @@ + + + @@ -213,6 +216,7 @@
  • Domain & Certs
  • Email
  • Graphs
  • +
  • Logs
  • Settings
  • Support
  • diff --git a/webadmin/src/js/client.js b/webadmin/src/js/client.js index e44416195..5b9375b23 100644 --- a/webadmin/src/js/client.js +++ b/webadmin/src/js/client.js @@ -571,6 +571,18 @@ angular.module('Application').service('Client', ['$http', 'md5', 'Notification', }).error(defaultErrorHandler(callback)); }; + Client.prototype.getPlatformLogs = function (units, follow, callback) { + if (follow) { + var eventSource = new EventSource(client.apiOrigin + '/api/v1/cloudron/logstream?lines=100&access_token=' + token); + callback(null, eventSource); + } else { + get('/api/v1/apps/' + appId + '/logs').success(function (data, status) { + if (status !== 200 || typeof data !== 'object') return callback(new ClientError(status, data)); + callback(null, data); + }).error(defaultErrorHandler(callback)); + } + }; + Client.prototype.getApps = function (callback) { get('/api/v1/apps').success(function (data, status) { if (status !== 200 || typeof data !== 'object') return callback(new ClientError(status, data)); @@ -578,11 +590,16 @@ angular.module('Application').service('Client', ['$http', 'md5', 'Notification', }).error(defaultErrorHandler(callback)); }; - Client.prototype.getAppLogs = function (appId, callback) { - get('/api/v1/apps/' + appId + '/logs').success(function (data, status) { - if (status !== 200 || typeof data !== 'object') return callback(new ClientError(status, data)); - callback(null); - }).error(defaultErrorHandler(callback)); + Client.prototype.getAppLogs = function (appId, follow, callback) { + if (follow) { + var eventSource = new EventSource(client.apiOrigin + '/api/v1/apps/' + appId + '/logstream?lines=100&access_token=' + token); + callback(null, eventSource); + } else { + get('/api/v1/apps/' + appId + '/logs').success(function (data, status) { + if (status !== 200 || typeof data !== 'object') return callback(new ClientError(status, data)); + callback(null, data); + }).error(defaultErrorHandler(callback)); + } }; Client.prototype.getAppBackups = function (appId, callback) { diff --git a/webadmin/src/theme.scss b/webadmin/src/theme.scss index e9d5abc5c..8d11c5bbc 100644 --- a/webadmin/src/theme.scss +++ b/webadmin/src/theme.scss @@ -1143,3 +1143,19 @@ $graphs-success-alt: lighten(#27CE65, 20%); } } } + + +// ---------------------------- +// Logs +// ---------------------------- + +.log-line-container { + width: 100%; + max-width: 100%; + height: 400px; + background-color: black; + color: white; + overflow: auto; + border: none; + padding: 5px; +} diff --git a/webadmin/src/views/logs.html b/webadmin/src/views/logs.html index 422305e94..9f40af0c9 100644 --- a/webadmin/src/views/logs.html +++ b/webadmin/src/views/logs.html @@ -1,32 +1,29 @@ -
    -
    +
    -
    -
    -

    Logs

    -
    -
    +
    +
    +

    Logs

    +
    +
    -
    -
    -
    -
    -

    Logs

    - Select the log to view -
    -
    -
    -
    - -
    - Download -
    -
    -
    -
    +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    +
    diff --git a/webadmin/src/views/logs.js b/webadmin/src/views/logs.js index 8bc0f988e..3d2bcd4d3 100644 --- a/webadmin/src/views/logs.js +++ b/webadmin/src/views/logs.js @@ -4,22 +4,56 @@ angular.module('Application').controller('LogsController', ['$scope', '$location $scope.config = Client.getConfig(); $scope.user = Client.getUserInfo(); - $scope.logs = { - types: null, - selectedUrl: '' // index into types - }; + $scope.logs = []; + $scope.selected = null; + + function ab2str(buf) { + return String.fromCharCode.apply(null, new Uint16Array(buf)); + } $scope.populateLogTypes = function () { - $scope.logs.types = [ - { name: 'System (All)', url: Client.makeURL('/api/v1/cloudron/logs?units=all') }, - { name: 'Box', url: Client.makeURL('/api/v1/cloudron/logs?units=box') }, - { name: 'Mail', url: Client.makeURL('/api/v1/cloudron/logs?units=mail') } - ]; + $scope.logs.push({ name: 'System (All)', type: 'platform', units: 'all' }); + $scope.logs.push({ name: 'Box', type: 'platform', units: 'box' }); + $scope.logs.push({ name: 'Mail', type: 'platform', units: 'mail' }); Client.getInstalledApps().forEach(function (app) { - $scope.logs.types.push({ name: app.fqdn, url: Client.makeURL('/api/v1/apps/' + app.id + '/logs') }); + $scope.logs.types.push({ name: app.fqdn, type: 'app', id: app.id }); }); }; + $scope.$watch('selected', function (newVal) { + if (!newVal) return; + + if (newVal.type === 'platform') { + Client.getPlatformLogs(newVal.units, true, function (error, result) { + if (error) return console.error(error); + + var logViewer = $('.log-line-container'); + logViewer.empty(); + }); + } else { + Client.getAppLogs(newVal.id, true, function (error, result) { + if (error) return console.error(error); + + var logViewer = $('.log-line-container'); + logViewer.empty(); + + result.onmessage = function (e) { + var data; + + try { + data = JSON.parse(e.data); + } catch (e) { + return console.error(e); + } + + var logLine = $('
    '); + logLine.html(window.ansiToHTML(ab2str(data.message))); + logViewer.append(logLine); + }; + }); + } + }); + Client.onReady($scope.populateLogTypes); }]);