Skip to content
This repository has been archived by the owner on Oct 20, 2021. It is now read-only.

Commit

Permalink
feat(logs): filter API requests logs
Browse files Browse the repository at this point in the history
  • Loading branch information
tcompiegne committed Nov 30, 2017
1 parent a647771 commit b5a391a
Show file tree
Hide file tree
Showing 7 changed files with 293 additions and 3 deletions.
8 changes: 6 additions & 2 deletions src/management/api/logs/_logs.scss
@@ -1,5 +1,3 @@


tr.log-error {
background-color: #f9f2f4;
color: #c7254e;
Expand Down Expand Up @@ -27,3 +25,9 @@ tr.log-error {
font-size:12px;
}
}

.logs-filters-container {
md-input-container.md-block {
margin-top: 0px;
}
}
27 changes: 27 additions & 0 deletions src/management/api/logs/components/logs-filters.component.ts
@@ -0,0 +1,27 @@
/*
* Copyright (C) 2015 The Gravitee team (http://gravitee.io)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

const LogsFiltersComponent: ng.IComponentOptions = {
template: require('./logs-filters.html'),
controller: 'LogsFiltersController',
bindings: {
onFiltersChange: '&',
metadata: '<'
}
};

export default LogsFiltersComponent;

172 changes: 172 additions & 0 deletions src/management/api/logs/components/logs-filters.controller.ts
@@ -0,0 +1,172 @@
/*
* Copyright (C) 2015 The Gravitee team (http://gravitee.io)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as _ from 'lodash';

class LogsFiltersController {
public filters: any = {};
public methods = {
1: 'CONNECT',
2: 'DELETE',
3: 'GET',
4: 'HEAD',
5: 'OPTIONS',
6: 'PATCH',
7: 'POST',
8: 'PUT',
9: 'TRACE'
};
public responseTimes = {
'[0 TO 100]': '0 to 100ms',
'[100 TO 200]': '100 to 200ms',
'[200 TO 300]': '200 to 300ms',
'[300 TO 400]': '300 to 400ms',
'[400 TO 500]': '400 to 500ms',
'[500 TO *]': '> 500ms'
};
public httpStatus = {
100: 'CONTINUE 100',
101: 'SWITCHING PROTOCOLS 101',
102: 'PROCESSING 102',
200: 'OK 200',
201: 'CREATED 201',
202: 'ACCEPTED 202',
203: 'NON AUTHORITATIVE INFORMATION 203',
204: 'NO CONTENT 204',
205: 'RESET CONTENT 205',
206: 'PARTIAL CONTENT 206',
207: 'MULTI STATUS 207',
300: 'MULTIPLE CHOICES 300',
301: 'MOVED PERMANENTLY 301',
302: 'FOUND 302',
303: 'SEE OTHER 303',
304: 'NOT MODIFIED 304',
305: 'USE PROXY 305',
307: 'TEMPORARY REDIRECT 307',
400: 'BAD REQUEST 400',
401: 'UNAUTHORIZED 401',
402: 'PAYMENT REQUIRED 402',
403: 'FORBIDDEN 403',
404: 'NOT FOUND 404',
405: 'METHOD NOT ALLOWED 405',
406: 'NOT ACCEPTABLE 406',
407: 'PROXY AUTHENTICATION REQUIRED 407',
408: 'REQUEST TIMEOUT 408',
409: 'CONFLICT 409',
410: 'GONE 410',
411: 'LENGTH REQUIRED 411',
412: 'PRECONDITION FAILED 412',
413: 'REQUEST ENTITY TOO LARGE 413',
414: 'REQUEST URI TOO LONG 414',
415: 'UNSUPPORTED MEDIA TYPE 415',
416: 'REQUESTED RANGE NOT SATISFIABLE 416',
417: 'EXPECTATION FAILED 417',
422: 'UNPROCESSABLE ENTITY 422',
423: 'LOCKED 423',
424: 'FAILED DEPENDENCY 424',
429: 'TOO MANY REQUESTS 429',
500: 'INTERNAL SERVER ERROR 500',
501: 'NOT IMPLEMENTED 501',
502: 'BAD GATEWAY 502',
503: 'SERVICE UNAVAILABLE 503',
504: 'GATEWAY TIMEOUT 504',
505: 'HTTP VERSION NOT SUPPORTED 505',
507: 'INSUFFICIENT STORAGE 507'
};
private fields = {
'responseTime': 'response-time'
};
private onFiltersChange: any;
private reordererdMedata: any;
private $scope;

constructor($scope) {
'ngInject';
this.$scope = $scope;
}

$onChanges(changesObj) {
if (changesObj.metadata) {
let metadata = changesObj.metadata.currentValue;
if (metadata) {
this.reordererdMedata = this.swap(metadata);
}
}
};

search() {
let query = this.buildQuery(this.filters);
this.onFiltersChange({filters : query});
}

clearFilters() {
this.$scope.logsFiltersForm.$setPristine();
this.filters = {};
this.search();
}

hasFilters() {
return !_.isEmpty(this.filters) && !this.isEmpty(this.filters);
}

private isEmpty(map) {
for(let key in map) {
let val = map[key];
return !(val !== undefined && val.length > 0);
}
return true;
}

private buildQuery(filters): string {
let query = '';
let keys = Object.keys(filters);
let index = 0;
let that = this;
_.forEach(keys, function (key) {
let val = filters[key];
if (key === 'application' || key === 'plan') {
val = that.map(val, that.reordererdMedata);
}
if (val !== undefined && val.length > 0) {
let params = (val.constructor === Array && val.length > 1) ? that.convert(val) : val;
query += that.map(key, that.fields) + ':' + params;
if (index + 1 < keys.length) {
query += ' AND ';
}
}
index++;
});
return query;
}

private convert(params) {
return '(' + params.join(' OR ') + ')';
}

private map(_val, list) {
let val = list[_val];
return (val) ? val : _val;
}

private swap(metadata) {
let ret = {};
for(let key in metadata){
ret[metadata[key].name] = key;
}
return ret;
}
}

export default LogsFiltersController;
74 changes: 74 additions & 0 deletions src/management/api/logs/components/logs-filters.html
@@ -0,0 +1,74 @@
<!--
Copyright (C) 2015 The Gravitee team (http://gravitee.io)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<md-card flex>
<div class="widget-card logs-filters-container" flex>
<md-card-title>
<md-card-title-text>
<span class="md-title"><strong>Filters</strong></span>
</md-card-title-text>
</md-card-title>
<md-card-content>
<form ng-submit="$ctrl.search()" name="logsFiltersForm">
<div layout-gt-sm="row">
<md-input-container class="md-block" flex-gt-sm flex="20">
<label>Transaction ID</label>
<input ng-model="$ctrl.filters.transaction">
</md-input-container>
<md-input-container class="md-block" flex-gt-sm flex="20">
<label>Methods</label>
<md-select ng-model="$ctrl.filters.method" placeholder="Methods" multiple>
<md-option ng-value="key" ng-repeat="(key, value) in $ctrl.methods">{{ value }}</md-option>
</md-select>
</md-input-container>
<md-input-container class="md-block" flex-gt-sm flex="20">
<label>Path</label>
<input ng-model="$ctrl.filters.path">
</md-input-container>
<md-input-container class="md-block" flex-gt-sm flex="20">
<label>Response times</label>
<md-select ng-model="$ctrl.filters.responseTime" placeholder="Response times" multiple>
<md-option ng-value="key" ng-repeat="(key, value) in $ctrl.responseTimes">{{ value }}</md-option>
</md-select>
</md-input-container>
<md-input-container class="md-block" flex-gt-sm flex="20">
<label>HTTP Status</label>
<md-select ng-model="$ctrl.filters.status" placeholder="HTTP Status" multiple>
<md-option ng-value="key" ng-repeat="(key, value) in $ctrl.httpStatus">{{ value }}</md-option>
</md-select>
</md-input-container>
<md-input-container class="md-block" flex-gt-sm flex="20">
<label>Application</label>
<input ng-model="$ctrl.filters.application">
</md-input-container>
<md-input-container class="md-block" flex-gt-sm flex="20">
<label>Plan</label>
<input ng-model="$ctrl.filters.plan">
</md-input-container>
<div>
<md-button type="button" class="md-raised" ng-click="$ctrl.clearFilters()" ng-disabled="logsFiltersForm.$pristine">
Clear filters
</md-button>
<md-button type="submit" class="md-raised md-primary" ng-click="$ctrl.search()" ng-disabled="!$ctrl.hasFilters()">
Search
</md-button>
</div>
</div>
</form>
</md-card-content>
</div>
</md-card>
7 changes: 6 additions & 1 deletion src/management/api/logs/logs.controller.ts
Expand Up @@ -58,7 +58,6 @@ class ApiLogsController {
}

selectLog(log) {
console.log(log);
}

refresh() {
Expand All @@ -70,6 +69,12 @@ class ApiLogsController {
getMetadata(id) {
return this.logs.metadata[id];
}

filtersChange(filters) {
this.query.page = 1;
this.query.query = filters;
this.refresh();
}
}

export default ApiLogsController;
4 changes: 4 additions & 0 deletions src/management/api/logs/logs.html
Expand Up @@ -18,11 +18,14 @@

<gv-logs-timeframe on-timeframe-change="logsCtrl.timeframeChange(timeframe)"></gv-logs-timeframe>

<gv-logs-filters on-filters-change="logsCtrl.filtersChange(filters)" metadata="logsCtrl.logs.metadata"></gv-logs-filters>

<md-table-container>
<table md-table class="gravitee-analytics-top-hits-table" multiple md-row-select="logsCtrl.widget.chart.selectable" data-ng-model="logsCtrl.selected">
<thead md-head>
<tr md-row>
<th md-column>Request Id</th>
<th md-column>Transaction Id</th>
<th md-column>Method</th>
<th md-column>Path</th>
<th md-column md-numeric>Status</th>
Expand All @@ -39,6 +42,7 @@
md-auto-select md-select="log" md-select-id="key"
md-on-select="logsCtrl.selectLog" ng-class="{'log-error': log.status >= 400}">
<td md-cell>{{log.id}}</td>
<td md-cell>{{log.transactionId}}</td>
<td md-cell>
<span class="badge gravitee-policy-method-badge-info ng-binding ng-scope gravitee-policy-method-badge-{{log.method | uppercase}}-selected">
{{log.method | uppercase}}
Expand Down
4 changes: 4 additions & 0 deletions src/management/management.module.ts
Expand Up @@ -222,6 +222,8 @@ import ApiLogsController from '../management/api/logs/logs.controller';
import LogsTimeframeComponent from '../management/api/logs/components/logs-timeframe.component';
import LogsTimeframeController from '../management/api/logs/components/logs-timeframe.controller';
import LogComponent from '../management/api/logs/log.component';
import LogsFiltersComponent from '../management/api/logs/components/logs-filters.component';
import LogsFiltersController from '../management/api/logs/components/logs-filters.controller';

// Others
import ImageDirective from '../components/image/image.directive';
Expand Down Expand Up @@ -548,6 +550,8 @@ angular.module('gravitee-management', [uiRouter, permission, uiPermission, 'ngMa
.component('gvLogsTimeframe', LogsTimeframeComponent)
.controller('LogsTimeframeController', LogsTimeframeController)
.component('log', LogComponent)
.component('gvLogsFilters', LogsFiltersComponent)
.controller('LogsFiltersController', LogsFiltersController)

.component("gvAudit", AuditComponent)
.component('gvContextualDoc', ContextualDocComponent)
Expand Down

0 comments on commit b5a391a

Please sign in to comment.