add debug console page, add log

This commit is contained in:
MaysWind 2018-04-06 00:58:14 +08:00
parent 94e295f184
commit 4bb0a9b972
15 changed files with 193 additions and 19 deletions

View file

@ -234,6 +234,9 @@
</li>
</ul>
</li>
<li class="ng-cloak" data-href-match="/debug" ng-if="enableDebugMode()">
<a href="#!/debug"><i class="fa fa-wrench"></i> <span translate>AriaNg Debug Console</span></a>
</li>
<li data-href-match="/status">
<a href="#!/status">
<span class="label pull-right" ng-if="globalStatusContext.isEnabled" ng-class="{'label-primary': taskContext.rpcStatus === 'Connecting', 'label-success': taskContext.rpcStatus === 'Connected', 'label-danger': taskContext.rpcStatus === 'Not Connected'}" ng-bind="taskContext.rpcStatus | translate"></span>
@ -356,6 +359,7 @@
<script src="scripts/config/aria2Errors.js"></script>
<script src="scripts/config/aria2RpcConstants.js"></script>
<script src="scripts/controllers/command.js"></script>
<script src="scripts/controllers/debug.js"></script>
<script src="scripts/controllers/main.js"></script>
<script src="scripts/controllers/new.js"></script>
<script src="scripts/controllers/list.js"></script>
@ -377,6 +381,7 @@
<script src="scripts/filters/longDate.js"></script>
<script src="scripts/filters/peerOrderBy.js"></script>
<script src="scripts/filters/percent.js"></script>
<script src="scripts/filters/reverse.js"></script>
<script src="scripts/filters/taskOrderBy.js"></script>
<script src="scripts/filters/taskStatus.js"></script>
<script src="scripts/filters/volume.js"></script>

View file

@ -59,6 +59,7 @@ BitTorrent Settings=BitTorrent 设置
Metalink Settings=Metalink 设置
RPC Settings=RPC 设置
Advanced Settings=高级设置
AriaNg Debug Console=AriaNg 调试控制台
Aria2 Status=Aria2 状态
File Name=文件名
File Size=大小
@ -193,6 +194,8 @@ GET=GET
Disabled=禁用
BitTorrent=BitTorrent
Changes to the settings take effect after refreshing page.=设置将在页面刷新后生效.
Show Detail=显示详情
Log Detail=日志详情
Type is illegal!=类型错误!
Parameter is invalid!=请求参数无效!
Option value cannot be empty!=参数内容不能为空!
@ -206,6 +209,7 @@ RPC secret is not base64 encoded!=RPC 密钥不是 Base64 编码后的字符串!
URL is not base64 encoded!=指定 URL 不是 Base64 编码后的字符串!
Tap to configure and get started with AriaNg.=您还没有进行过设置, 点击这里进行设置.
Cannot initialize WebSocket!=无法初始化 WebSocket!
Access Denied!=拒绝访问!
[error]
unknown=未知错误.
@ -255,6 +259,7 @@ task.pieceinfo=已完成: {{completed}}, 共计: {{total}} 块
task.error-occurred=发生错误 ({{errorcode}})
settings.file-count=({{count}} 个文件)
settings.total-count=(共计: {{count}}个)
debug.latest-logs=最近 {{count}} 条日志
[rpc.error]
unauthorized=认证失败!

View file

@ -59,6 +59,7 @@ BitTorrent Settings=BitTorrent 設定
Metalink Settings=Metalink 設定
RPC Settings=RPC 設定
Advanced Settings=進階設定
AriaNg Debug Console=AriaNg 調試控制台
Aria2 Status=Aria2 狀態
File Name=文件名
File Size=大小
@ -158,6 +159,8 @@ Waiting Count=正在等待數量
Stopped Count=已停止數量
You have disabled notification in your browser. You should change your browser's settings before you enable this function.=您已經在瀏覽器中禁用通知功能. 如需使用此功能, 請修改您瀏覽器的設定.
Configuration has been modified, please reload the page for the changes to take effect.=配置已經修改, 請重新載入頁面使其生效.
Show Detail=顯示詳情
Log Detail=日誌詳情
Reload Page=重新載入頁面
Show Secret=顯示密鑰
Hide Secret=隱藏密鑰
@ -206,6 +209,7 @@ RPC secret is not base64 encoded!=RPC 密鑰不是 Base64 編碼後的字元串!
URL is not base64 encoded!=指定 URL 不是 Base64 編碼後的字元串!
Tap to configure and get started with AriaNg.=您還沒有進行過設定, 點擊這裡進行設定.
Cannot initialize WebSocket!=無法初始化 WebSocket!
Access Denied!=拒絕訪問!
[error]
unknown=未知錯誤.
@ -255,6 +259,7 @@ task.pieceinfo=已完成: {{completed}}, 共計: {{total}} 塊
task.error-occurred=發生錯誤 ({{errorcode}})
settings.file-count=({{count}} 個文件)
settings.total-count=(共計: {{count}}個)
debug.latest-logs=最近 {{count}} 條日誌
[rpc.error]
unauthorized=認證失敗!

