diff options
Diffstat (limited to 'sflow-rt/app/browse-metrics')
| -rw-r--r-- | sflow-rt/app/browse-metrics/LICENSE | 21 | ||||
| -rw-r--r-- | sflow-rt/app/browse-metrics/README.md | 10 | ||||
| -rw-r--r-- | sflow-rt/app/browse-metrics/html/index.html | 80 | ||||
| -rw-r--r-- | sflow-rt/app/browse-metrics/html/js/app.js | 226 |
4 files changed, 337 insertions, 0 deletions
diff --git a/sflow-rt/app/browse-metrics/LICENSE b/sflow-rt/app/browse-metrics/LICENSE new file mode 100644 index 0000000..1ee363b --- /dev/null +++ b/sflow-rt/app/browse-metrics/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2019 InMon Corporation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/sflow-rt/app/browse-metrics/README.md b/sflow-rt/app/browse-metrics/README.md new file mode 100644 index 0000000..edd31d9 --- /dev/null +++ b/sflow-rt/app/browse-metrics/README.md @@ -0,0 +1,10 @@ +# Browse metrics + +## To install + +1. [Download sFlow-RT](https://sflow-rt.com/download.php) +2. Run command: `sflow-rt/get-app.sh sflow-rt browse-metrics` +3. Restart sFlow-RT + +For more information, visit: +https://sFlow-RT.com diff --git a/sflow-rt/app/browse-metrics/html/index.html b/sflow-rt/app/browse-metrics/html/index.html new file mode 100644 index 0000000..bbb210a --- /dev/null +++ b/sflow-rt/app/browse-metrics/html/index.html @@ -0,0 +1,80 @@ +<!doctype html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> + <link rel="icon" type="image/png" href="../../../inc/img/favicon.png"> + <link rel="stylesheet" href="../../../inc/bootstrap.min.css"> + <link rel="stylesheet" href="../../../inc/stripchart.css"> + <script type="text/javascript" src="../../../inc/jquery.min.js"></script> + <script type="text/javascript" src="../../../inc/jquery.widget.js"></script> + <script type="text/javascript" src="../../../inc/jquery.stripchart.js"></script> + <script type="text/javascript" src="../../../inc/popper.min.js"></script> + <script type="text/javascript" src="../../../inc/bootstrap.min.js"></script> + <script type="text/javascript" src="js/app.js"></script> + <title>Metric Browser</title> + </head> + <body> + <nav class="navbar navbar-dark mb-3" style="background-color: #336;"> + <a class="navbar-brand" href="#"> + <img src="../../../inc/img/inmon.svg" height="30" class="d-inline-block align-top"> + Metric Browser + </a> + <form class="form-inline"> + <button id="clone" class="btn btn-outline-light" type="button">Clone</button> + </form> + </nav> + <main class="container" role="main"> + <form> + <div class="form-row"> + <div class="form-group col-md-4"> + <label for="agent">Agent</label> + <select class="form-control" id="agent"> + </select> + </div> + <div class="form-group col-md-4"> + <label for="metric">Metric</label> + <select class="form-control" id="metric"> + </select> + </div> + <div class="form-group col-md-2"> + <label for="datasource">Datasource</label> + <select class="form-control" id="datasource"> + </select> + </div> + <div class="form-group col-md-2"> + <label for="aggregation">Statistic</label> + <select class="form-control" id="aggregation"> + <option value="max">max</option> + <option value="min">min</option> + <option value="sum">sum</option> + <option value="avg">avg</option> + <option value="var">var</option> + <option value="sdev">sdev</option> + <option value="med">med</option> + <option value="q1">q1</option> + <option value="q2">q2</option> + <option value="q3">q3</option> + <option value="iqr">iqr</option> + <option value="any">any</option> + </select> + </div> + </div> + </form> + <table class="table table-striped table-bordered table-sm"> + <tbody> + <tr><td class="text-right font-weight-bold" style="width: 50%">Value</td><td id="metric-value" style="width: 50%"></td></tr> + <tr><td class="text-right font-weight-bold" style="width: 50%">N</td><td id="metric-n" style="width: 50%"></td></tr> + <tr><td class="text-right font-weight-bold" style="width: 50%">Agent</td><td id="metric-agent" style="width: 50%"></td></tr> + <tr><td class="text-right font-weight-bold" style="wdith: 50%">Datasource</td><td id="metric-datasource" style="width: 50%"></td></tr> + </tbody> + </table> + <div id="chart" class="trend" style="height:300px"></div> + </main> + <footer class="footer page-footer border-top mt-3"> + <div class="footer-copyright text-center py-2"> + <small class="text-muted">Copyright © 2015-<span class="year">2019</span> InMon Corp. ALL RIGHTS RESERVED</small> + </div> + </footer> + </body> +</html> diff --git a/sflow-rt/app/browse-metrics/html/js/app.js b/sflow-rt/app/browse-metrics/html/js/app.js new file mode 100644 index 0000000..4847897 --- /dev/null +++ b/sflow-rt/app/browse-metrics/html/js/app.js @@ -0,0 +1,226 @@ +$(function() { + var defaults = { + agent: 'ALL', + datasource: 'ALL', + aggregation: 'max' + }; + + var state = {}; + $.extend(state,defaults); + + function createQuery(params) { + var query, key, value; + for(key in params) { + value = params[key]; + if(value === defaults[key]) continue; + if(query) query += '&'; + else query = ''; + query += encodeURIComponent(key)+'='+encodeURIComponent(value); + } + return query; + } + + function getState(key, defVal) { + return window.sessionStorage.getItem('mb_'+key) || state[key] || defVal; + } + + function setState(key, val, showQuery) { + state[key] = val; + window.sessionStorage.setItem('mb_'+key, val); + if(showQuery) { + var query = createQuery(state); + window.history.replaceState({},'',query ? '?' + query : './'); + } + } + + function setQueryParams(query) { + var vars = query.split('&'); + var params = {}; + for(var i = 0; i < vars.length; i++) { + var pair = vars[i].split('='); + if(pair.length === 2) setState(decodeURIComponent(pair[0]), decodeURIComponent(pair[1]),false); + } + } + + var search = window.location.search; + if(search) setQueryParams(search.substring(1)); + + $('#clone').click(function() { + window.open(window.location); + }); + + var selectedAgent = getState('agent'); + var selectedMetric = getState('metric'); + var selectedDatasource = getState('datasource'); + var selectedAggregation = getState('aggregation'); + + var names = {}; + var maxPoints = 5 * 60; + var step = 1000; + var chartData; + + var nf = $.inmon.stripchart.prototype.valueStr; + + var widget = $('#chart').stripchart(); + + function resetChart() { + chartData = {times:[], values: []}; + var i, t = Date.now(); + for(i = 0; i < maxPoints; i++) { + t = t - step; + chartData.times.unshift(t); + } + var series = new Array(chartData.times.length); + for(i = 0; i < chartData.times.length; i++) series[i] = 0; + chartData.values.push(series); + } + + function updateChart(data) { + if(!data || data.length === 0) return; + if(!chartData) resetChart(); + + var now = Date.now(); + chartData.times.push(now); + var tmin = now - (maxPoints * 1.04 * step); + var nshift = 0; + while(chartData.times.length >= maxPoints || chartData.times[0] < tmin) { + chartData.times.shift(); + nshift++; + } + var series = chartData.values[0]; + var val = data[0].metricValue; + series.push($.isNumeric(val) ? val : 0); + for(var i = 0; i < nshift; i++) { + series.shift(); + } + widget.stripchart("draw", chartData); + $('#metric-agent').text(data[0].agent || ''); + $('#metric-datasource').text(data[0].dataSource || ''); + $('#metric-value').text($.isNumeric(val) ? nf(val) : val); + $('#metric-n').text(data[0].metricN || ''); + } + + $(window).resize(function() { + widget.stripchart("draw", chartData); + }); + + function updateMetrics() { + names = {}; + if('ALL' == selectedAgent) { + $.get('../../../metrics/json', function(metrics) { + var metricSelect = $('#metric'); + var dsSelect = $('#datasource'); + var i, metricsList = Object.keys(metrics).sort(); + if(!metrics[selectedMetric]) { + selectedMetric = metricsList[0]; + setState('metric',selectedMetric,true); + } + metricSelect.empty(); + for(i = 0; i < metricsList.length; i++) { + metricSelect.append('<option value="'+metricsList[i]+'"' + (selectedMetric == metricsList[i] ? ' selected' : '') + '>'+metricsList[i]+'</option>'); + } + dsSelect.empty(); + dsSelect.append('<option value="ALL" selected>ALL</option>'); + selectedDatasource = 'ALL'; + setState('datasource',selectedDatasource,true); + resetChart(); + }); + } else { + $.get('../../../metric/'+selectedAgent+'/json',function(metrics) { + var metricSelect = $('#metric'); + var dsSelect = $('#datasource'); + var i, idx, ds, dsName, dsList, name, nameList, metricsList = Object.keys(metrics); + for(i = 0; i < metricsList.length; i++) { + idx = metricsList[i].lastIndexOf('.'); + ds = metricsList[i].substring(0,idx); + name = metricsList[i].substring(idx+1); + dsList = names[name]; + if(!dsList) { + dsList = {}; + names[name] = dsList; + }; + dsList[ds] = metrics[ds+'.vir_host_name'] || metrics[ds+'.host_name'] || metrics[ds+'.ifname'] || ds;; + } + nameList = Object.keys(names).sort(); + if(!names[selectedMetric]) { + selectedMetric = nameList[0]; + setState('metric',selectedMetric,true); + } + metricSelect.empty(); + for(i = 0; i < nameList.length; i++) { + metricSelect.append('<option value="'+nameList[i]+'"' + (selectedMetric == nameList[i] ? ' selected' : '') + '>'+nameList[i]+'</option>'); + } + dsList = Object.keys(names[selectedMetric]).sort((a,b) => a - b); + dsSelect.empty(); + dsSelect.append('<option value="ALL"'+('ALL' === selectedDatasource ? ' selected' : '')+'>ALL</option>'); + for(i = 0; i < dsList.length; i++) { + ds = dsList[i]; + dsName = names[selectedMetric][ds]; + dsSelect.append('<option value="'+ds+'"'+(ds === selectedDatasource ? ' selected' : '')+'>'+dsName+'</options>'); + } + resetChart(); + }); + } + } + $('#agent').change(function(evt) { + selectedAgent = $('#agent').children('option:selected').val(); + setState('agent',selectedAgent,true); + updateMetrics(); + }); + $('#metric').change(function(evt) { + selectedMetric = $('#metric').children('option:selected').val(); + setState('metric',selectedMetric,true); + var dsSelect = $('#datasource'); + var i, ds, dsName, dsList = Object.keys(names[selectedMetric] || {}); + dsSelect.empty(); + if(dsList) { + dsList.sort((a,b) => a - b); + dsSelect.append('<option value="ALL">ALL</option>'); + for(i = 0; i < dsList.length; i++) { + ds = dsList[i]; + dsName = names[selectedMetric][ds]; + dsSelect.append('<option value="'+ds+'">'+dsName+'</options>'); + } + } else { + dsSelect.append('<option value="ALL" selected>ALL</option>'); + } + resetChart(); + }); + $('#datasource').change(function(evt) { + selectedDatasource = $('#datasource').children('option:selected').val(); + setState('datasource',selectedDatasource,true); + resetChart(); + }); + $('#aggregation option[value="'+selectedAggregation+'"]').prop('selected',true); + $('#aggregation').change(function(evt) { + selectedAggregation = $('#aggregation').children('option:selected').val(); + setState('aggregation',selectedAggregation,true); + resetChart(); + }); + $.get('../../../agents/json', function(agents) { + var agentSelect = $('#agent'); + var i, agentList = Object.keys(agents).sort(); + agentSelect.append('<option value="ALL"'+('ALL' === selectedAgent ? ' selected' : '')+'>ALL</option>'); + for(i = 0; i < agentList.length; i++) { + agentSelect.append('<option value="'+agentList[i]+'"'+(agentList[i] === selectedAgent ? ' selected' : '')+'>'+agentList[i]+'</option>'); + } + updateMetrics(); + resetChart(); + }); + (function poll() { + var metric = (!selectedDatasource || 'ALL' === selectedDatasource ? '' : selectedDatasource + '.') + selectedMetric; + var url = '../../../metric/'+selectedAgent+'/'+selectedAggregation+':'+metric+'/json'; + $.ajax({ + url: url, + success: function(data) { + updateChart(data); + setTimeout(poll, step); + }, + error: function(result,status,errorThrown) { + setTimeout(poll, 5000); + }, + dataType: "json", + timeout: 60000 + }); + })(); +}); |
