github.com/nsqio/nsq@v1.3.0/nsqadmin/static/js/lib/handlebars_helpers.js (about) 1 var $ = require('jquery'); 2 var _ = require('underscore'); 3 var Handlebars = require('hbsfy/runtime'); 4 5 var AppState = require('../app_state'); 6 7 var formatStatsdKey = function(metricType, key) { 8 var fullKey = key; 9 var fmt; 10 11 if (metricType === 'counter') { 12 fmt = AppState.get('STATSD_COUNTER_FORMAT'); 13 fullKey = fmt.replace(/%s/g, key); 14 } else if (metricType === 'gauge') { 15 fmt = AppState.get('STATSD_GAUGE_FORMAT'); 16 fullKey = fmt.replace(/%s/g, key); 17 } 18 19 return fullKey; 20 }; 21 22 var statsdPrefix = function(host) { 23 var prefix = AppState.get('STATSD_PREFIX'); 24 var statsdHostKey = host.replace(/[\.:]/g, '_'); 25 prefix = prefix.replace(/%s/g, statsdHostKey); 26 if (prefix.substring(prefix.length, 1) !== '.') { 27 prefix += '.'; 28 } 29 return prefix; 30 }; 31 32 /* eslint-disable key-spacing */ 33 var metricType = function(key) { 34 return { 35 'depth': 'gauge', 36 'in_flight_count': 'gauge', 37 'deferred_count': 'gauge', 38 'requeue_count': 'counter', 39 'timeout_count': 'counter', 40 'message_count': 'counter', 41 'clients': 'gauge', 42 '*_bytes': 'gauge', 43 'gc_pause_*': 'gauge', 44 'gc_runs': 'counter', 45 'heap_objects': 'gauge', 46 'e2e_processing_latency': 'gauge' 47 }[key]; 48 }; 49 /* eslint-enable key-spacing */ 50 51 var genColorList = function(typ, key) { 52 if (typ === 'topic' || typ === 'channel') { 53 if (key === 'depth' || key === 'deferred_count') { 54 return 'red'; 55 } 56 } else if (typ === 'node') { 57 return 'red,green,blue,purple'; 58 } else if (typ === 'counter') { 59 return 'green'; 60 } 61 return 'blue'; 62 }; 63 64 // sanitizeGraphiteKey removes special characters from a graphite key 65 // this matches behavior of bitly/statsdaemon 66 // eslint-disable-next-line max-len 67 // https://github.com/bitly/statsdaemon/blob/fc46d9cfe29b674a0c8abc723afaa9370430cdcd/statsdaemon.go#L64-L88 68 var sanitizeGraphiteKey = function(s) { 69 return s.replaceAll(' ', '_').replaceAll('/', '-').replaceAll(/[^a-zA-Z0-9-_.]/g, ''); 70 }; 71 72 var genTargets = function(typ, node, ns1, ns2, key) { 73 var targets = []; 74 var prefix = statsdPrefix(node ? node : '*'); 75 var fullKey; 76 var target; 77 if (typ === 'topic') { 78 fullKey = formatStatsdKey(metricType(key), 79 prefix + 'topic.' + sanitizeGraphiteKey(ns1) + '.' + key); 80 targets.push('sumSeries(' + fullKey + ')'); 81 } else if (typ === 'channel') { 82 fullKey = formatStatsdKey(metricType(key), 83 prefix + 'topic.' + sanitizeGraphiteKey(ns1) + '.channel.' + 84 sanitizeGraphiteKey(ns2) + '.' + key); 85 targets.push('sumSeries(' + fullKey + ')'); 86 } else if (typ === 'node') { 87 target = prefix + 'mem.' + key; 88 if (key === 'gc_runs') { 89 target = 'movingAverage(' + target + ',45)'; 90 } 91 targets.push(formatStatsdKey(metricType(key), target)); 92 } else if (typ === 'e2e') { 93 targets = _.map(ns1['percentiles'], function(p) { 94 var t; 95 if (ns1['channel'] !== '') { 96 t = prefix + 'topic.' + ns1['topic'] + '.channel.' + ns1['channel'] + '.' + 97 key + '_' + (p['quantile'] * 100); 98 } else { 99 t = prefix + 'topic.' + ns1['topic'] + '.' + key + '_' + (p['quantile'] * 100); 100 } 101 if (node === '*') { 102 t = 'averageSeries(' + t + ')'; 103 } 104 return 'scale(' + formatStatsdKey(metricType(key), t) + ',0.000001)'; 105 }); 106 } else if (typ === 'counter') { 107 fullKey = formatStatsdKey(metricType(key), prefix + 'topic.*.channel.*.' + key); 108 targets.push('sumSeries(' + fullKey + ')'); 109 } 110 return targets; 111 }; 112 113 Handlebars.registerHelper('default', function(x, defaultValue) { 114 return x ? x : defaultValue; 115 }); 116 117 Handlebars.registerHelper('ifeq', function(a, b, options) { 118 return (a === b) ? options.fn(this) : options.inverse(this); 119 }); 120 121 Handlebars.registerHelper('unlesseq', function(a, b, options) { 122 return (a !== b) ? options.fn(this) : options.inverse(this); 123 }); 124 125 Handlebars.registerHelper('ifgteq', function(a, b, options) { 126 return (a >= b) ? options.fn(this) : options.inverse(this); 127 }); 128 129 Handlebars.registerHelper('iflteq', function(a, b, options) { 130 return (a <= b) ? options.fn(this) : options.inverse(this); 131 }); 132 133 Handlebars.registerHelper('length', function(xs) { 134 return xs.length; 135 }); 136 137 Handlebars.registerHelper('lowercase', function(s) { 138 return s.toLowerCase(); 139 }); 140 141 Handlebars.registerHelper('uppercase', function(s) { 142 return s.toUpperCase(); 143 }); 144 145 // this helper is inclusive of the top number 146 Handlebars.registerHelper('for', function(from, to, incr, block) { 147 var accum = ''; 148 for (var i = from; i <= to; i += incr) { 149 accum += block.fn(i); 150 } 151 return accum; 152 }); 153 154 // Logical operators as helper functions, which can be useful when used within 155 // an `if` or `unless` block via the new helper composition syntax, like so: 156 // 157 // {{#if (or step.unlocked step.is_finished)}} 158 // Step is unlocked or finished! 159 // {{/if}} 160 // 161 // Any number of arguments may be given to either helper. NOTE: _.initial() is 162 // used below because every helper takes an options hash as its last argument. 163 Handlebars.registerHelper('and', function() { 164 return _.all(_.initial(arguments)); 165 }); 166 167 Handlebars.registerHelper('or', function() { 168 return _.any(_.initial(arguments)); 169 }); 170 171 Handlebars.registerHelper('eq', function(a, b) { 172 return a === b; 173 }); 174 175 Handlebars.registerHelper('neq', function(a, b) { 176 return a !== b; 177 }); 178 179 Handlebars.registerHelper('urlencode', function(a) { 180 return encodeURIComponent(a); 181 }); 182 183 Handlebars.registerHelper('floatToPercent', function(f) { 184 return Math.floor(f * 100); 185 }); 186 187 Handlebars.registerHelper('percSuffix', function(f) { 188 var v = Math.floor(f * 100) % 10; 189 if (v === 1) { 190 return 'st'; 191 } else if (v === 2) { 192 return 'nd'; 193 } else if (v === 3) { 194 return 'rd'; 195 } 196 return 'th'; 197 }); 198 199 Handlebars.registerHelper('commafy', function(n) { 200 n = n || 0; 201 return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); 202 }); 203 204 function round(num, places) { 205 var multiplier = Math.pow(10, places); 206 return Math.round(num * multiplier) / multiplier; 207 } 208 209 Handlebars.registerHelper('nanotohuman', function(n) { 210 var s = ''; 211 var v; 212 if (n >= 3600000000000) { 213 v = Math.floor(n / 3600000000000); 214 n = n % 3600000000000; 215 s = v + 'h'; 216 } 217 if (n >= 60000000000) { 218 v = Math.floor(n / 60000000000); 219 n = n % 60000000000; 220 s += v + 'm'; 221 } 222 if (n >= 1000000000) { 223 n = round(n / 1000000000, 2); 224 s += n + 's'; 225 } else if (n >= 1000000) { 226 n = round(n / 1000000, 2); 227 s += n + 'ms'; 228 } else if (n >= 1000) { 229 n = round(n / 1000, 2); 230 s += n + 'us'; 231 } else { 232 s = n + 'ns'; 233 } 234 return s; 235 }); 236 237 Handlebars.registerHelper('sparkline', function(typ, node, ns1, ns2, key) { 238 var q = { 239 'colorList': genColorList(typ, key), 240 'height': '20', 241 'width': '120', 242 'hideGrid': 'true', 243 'hideLegend': 'true', 244 'hideAxes': 'true', 245 'bgcolor': 'ff000000', // transparent 246 'fgcolor': 'black', 247 'margin': '0', 248 'yMin': '0', 249 'lineMode': 'connected', 250 'drawNullAsZero': 'false', 251 'from': '-' + AppState.get('graph_interval'), 252 'until': '-1min' 253 }; 254 255 var interval = AppState.get('STATSD_INTERVAL') + 'sec'; 256 q['target'] = _.map(genTargets(typ, node, ns1, ns2, key), function(t) { 257 return 'summarize(' + t + ',"' + interval + '","avg")'; 258 }); 259 260 return AppState.get('GRAPHITE_URL') + '/render?' + $.param(q); 261 }); 262 263 Handlebars.registerHelper('large_graph', function(typ, node, ns1, ns2, key) { 264 var q = { 265 'colorList': genColorList(typ, key), 266 'height': '450', 267 'width': '800', 268 'bgcolor': 'ff000000', // transparent 269 'fgcolor': '999999', 270 'yMin': '0', 271 'lineMode': 'connected', 272 'drawNullAsZero': 'false', 273 'from': '-' + AppState.get('graph_interval'), 274 'until': '-1min' 275 }; 276 277 var interval = AppState.get('STATSD_INTERVAL') + 'sec'; 278 q['target'] = _.map(genTargets(typ, node, ns1, ns2, key), function(t) { 279 if (metricType(key) === 'counter') { 280 var scale = 1 / AppState.get('STATSD_INTERVAL'); 281 t = 'scale(' + t + ',' + scale + ')'; 282 } 283 return 'summarize(' + t + ',"' + interval + '","avg")'; 284 }); 285 286 return AppState.get('GRAPHITE_URL') + '/render?' + $.param(q); 287 }); 288 289 Handlebars.registerHelper('rate', function(typ, node, ns1, ns2) { 290 return genTargets(typ, node, ns1, ns2, 'message_count')[0]; 291 }); 292 293 Handlebars.registerPartial('error', require('../views/error.hbs')); 294 Handlebars.registerPartial('warning', require('../views/warning.hbs')); 295 296 Handlebars.registerHelper('basePath', function(p) { 297 return AppState.basePath(p); 298 });