-
Notifications
You must be signed in to change notification settings - Fork 0
/
stats.js
134 lines (129 loc) · 3.92 KB
/
stats.js
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
"use strict";
module.exports = Stats
var FixedArray = require("fixed-array")
var StatsIncremental = require("stats-incremental")
function Stats(initial) {
if (!(this instanceof Stats)) return new Stats(initial)
this._stats = initial || {}
this.helper_stack = []
}
Stats.prototype._handle = function (out) {
// Bypass helper chain if there is none. (Mostly to avoid tacking on stats_runtime)
if (this.helper_stack.length === 0) return out(this._stats)
var self = this
var index = 0
var stack = this.helper_stack
var start = process.hrtime()
function next(error) {
if (error && error instanceof Error) {
self.increment("helperErrors")
}
var layer = stack[index++]
if (!layer) {
var elapsed = process.hrtime(start)
var agentStats = self.namespace("statware")
agentStats.checktime = Date.now()
agentStats.stats_runtime = elapsed[0] + elapsed[1] / 1e9
return out(self._stats)
}
layer(self._stats, next)
}
next()
}
Stats.prototype.getStats = function (callback) {
var self = this
self._handle(callback)
}
Stats.prototype.set = function (key, value) {
this._stats[key] = value
}
Stats.prototype.increment = function (key) {
if (isNaN(this._stats[key])) {
this._stats[key] = 1
}
else {
this._stats[key]++
}
}
// Async helpers should be be function(status_object, next)
Stats.prototype.registerHelper = function (fn) {
this.helper_stack.push(fn)
return this
}
Stats.prototype.windowedStat = function (key, windowSize) {
var statWindow = FixedArray(windowSize)
this.registerHelper(function (status, next) {
var vals = statWindow.values()
status[key] = {}
status[key].n = statWindow.length()
status[key].min = statWindow.min()
status[key].max = statWindow.max()
status[key].mean = statWindow.mean()
next()
})
return statWindow
}
Stats.prototype.addStat = function (key) {
var rolling = new StatsIncremental()
this.registerHelper(function (status, next) {
status[key] = rolling.getAll()
next()
})
return rolling
}
// Create a "namespace" within the object that has a similar interface.
// Rather than creating another underlaying Stats instance it just a sugary
// wrap around the existing one.
// Does not manage nested namespaces.
Stats.prototype.namespace = function (name) {
var parent = this
if (this._stats[name] == null) {
var space = {}
Object.defineProperty(space, "getStats", {value: function (callback) {
return parent.getStats(callback)
}})
Object.defineProperty(space, "set", {value: function (key, value) {
this[key] = value
}})
Object.defineProperty(space, "increment", {value: function (key) {
if (isNaN(this[key])) {
this[key] = 1
}
else {
this[key]++
}
}})
Object.defineProperty(space, "windowedStat", {value: function (key, windowSize) {
var statWindow = FixedArray(windowSize)
parent.registerHelper(function (status, next) {
var vals = statWindow.values()
status[name][key] = {}
status[name][key].n = statWindow.length()
status[name][key].min = statWindow.min()
status[name][key].max = statWindow.max()
status[name][key].mean = statWindow.mean()
next()
})
return statWindow
}})
Object.defineProperty(space, "addStat", {value: function (key) {
var rolling = new StatsIncremental()
parent.registerHelper(function (status, next) {
status[name][key] = rolling.getAll()
next()
})
return rolling
}})
Object.defineProperty(space, "registerHelper", {value: function (fn) {
parent.registerHelper(function (status, next) {
var ns = status[name]
fn(ns, next)
})
}})
Object.defineProperty(space, "namespace", {value: function () {
throw new Error("This is already a namespace. Nested namespaces not supported.")
}})
this._stats[name] = space
}
return this._stats[name]
}