Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 60x 60x 1x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 1x 25x 25x 25x 25x 1x 1x 27x 27x 1x 60x 1x 1x 25x 1x 25x 25x 25x 25x 25x 1x 25x 25x 25x 25x 25x 1x 1x 1x 1x 1x 1x | /** * Created by sv2 on 2/18/17. * Timeline Statistics */ 'use strict'; var util = require('util'); var debug = require('debug')('sws:timeline'); var swsUtil = require('./swsUtil'); var swsReqResStats = require('./swsReqResStats'); function swsTimeline() { // Options this.options = null; // Timeline Settings this.settings = { bucket_duration: 60000, // Timeline bucket duration in milliseconds bucket_current: 0, // Current Timeline bucket ID length: 60 // Timeline length - number of buckets to keep }; // Timeline of req / res statistics, one entry per minute for past 60 minutes // Hash by timestamp divided by settings.bucket_duration, so we can match finished response to bucket this.data = {}; this.startTime = process.hrtime(); this.startUsage = process.cpuUsage(); // average memory usage values on time interval this.memorySum = process.memoryUsage(); this.memoryMeasurements = 1; // current max event loop lag this.lag = 0; } swsTimeline.prototype.getStats = function(reqresdata) { return { settings: this.settings, data: this.data }; }; // Create empty timeline going back 60 minutes swsTimeline.prototype.initialize = function (swsOptions) { this.options = swsOptions; var curr = Date.now(); Eif( swsUtil.supportedOptions.timelineBucketDuration in swsOptions ) { this.settings.bucket_duration = swsOptions[swsUtil.supportedOptions.timelineBucketDuration]; } var timelineid = Math.floor(curr / this.settings.bucket_duration ); this.settings.bucket_current = timelineid; for (var i = 0; i < this.settings.length; i++) { this.openTimelineBucket(timelineid); timelineid--; } }; // Update timeline and stats per tick swsTimeline.prototype.tick = function (ts,totalElapsedSec) { var timelineid = Math.floor( ts / this.settings.bucket_duration ); this.settings.bucket_current = timelineid; var currBucket = this.getTimelineBucket(timelineid); this.expireTimelineBucket(timelineid - this.settings.length); // Update rates in timeline, only in current bucket var currBucketElapsedSec = (ts - timelineid*this.settings.bucket_duration)/1000; currBucket.stats.updateRates(currBucketElapsedSec); // Update sys stats in current bucket var cpuPercent = swsUtil.swsCPUUsagePct(this.startTime, this.startUsage); currBucket.sys.cpu = cpuPercent; this.updateMemoryUsage(process.memoryUsage()); this.setMemoryStats(currBucket); let start = process.hrtime(); setImmediate(this.setMaxEvenLoopLag,start,this); }; swsTimeline.prototype.setMaxEvenLoopLag = function (start, dest) { const delta = process.hrtime(start); const nanosec = delta[0] * 1e9 + delta[1]; const mseconds = nanosec / 1e6; if( mseconds > dest.lag ){ dest.lag = mseconds; } } swsTimeline.prototype.getTimelineBucket = function (timelineid) { Iif( (timelineid>0) && (!(timelineid in this.data)) ) { // Open new bucket this.openTimelineBucket(timelineid); // Close previous bucket this.closeTimelineBucket(timelineid-1); } return this.data[timelineid]; }; swsTimeline.prototype.openTimelineBucket = function(timelineid) { // Open new bucket this.data[timelineid] = { stats: new swsReqResStats(this.options.apdexThreshold), sys: { rss:0, heapTotal:0, heapUsed:0, external:0, cpu: 0} }; }; // TODO Carry over rates, SYS from prev bucket - so it would be aways 0 on refresh with short buckets swsTimeline.prototype.closeTimelineBucket = function(timelineid) { if( !(timelineid in this.data) ) return; // Close bucket // update rates in previous timeline bucket: it becomes closed this.data[timelineid].stats.updateRates(this.settings.bucket_duration/1000); // Update sys stats var cpuPercent = swsUtil.swsCPUUsagePct(this.startTime, this.startUsage); this.data[timelineid].sys.cpu = cpuPercent; //debug('CPU: %s on %d', cpuPercent.toFixed(4), timelineid); var currMem = process.memoryUsage(); this.updateMemoryUsage(currMem); this.setMemoryStats(this.data[timelineid]); //debug('Mem: %s - CLOSE', this.data[timelineid].sys.heapUsed.toFixed(0)); // start from last this.memorySum = currMem; this.memoryMeasurements = 1; //debug('Mem: %s - CURR %s - START %d', this.memorySum.heapUsed.toFixed(0),currMem.heapUsed,this.memoryMeasurements); // Lag this.data[timelineid].sys.lag = this.lag; this.lag=0; this.startTime = process.hrtime(); setImmediate(this.setMaxEvenLoopLag,this.startTime,this.data[timelineid]); this.startUsage = process.cpuUsage(); }; swsTimeline.prototype.expireTimelineBucket = function (timelineid) { delete this.data[timelineid]; }; swsTimeline.prototype.updateMemoryUsage = function(currMem){ this.memoryMeasurements++; this.memorySum.rss += currMem.rss; this.memorySum.heapTotal += currMem.heapTotal; this.memorySum.heapUsed += currMem.heapUsed; this.memorySum.external += currMem.external; //debug('Mem: %s - CURR %s - UPDATE %d', Math.round(this.memorySum.heapUsed/this.memoryMeasurements),currMem.heapUsed,this.memoryMeasurements); }; swsTimeline.prototype.setMemoryStats = function(bucket){ Iif(!('sys' in bucket )) return; bucket.sys.rss = Math.round(this.memorySum.rss/this.memoryMeasurements); bucket.sys.heapTotal = Math.round(this.memorySum.heapTotal/this.memoryMeasurements); bucket.sys.heapUsed = Math.round(this.memorySum.heapUsed/this.memoryMeasurements); bucket.sys.external = Math.round(this.memorySum.external/this.memoryMeasurements); }; // Count request swsTimeline.prototype.countRequest = function (req, res) { // Count in timeline this.getTimelineBucket(req.sws.timelineid).stats.countRequest(req.sws.req_clength); }; // Count finished response swsTimeline.prototype.countResponse = function (res) { var req = res._swsReq; // Update timeline stats this.getTimelineBucket(req.sws.timelineid).stats.countResponse( res.statusCode, swsUtil.getStatusCodeClass(res.statusCode), req.sws.duration, req.sws.res_clength); }; module.exports = swsTimeline; |