Commit b6a8d375 by joshiste Committed by Johannes Stelzer

New logging-view for easier logger-management

parent b0b82b2c
......@@ -75,19 +75,8 @@ angular.module('springBootAdmin', [
})
.state('apps.logging', {
url: '/logging/:id',
abstract: true,
templateUrl: 'views/apps/logging.html',
controller: 'detailsCtrl'
})
.state('apps.logging.read', {
url: '/read',
templateUrl: 'views/apps/logging/read.html',
controller: 'loggingReadCtrl'
})
.state('apps.logging.write', {
url: '/write',
templateUrl: 'views/apps/logging/write.html',
controller: 'loggingWriteCtrl'
controller: 'loggingCtrl'
})
.state('apps.jmx', {
url: '/jmx/:id',
......
......@@ -34,7 +34,7 @@ angular.module('springBootAdmin')
};
// callback for ng-click 'showLogging':
$scope.showLogging = function(id) {
$location.path('/apps/logging/' + id + '/read');
$location.path('/apps/logging/' + id);
};
// callback for ng-click 'showJmx':
$scope.showJmx = function(id) {
......@@ -192,20 +192,86 @@ angular.module('springBootAdmin')
ApplicationDetails.getClasspath(application);
});
})
.controller('loggingCtrl', function ($scope, $stateParams, Application) {
$scope.application = Application.query({id: $stateParams.id});
})
.controller('loggingReadCtrl', function ($scope, $stateParams, Application, ApplicationLogging) {
$scope.$parent.application.logger = new Object();
$scope.readLoglevel = function(application) {
ApplicationLogging.getLoglevel(application);
};
})
.controller('loggingWriteCtrl', function ($scope, $stateParams, Application, ApplicationLogging) {
$scope.$parent.application.logger = new Object();
$scope.writeLoglevel = function(application) {
ApplicationLogging.setLoglevel(application);
};
.controller('loggingCtrl', function ($scope, $stateParams, $filter, Application, ApplicationLogging) {
$scope.loggers = [];
$scope.filteredLoggers = [];
$scope.limit = 10;
function findLogger(loggers, name) {
for(var i in loggers) {
if (loggers[i].name === name){
return loggers[i];
}
}
}
$scope.setLogLevel = function(name, level) {
ApplicationLogging.setLoglevel($scope.application, name, level).then(function(response){
$scope.reload(name);
}).catch(function(response){
$scope.error = response.error;
console.log(response.stacktrace)
$scope.reload(name);
})
}
$scope.reload = function(prefix) {
for (var i in $scope.loggers) {
if (prefix == null || prefix === 'ROOT' || $scope.loggers[i].name.indexOf(prefix) == 0 ){
$scope.loggers[i].level = null;
}
}
$scope.refreshLevels();
}
$scope.refreshLevels = function() {
var toLoad = [];
var slice = $scope.filteredLoggers.slice(0, $scope.limit);
for (var i in slice ) {
if (slice[i].level === null) {
toLoad.push(slice[i]);
}
}
if (toLoad.length == 0) return;
ApplicationLogging.getLoglevel($scope.application, toLoad).then(
function(responses) {
for (var i in responses) {
var name = responses[i].request.arguments[0];
var level = responses[i].value;
findLogger($scope.loggers, name).level = level;
}
}).catch(function(responses){
for (var i in responses) {
if (responses[i].error != null) {
$scope.error = responses[i].error;
console.log(responses[i].stacktrace);
break;
}
}
});
}
$scope.application = Application.query({id: $stateParams.id}, function(application) {
ApplicationLogging.getAllLoggers(application).then( function (response) {
$scope.loggers = [];
for (var i in response.value) {
$scope.loggers .push({name: response.value[i], level: null});
}
$scope.$watchCollection('filteredLoggers', function() {
$scope.refreshLevels();
});
$scope.$watch('limit', function() {
$scope.refreshLevels();
});
}).catch(function(response) {
$scope.error = response.error;
console.log(response.stacktrace);
})
});
})
.controller('jmxCtrl', function ($scope, $stateParams, $modal, Application, ApplicationJMX) {
$scope.application = Application.query({id: $stateParams.id}, function(application) {
......@@ -219,9 +285,9 @@ angular.module('springBootAdmin')
})
});
$scope.readAttr = function(bean) {
$scope.readAllAttr = function(bean) {
bean.error = null;
ApplicationJMX.readAttr($scope.application, bean).then(
ApplicationJMX.readAllAttr($scope.application, bean).then(
function(response) {
for (var name in response.value) {
bean.attributes[name].error = null;
......@@ -244,7 +310,6 @@ angular.module('springBootAdmin')
}
$scope.invoke = function() {
$scope.invocation.state = 'executing';
ApplicationJMX.invoke($scope.application, $scope.invocation.bean, $scope.invocation.opname, $scope.invocation.args).then(
......
......@@ -32,4 +32,20 @@ angular.module('springBootAdmin')
while (s.length < 2) s = "0" + s;
return s;
}
});
\ No newline at end of file
})
.filter('classNameLoggerOnly', function() {
return function(input, active) {
if (!active) {
return input;
}
var result = [];
for (var j in input) {
var name = input[j].name;
var i = name.lastIndexOf('.') + 1;
if ( name.charAt(i) === name.charAt(i).toUpperCase() ) {
result.push(input[j]);
}
}
return result;
}
})
\ No newline at end of file
......@@ -104,30 +104,23 @@ angular.module('springBootAdmin.services', ['ngResource'])
});
}
}])
.service('ApplicationLogging', ['$http', function($http) {
this.getLoglevel = function(app) {
return $http.get(app.url +
'/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/getLoggerLevel/' +
app.logger.name)
.success(function(response) {
if (response['value'].length > 0) {
app.logger.loglevel = response['value'];
} else {
app.logger.loglevel = '<unknown>';
}
});
.service('ApplicationLogging', ['$http' , 'Jolokia', function($http, jolokia) {
var LOGBACK_MBEAN = 'ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator';
this.getLoglevel = function(app, loggers) {
var requests = [];
for (var j in loggers) {
requests.push({ type: 'exec', mbean: LOGBACK_MBEAN, operation: 'getLoggerEffectiveLevel', arguments: [ loggers[j].name ] })
}
return jolokia.bulkRequest(app.url + '/jolokia', requests);
}
this.setLoglevel = function(app) {
return $http.get(app.url +
'/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/setLoggerLevel/' +
app.logger.name + '/' + app.logger.loglevel)
.success(function(response) {
if (response['status'] == 200) {
app.logger.success = true;
} else {
app.logger.success = false;
}
});
this.setLoglevel = function(app, logger, level) {
return jolokia.exec(app.url + '/jolokia', LOGBACK_MBEAN, 'setLoggerLevel' , [ logger, level] );
}
this.getAllLoggers = function(app) {
return jolokia.readAttr(app.url + '/jolokia', LOGBACK_MBEAN, 'LoggerList');
}
}])
.service('ApplicationJMX', ['$rootScope', 'Abbreviator', 'Jolokia', function($rootScope, Abbreviator, jolokia) {
......@@ -189,12 +182,12 @@ angular.module('springBootAdmin.services', ['ngResource'])
});
}
this.readAttr = function(app, bean) {
this.readAllAttr = function(app, bean) {
return jolokia.read(app.url + '/jolokia', bean.id)
}
this.writeAttr = function(app, bean, attr, val) {
return jolokia.write(app.url + '/jolokia', bean.id, attr, val);
return jolokia.writeAttr(app.url + '/jolokia', bean.id, attr, val);
}
this.invoke = function(app, bean, opname, args) {
......@@ -272,9 +265,44 @@ angular.module('springBootAdmin.services', ['ngResource'])
}
}])
.service('Jolokia', [ '$q' , '$rootScope', function($q){
var outer = this;
var j4p = new Jolokia();
function call(url, request) {
this.bulkRequest = function(url, requests) {
var deferred = $q.defer();
deferred.notify(requests);
var hasError = false;
var responses = [];
j4p.request( requests,
{ url: url,
method: 'post',
success: function (response) {
responses.push(response);
if (responses.length >= requests.length) {
if (!hasError) {
deferred.resolve(responses);
} else {
deferred.resolve(responses);
}
}
},
error: function (response) {
hasError = true;
responses.push(response);
if (responses.length >= requests.length) {
deferred.reject(responses);
}
}
});
return deferred.promise;
}
this.request = function(url, request) {
var deferred = $q.defer();
deferred.notify(request);
......@@ -293,18 +321,22 @@ angular.module('springBootAdmin.services', ['ngResource'])
}
this.exec = function(url, mbean, op, args) {
return call(url, { type: 'exec', mbean: mbean, operation: op, arguments: args });
return outer.request(url, { type: 'exec', mbean: mbean, operation: op, arguments: args });
}
this.read = function(url, mbean) {
return call(url, { type: 'read', mbean: mbean });
return outer.request(url, { type: 'read', mbean: mbean });
}
this.readAttr = function(url, mbean, attr) {
return outer.request(url, { type: 'read', mbean: mbean, attribute: attr });
}
this.write = function(url, mbean, attr, val) {
return call(url, { type: 'write', mbean: mbean, attribute: attr, value: val });
this.writeAttr = function(url, mbean, attr, val) {
return outer.request(url, { type: 'write', mbean: mbean, attribute: attr, value: val });
}
this.list = function(url) {
return call(url, { type: 'list' });
return outer.request(url, { type: 'list' });
}
}]);
......@@ -33,7 +33,7 @@
<form class="form-horizontal" ng-if="bean.attributes !== undefinded">
<legend>
Attributes
<button class="btn" type="button" ng-click="readAttr(bean)">read</button>
<button class="btn" type="button" ng-click="readAllAttr(bean)">read</button>
</legend>
<div ng-show="bean.error" class="alert alert-error">
<b>Error:</b> {{ bean.error }}
......
<div class="row-fluid">
<div class="span12">
<h1 class="index-page--title">{{ application.id }}</h1>
<p class="index-page--subtitle">Read and write log levels of specified loggers.</p>
<p class="index-page--subtitle">Manage loggers</p>
</div>
</div>
<div class="container">
<div class="main-template">
<div id="xd-jobs" class="tab-pane active col-md-12">
<ul class="nav nav-tabs">
<li ui-sref-active="active"><a ui-sref="apps.logging.read({id: application.id})">Read</a></li>
<li ui-sref-active="active"><a ui-sref="apps.logging.write({id: application.id})">Write</a></li>
</ul>
<div class="tab-content">
<div ui-view></div>
</div>
<form ng-init="showPackageLoggers = false">
<div class="input-prepend input-append">
<button class="btn" title="Show package-level loggers" ng-model="showPackageLoggers" btn-checkbox ><i class="icon-folder-open"></i></button>
<input placeholder="Filter by name ..." class="span10" type="search" ng-model="filterLogger.name" />
<button class="btn" title="reload list" ng-click="reload()"><i class="icon-refresh"></i></button>
<span title="filtered / total" class="add-on">{{ filteredLoggers.length }}/{{ loggers.length }}</span>
</div>
</div>
</div>
</form>
<table class="table">
<tbody>
<tr ng-repeat="logger in (filteredLoggers = (loggers | classNameLoggerOnly:!showPackageLoggers | filter:filterLogger) ) | limitTo: limit track by logger.name">
<td>
{{ logger.name }}
<div class="btn-group pull-right">
<label class="btn btn-small" ng-class="{'btn-danger': logger.level== 'TRACE'}" ng-model="logger.level" btn-radio="'TRACE'" ng-click="setLogLevel(logger.name, 'TRACE')">TRACE</label>
<label class="btn btn-small" ng-class="{'btn-warning': logger.level=='DEBUG'}" ng-model="logger.level" btn-radio="'DEBUG'" ng-click="setLogLevel(logger.name, 'DEBUG')">DEBUG</label>
<label class="btn btn-small" ng-class="{'btn-info': logger.level=='INFO'}" ng-model="logger.level" btn-radio="'INFO'" ng-click="setLogLevel(logger.name, 'INFO')">INFO</label>
<label class="btn btn-small" ng-class="{'btn-success': logger.level == 'WARN'}" ng-model="logger.level" btn-radio="'WARN'" ng-click="setLogLevel(logger.name, 'WARN')">WARN</label>
<label class="btn btn-small" ng-class="{'btn-primary': logger.level == 'ERROR'}" ng-model="logger.level" btn-radio="'ERROR'" ng-click="setLogLevel(logger.name, 'ERROR')">ERROR</label>
<label class="btn btn-small" ng-class="{'btn-inverse': logger.level == 'OFF'}" ng-model="logger.level" btn-radio="'OFF'" ng-click="setLogLevel(logger.name, 'OFF')">OFF</label>
</div>
</td>
</tr>
<tr>
<td>
<button ng-show="limit < loggers.length" class="btn btn-link" ng-click="limit = limit + 10">show more</button>
<button ng-show="limit < loggers.length" class="btn btn-link" ng-click="limit = loggers.length">show all</button>
</td>
</tr>
</tbody>
</table>
</div>
\ No newline at end of file
<table class="table table-striped">
<thead>
<tr>
<th>Read log level</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<table>
<tr>
<td>Logger name</td>
<td><input type="text" ng-model="application.logger.name" style="margin-bottom: 0"></td>
</tr>
<tr>
<td>Log level</td>
<td>{{ application.logger.loglevel }}</td>
</tr>
<tr>
<td></td>
<td><button ng-click="readLoglevel(application)" class="btn btn-success">Read log level</button></td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
<table class="table table-striped">
<thead>
<tr>
<th>Write log level</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<table>
<tr>
<td>Logger name</td>
<td><input type="text" ng-model="application.logger.name" style="margin-bottom: 0"></td>
</tr>
<tr>
<td>Log level</td>
<td><div class="radio">
<label> <input type="radio" value="ERROR" ng-model="application.logger.loglevel">ERROR
</label>
</div>
<div class="radio">
<label> <input type="radio" value="WARN" ng-model="application.logger.loglevel">WARN
</label>
</div>
<div class="radio">
<label><input type="radio" value="INFO" ng-model="application.logger.loglevel">INFO</label>
</div>
<div class="radio">
<label><input type="radio" value="DEBUG" ng-model="application.logger.loglevel">DEBUG</label>
</div>
<div class="radio">
<label><input type="radio" value="TRACE" ng-model="application.logger.loglevel">TRACE</label>
</div></td>
</tr>
<tr>
<td></td>
<td><button ng-click="writeLoglevel(application)" class="btn btn-success">Write log level</button> <span
ng-show="application.logger.success" style="color: #008800">Success!</span><span
ng-show="application.logger.success != null && !application.logger.success" style="color: #880000">Error!</span></td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment