Skip to content
This repository was archived by the owner on Nov 24, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
- Added Rocky Linux 8 support
- Traffic Monitors now peer with other Traffic Monitors of the same status (e.g. ONLINE with ONLINE, OFFLINE with OFFLINE), instead of all peering with ONLINE.
- Added permissions to the role form in traffic portal
- Updated the Cache Stats Traffic Portal page to use a more performant AG-Grid-based table.

## [6.1.0] - 2022-01-18
### Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,60 +17,220 @@
* under the License.
*/

var CacheStatsController = function(cacheStats, $scope, $state, $interval, numberUtils, serverUtils) {
/**
* @typedef CacheStat
* @property {string} cachegroup
* @property {number} connections
* @property {boolean} healthy
* @property {string} hostname
* @property {string | null} ip
* @property {number} kbps
* @property {string} profile
* @property {string} status
*/

var cacheStatsInterval,
autoRefresh = false,
refreshRateInMS = 10000;

var createInterval = function() {
killInterval();
cacheStatsInterval = $interval(function() { $scope.refresh() }, refreshRateInMS );
};
class CacheStatsHealthyCellRenderer {
Comment thread
shamrickus marked this conversation as resolved.
Outdated
/** @type HTMLSpanElement */
eGui;

var killInterval = function() {
if (angular.isDefined(cacheStatsInterval)) {
$interval.cancel(cacheStatsInterval);
cacheStatsInterval = undefined;
}
};
/**
* Called by AG-Grid as a pseudo constructor, used when a renderer is
* instantiated.
*
* @param {{
* api: any;
* colDef: any;
* column: any;
* columnApi: any;
* context: any;
* data: CacheStat;
* eGridCell: HTMLElement;
* eParentOfValue: HTMLElement;
* formatValue: function;
* fullWidth: boolean;
* getValue: function;
* node: any;
* pinned: string | null;
* refreshCell: function;
* registerRowDragger: function;
* rowIndex: number;
* setValue: function;
* value: boolean;
* valueFormatted: null;
* $scope: null;
* }} params
*/
init(params) {
this.eGui = document.createElement("span");
this.eGui.setAttribute("class", params.value ? "green" : "red");
this.eGui.textContent = String(params.value);
}

$scope.cacheStats = cacheStats;
/**
* Gets a rendered cell. Parameters are available, but not currently used.
*
* @returns {HTMLElement | Text} A rendered cell element.
*/
getGui() {
return this.eGui;
}
}

$scope.ssh = serverUtils.ssh;
/**
*
* @param {CacheStat[]} cacheStats
* @param {{user: {username: string}}} userModel
*/
var CacheStatsController = function(cacheStats, $scope, userModel) {

$scope.bandwidth = function(kbps, unit) {
return numberUtils.addCommas(numberUtils.convertTo(kbps, unit));
};
class CacheStatsSSHCellRenderer {
/** @type HTMLAnchorElement | Text */
eGui;

$scope.connections = function(amt) {
return numberUtils.addCommas(amt);
};
/**
* Called by AG-Grid as a pseudo constructor, used when a renderer is
* instantiated.
*
* @param {{
* api: any;
* colDef: any;
* column: any;
* columnApi: any;
* context: any;
* data: CacheStat;
* eGridCell: HTMLElement;
* eParentOfValue: HTMLElement;
* formatValue: function;
* fullWidth: boolean;
* getValue: function;
* node: any;
* pinned: string | null;
* refreshCell: function;
* registerRowDragger: function;
* rowIndex: number;
* setValue: function;
* value: string;
* valueFormatted: null;
* $scope: null;
* }} params
*/
init(params) {
if (params.data.ip === null) {
this.eGui = document.createTextNode(params.value);
return;
}
this.eGui = document.createElement("a");
this.eGui.href = `ssh://${userModel.user.username}@${params.data.ip}`;
this.eGui.setAttribute("class", "link");
this.eGui.textContent = params.value;
}

$scope.refresh = function() {
$state.reload(); // reloads all the resolves for the view
};
/**
* Gets a rendered cell. Parameters are available, but not currently used.
*
* @returns {HTMLElement | Text} A rendered cell element.
*/
getGui() {
return this.eGui;
}
}

$scope.$on("$destroy", function() {
killInterval();
});
/**
* The columns of the ag-grid table.
* @type CGC.ColumnDefinition[]
*/
$scope.columns = [
{
headerName: "Cache Group",
field: "cachegroup",
hide: false
},
{
headerName: "Connections",
field: "connections",
hide: false,
filter: "agNumberColumnFilter"
},
{
cellRenderer: CacheStatsHealthyCellRenderer,
headerName: "Healthy",
field: "healthy",
hide: false
},
{
cellRenderer: CacheStatsSSHCellRenderer,
headerName: "Host",
field: "hostname",
hide: false
},
{
cellRenderer: CacheStatsSSHCellRenderer,
headerName: "IP",
field: "ip",
hide: true,
},
{
headerName: "Data out rate",
field: "kbps",
filter: "agNumberColumnFilter",
hide: false,
/**
* Formats the kbps metric.
* @param {{value: number}} value Some AG Grid params containing the raw value to be formatted.
* @returns {string} The formatted value.
*/
valueFormatter: ({value}) => {
if (!value || value <= 0 || !isFinite(value)) {
return "0bps";
}
if (value >= 1e9) {
return `${(value/1e9).toFixed(3)}Tb/s`;
}
if (value >= 1e6) {
return `${(value/1e6).toFixed(3)}Gb/s`;
}
if (value >= 1000) {
return `${(value/1000).toFixed(3)}Mb/s`;
}
if (value >= 1) {
return `${value.toFixed(3)}kb/s`;
}
return `${(value*1000).toFixed(0)}b/s`;
}
},
{
headerName: "Profile",
field: "profile",
hide: false,
},
{
headerName: "Status",
field: "status",
hide: false,
}
];

angular.element(document).ready(function () {
$('#cacheStatsTable').dataTable({
"aLengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]],
"iDisplayLength": 25,
"order": [ [ 6, "desc" ] ] // sort by bandwidth, descending
});
});
$scope.data = cacheStats;

var init = function () {
if (autoRefresh) {
createInterval();
}
/** Options, configuration, data and callbacks for the ag-grid table. */
/** @type CGC.GridSettings */
$scope.gridOptions = {
refreshable: true,
};

$scope.defaultData = {
cachegroup: "ALL",
connections: -1,
healthy: false,
hostname: "ALL",
ip: null,
kbps: -1,
profile: "ALL",
status: "ALL"
};
init();

};

CacheStatsController.$inject = ['cacheStats', '$scope', '$state', '$interval', 'numberUtils', 'serverUtils'];
CacheStatsController.$inject = ["cacheStats", "$scope", "userModel"];
module.exports = CacheStatsController;
Original file line number Diff line number Diff line change
Expand Up @@ -18,41 +18,7 @@
-->

<div class="x_panel">
<div class="x_title">
<ol class="breadcrumb pull-left">
<li class="active">Cache Stats</li>
</ol>
<div class="pull-right" role="group">
<button class="btn btn-default" title="Refresh" ng-click="refresh()"><i class="fa fa-refresh"></i></button>
</div>
<div class="clearfix"></div>
</div>
<div class="x_content">
<br>
<table id="cacheStatsTable" class="table responsive-utilities jambo_table">
<thead>
<tr class="headings">
<th>Profile</th>
<th>Host</th>
<th>Cache Group</th>
<th>Healthy</th>
<th>Status</th>
<th>Connections</th>
<th>Mbps Out</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="cs in ::cacheStats">
<td>{{::cs.profile}}</td>
<td><a ng-click="ssh(cs.ip, $event)">{{::cs.hostname}}</a></td>
<td>{{::cs.cachegroup}}</td>
<td ng-class="{'green': cs.healthy, 'red': !cs.healthy}"><strong>{{::cs.healthy}}</strong></td>
<td>{{::cs.status}}</td>
<td>{{::connections(cs.connections)}}</td>
<td>{{::bandwidth(cs.kbps, 'Mb')}}</td>
</tr>
</tbody>
</table>
</div>
<common-grid-controller title="Cache Stats" table-name="cache-stats" options="gridOptions" data="data" columns="columns"
default-data="defaultData">
</common-grid-controller>
</div>