View file

@ -15,7 +15,8 @@
taskStatStorageCapacity: 300,
lazySaveTimeout: 500,
errorTooltipDelay: 500,
notificationInPageTimeout: 2000
notificationInPageTimeout: 2000,
cachedDebugLogsLimit: 100
}).constant('ariaNgDefaultOptions', {
language: 'en',
title: '${downspeed}, ${upspeed} - ${title}',

View file

@ -63,6 +63,7 @@
'Metalink Settings': 'Metalink Settings',
'RPC Settings': 'RPC Settings',
'Advanced Settings': 'Advanced Settings',
'AriaNg Debug Console': 'AriaNg Debug Console',
'Aria2 Status': 'Aria2 Status',
'File Name': 'File Name',
'File Size': 'File Size',
@ -197,6 +198,9 @@
'Disabled': 'Disabled',
'BitTorrent': 'BitTorrent',
'Changes to the settings take effect after refreshing page.': 'Changes to the settings take effect after refreshing page.',
'Latest {{count}} Logs': 'Latest {{count}} Logs',
'Show Detail': 'Show Detail',
'Log Detail': 'Log Detail',
'Type is illegal!': 'Type is illegal!',
'Parameter is invalid!': 'Parameter is invalid!',
'Option value cannot be empty!': 'Option value cannot be empty!',
@ -210,6 +214,7 @@
'URL is not base64 encoded!': 'URL is not base64 encoded!',
'Tap to configure and get started with AriaNg.': 'Tap to configure and get started with AriaNg.',
'Cannot initialize WebSocket!': 'Cannot initialize WebSocket!',
'Access Denied!': 'Access Denied!',
'error': {
'unknown': 'Unknown error occurred.',
'operation.timeout': 'Operation timed out.',
@ -257,7 +262,8 @@
'task.pieceinfo': 'Completed: {{completed}}, Total: {{total}}',
'task.error-occurred': 'Error Occurred ({{errorcode}})',
'settings.file-count': '({{count}} Files)',
'settings.total-count': '(Total Count: {{count}})'
'settings.total-count': '(Total Count: {{count}})',
'debug.latest-logs': 'Latest {{count}} Logs'
},
'rpc': {
'error': {

View file

@ -0,0 +1,38 @@
(function () {
'use strict';
angular.module('ariaNg').controller('AriaNgDebugController', ['$rootScope', '$scope', '$location', '$timeout', 'ariaNgConstants', 'ariaNgCommonService', 'ariaNgSettingService', 'ariaNgLogService', function ($rootScope, $scope, $location, $timeout, ariaNgConstants, ariaNgCommonService, ariaNgSettingService, ariaNgLogService) {
$scope.logMaxCount = ariaNgConstants.cachedDebugLogsLimit;
$scope.currentLog = null;
$scope.enableDebugMode = function () {
return ariaNgSettingService.isEnableDebugMode();
};
$scope.reloadLogs = function () {
$scope.logs = ariaNgLogService.getDebugLogs().slice();
};
$scope.showLogDetail = function (log) {
$scope.currentLog = log;
angular.element('#log-detail-modal').modal();
};
$('#log-detail-modal').on('hide.bs.modal', function (e) {
$scope.currentLog = null;
});
$rootScope.loadPromise = $timeout(function () {
if (!ariaNgSettingService.isEnableDebugMode()) {
ariaNgCommonService.showError('Access Denied!', function () {
if (!ariaNgSettingService.isEnableDebugMode()) {
$location.path('/settings/ariang');
}
});
return;
}
$scope.reloadLogs();
}, 100);
}]);
}());

View file

@ -36,6 +36,10 @@
data: ariaNgMonitorService.getGlobalStatsData()
};
$scope.enableDebugMode = function () {
return ariaNgSettingService.isEnableDebugMode();
};
$scope.quickSettingContext = null;
$scope.rpcSettings = ariaNgSettingService.getAllRpcSettings();

View file

@ -75,6 +75,10 @@
template: '',
controller: 'CommandController'
})
.when('/debug', {
templateUrl: 'views/debug.html',
controller: 'AriaNgDebugController'
})
.when('/status', {
templateUrl: 'views/status.html',
controller: 'Aria2StatusController'

View file

@ -0,0 +1,13 @@
(function () {
'use strict';
angular.module('ariaNg').filter('reverse', function () {
return function(array) {
if (!array) {
return array;
}
return array.slice().reverse();
};
});
}());

View file

@ -66,12 +66,12 @@
requestContext.url = getUrlWithQueryString(requestContext.url, context.requestBody);
}
ariaNgLogService.debug('[aria2HttpRpcService.request] request start', requestContext);
ariaNgLogService.debug('[aria2HttpRpcService.request] ' + (context && context.requestBody && context.requestBody.method ? context.requestBody.method + ' ' : '') + 'request start', requestContext);
return $http(requestContext).then(function onSuccess(response) {
var data = response.data;
ariaNgLogService.debug('[aria2HttpRpcService.request] response success', data);
ariaNgLogService.debug('[aria2HttpRpcService.request] ' + (context && context.requestBody && context.requestBody.method ? context.requestBody.method + ' ' : '') + 'response success', response);
if (!data) {
return;
@ -83,7 +83,7 @@
}).catch(function onError(response) {
var data = response.data;
ariaNgLogService.debug('[aria2HttpRpcService.request] response error', data);
ariaNgLogService.debug('[aria2HttpRpcService.request] ' + (context && context.requestBody && context.requestBody.method ? context.requestBody.method + ' ' : '') + 'response error', response);
if (!data) {
data = {

View file

@ -190,6 +190,8 @@
}
}
ariaNgLogService.debug('[aria2TaskService.processDownloadTask] process success', task);
return task;
};
@ -469,7 +471,7 @@
}
if (!response.success) {
ariaNgLogService.warn('[aria2TaskService.restartTask] response is not success');
ariaNgLogService.warn('[aria2TaskService.restartTask] response is not success', response);
deferred.reject(response);
callback(response);
return;
@ -528,7 +530,7 @@
silent: !!silent,
callback: function (response) {
if (!response.success) {
ariaNgLogService.warn('[aria2TaskService.restartTask] addUri response is not success');
ariaNgLogService.warn('[aria2TaskService.restartTask] addUri response is not success', response);
deferred.reject(response);
callback(response);
return;
@ -540,7 +542,7 @@
silent: true,
callback: function (response) {
if (!response.success) {
ariaNgLogService.warn('[aria2TaskService.restartTask] removeDownloadResult response is not success');
ariaNgLogService.warn('[aria2TaskService.restartTask] removeDownloadResult response is not success', response);
}
}
});
@ -685,7 +687,7 @@
},
processDownloadTasks: function (tasks) {
if (!angular.isArray(tasks)) {
ariaNgLogService.warn('[aria2TaskService.processDownloadTasks] tasks is not array');
ariaNgLogService.warn('[aria2TaskService.processDownloadTasks] tasks is not array', tasks);
return;
}
@ -701,7 +703,7 @@
},
estimateHealthPercentFromPeers: function (task, peers) {
if (!task || task.numPieces < 1 || peers.length < 1) {
ariaNgLogService.warn('[aria2TaskService.estimateHealthPercentFromPeers] tasks is null or numPieces < 1 or peers < 1');
ariaNgLogService.warn('[aria2TaskService.estimateHealthPercentFromPeers] tasks is null or numPieces < 1 or peers < 1', task);
return task.completePercent;
}

View file

@ -29,13 +29,13 @@
});
if (content.result && context.successCallback) {
ariaNgLogService.debug('[aria2WebSocketRpcService.request] response success', content);
ariaNgLogService.debug('[aria2WebSocketRpcService.request] ' + (context && context.requestBody && context.requestBody.method ? context.requestBody.method + ' ' : '') + 'response success', content);
context.successCallback(context.id, content.result);
}
if (content.error && context.errorCallback) {
ariaNgLogService.debug('[aria2WebSocketRpcService.request] response error', content);
ariaNgLogService.debug('[aria2WebSocketRpcService.request] ' + (context && context.requestBody && context.requestBody.method ? context.requestBody.method + ' ' : '') + 'response error', content);
context.errorCallback(context.id, content.error);
}
@ -110,7 +110,7 @@
var uniqueId = context.uniqueId;
var requestBody = angular.toJson(context.requestBody);
ariaNgLogService.debug('[aria2WebSocketRpcService.request] request start', context);
ariaNgLogService.debug('[aria2WebSocketRpcService.request] ' + (context && context.requestBody && context.requestBody.method ? context.requestBody.method + ' ' : '') + 'request start', context);
var deferred = $q.defer();

View file

@ -9,21 +9,25 @@
return hashedId;
},
showDialog: function (title, text, type) {
showDialog: function (title, text, type, callback) {
$timeout(function () {
SweetAlert.swal({
title: $translate.instant(title),
text: $translate.instant(text),
type: type,
confirmButtonText: $translate.instant('OK')
}, function () {
if (callback) {
callback();
}
});
}, 100);
},
showError: function (text) {
this.showDialog('Error', text, 'error');
showError: function (text, callback) {
this.showDialog('Error', text, 'error', callback);
},
showOperationSucceeded: function (text) {
this.showDialog('Operation Succeeded', text, 'success');
showOperationSucceeded: function (text, callback) {
this.showDialog('Operation Succeeded', text, 'success', callback);
},
confirm: function (title, text, type, callback, notClose, extendSettings) {
var options = {

View file

@ -1,7 +1,30 @@
(function () {
'use strict';
angular.module('ariaNg').factory('ariaNgLogService', ['$log', 'ariaNgSettingService', function ($log, ariaNgSettingService) {
angular.module('ariaNg').factory('ariaNgLogService', ['$log', 'moment', 'ariaNgConstants', 'ariaNgSettingService', function ($log, moment, ariaNgConstants, ariaNgSettingService) {
var cachedDebugLogs = [];
var createNewCacheLogItem = function (msg, level, obj) {
return {
time: moment(),
level: level,
content: msg,
attachment: obj
};
};
var pushLogToCache = function (msg, level, obj) {
if (!ariaNgSettingService.isEnableDebugMode()) {
return;
}
if (cachedDebugLogs.length >= ariaNgConstants.cachedDebugLogsLimit) {
cachedDebugLogs.shift();
}
cachedDebugLogs.push(createNewCacheLogItem(msg, level, obj));
};
return {
debug: function (msg, obj) {
if (ariaNgSettingService.isEnableDebugMode()) {
@ -10,6 +33,8 @@
} else {
$log.debug('[AriaNg Debug]' + msg);
}
pushLogToCache(msg, 'DEBUG', obj);
}
},
info: function (msg, obj) {
@ -18,6 +43,8 @@
} else {
$log.info('[AriaNg Info]' + msg);
}
pushLogToCache(msg, 'INFO', obj);
},
warn: function (msg, obj) {
if (obj) {
@ -25,6 +52,8 @@
} else {
$log.warn('[AriaNg Warn]' + msg);
}
pushLogToCache(msg, 'WARN', obj);
},
error: function (msg, obj) {
if (obj) {
@ -32,6 +61,15 @@
} else {
$log.error('[AriaNg Error]' + msg);
}
pushLogToCache(msg, 'ERROR', obj);
},
getDebugLogs: function () {
if (ariaNgSettingService.isEnableDebugMode()) {
return cachedDebugLogs;
} else {
return [];
}
}
};
}]);

49
src/views/debug.html Normal file
View file

@ -0,0 +1,49 @@
<section class="content no-padding ng-cloak" ng-if="enableDebugMode()">
<div class="nav-tabs-custom">
<ul class="nav nav-tabs">
<li class="active">
<a class="pointer-cursor" ng-bind="('format.debug.latest-logs' | translate: {count: logMaxCount})" ng-click="reloadLogs()">Latest Logs</a>
</li>
</ul>
<div class="tab-content no-padding">
<div class="settings-table striped hoverable">
<div class="row" ng-repeat="log in logs | reverse">
<div class="col-sm-12">
<span class="label label-default" ng-bind="'#' + ($index + 1)"></span>
<span ng-bind="log.time | longDate"></span>
<span class="label" ng-class="{'DEBUG':'label-default', 'INFO':'label-primary', 'WARN':'label-warning', 'ERROR':'label-danger'}[log.level]" ng-bind="log.level"></span>
<span ng-bind="log.content"></span>
<a class="pointer-cursor" ng-click="showLogDetail(log)" ng-if="log.attachment"><i class="fa fa-file-o"></i> <span translate>Show Detail</span></a>
</div>
</div>
</div>
</div>
</div>
<div id="log-detail-modal" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" translate>Log Detail</h4>
</div>
<div class="modal-body no-padding">
<div class="settings-table striped">
<div class="row">
<div class="col-sm-12">
<span ng-bind="currentLog.time | longDate"></span>
<span class="label" ng-class="{'DEBUG':'label-default', 'INFO':'label-primary', 'WARN':'label-warning', 'ERROR':'label-danger'}[currentLog.level]" ng-bind="currentLog.level"></span>
<span ng-bind="currentLog.content"></span>
</div>
</div>
<div class="row" ng-if="currentLog.attachment">
<div class="col-sm-12">
<pre ng-bind="currentLog.attachment | json"></pre>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>