guvnor
Version:
A node process manager that isn't spanners all the way down
167 lines (139 loc) • 3.99 kB
JavaScript
var Autowire = require('wantsit').Autowire
var shortId = require('shortid')
var ProcessData = function (data) {
this._config = Autowire
this._processDataFactory = Autowire
Object.defineProperties(this, {
logs: {
value: [],
writable: true
},
exceptions: {
value: [],
writable: true
},
usage: {
value: {
heapTotal: [],
heapUsed: [],
residentSize: [],
cpu: [],
latency: []
}
},
snapshots: {
value: [],
writable: true
}
})
this.afterPropertiesSet = this.update.bind(this, data)
}
ProcessData.prototype.update = function (data) {
this._map(data)
if (data.heapTotal === undefined) {
// partial data (ie. status timed out), skip appending data
return
}
// memory usage is reported in bytes, round to nearest 10Kb
this._appendUsage('heapTotal', ~~(data.heapTotal / 10000) * 10000, data.time)
this._appendUsage('heapUsed', ~~(data.heapUsed / 10000) * 10000, data.time)
this._appendUsage('residentSize', ~~(data.residentSize / 10000) * 10000, data.time)
this._appendUsage('cpu', data.cpu, data.time)
this._appendUsage('latency', Math.max(parseFloat(data.latency.toFixed(2)), 0), data.time)
}
ProcessData.prototype.log = function (type, date, message) {
if (!type || !date || !message) {
return
}
this.logs.push({
type: type,
date: date,
message: message
})
// rotate logs if necessary
if (this.logs.length > this._config.logs.max) {
this.logs.splice(0, this.logs.length - this._config.logs.max)
}
}
ProcessData.prototype.exception = function (date, message, code, stack) {
this.exceptions.push({
id: shortId.generate(),
date: date,
message: message,
code: code,
stack: stack
})
// rotate exceptions if necessary
if (this.exceptions.length > this._config.exceptions.max) {
this.exceptions.splice(0, this.exceptions.length - this._config.exceptions.max)
}
}
ProcessData.prototype.snapshot = function (id, date, path, size) {
this.snapshots.push({
id: id,
date: date,
path: path,
size: size
})
// rotate snapshots if necessary
if (this.snapshots.length > this._config.snapshots.max) {
this.snapshots.splice(0, this.snapshots.length - this._config.snapshots.max)
}
}
ProcessData.prototype.removeSnapshot = function (id) {
for (var i = 0; i < this.snapshots.length; i++) {
if (this.snapshots[i].id === id) {
this.snapshots.splice(i, 1)
i--
}
}
}
ProcessData.prototype._map = function (data) {
['debugPort', 'gid', 'group', 'id', 'name', 'pid', 'restarts', 'script', 'uid',
'uptime', 'user', 'status', 'heapTotal', 'heapUsed', 'residentSize', 'cpu',
'cwd', 'argv', 'execArgv', 'latency', 'language'].forEach(function (key) {
this[key] = data[key]
}.bind(this))
if (data.workers) {
this.cluster = true
if (!this.workers) {
this.workers = []
}
var workers = []
data.workers.forEach(function (incomingWorker) {
var worker
for (var i = 0; i < this.workers.length; i++) {
if (this.workers[i].id === incomingWorker.id) {
worker = this.workers[i]
break
}
}
if (!worker) {
this._processDataFactory.create([incomingWorker], function (error, worker) {
if (!error) {
workers.push(worker)
}
})
} else {
worker.update(incomingWorker)
workers.push(worker)
}
}.bind(this))
this.workers = workers
}
if (data.logs) {
data.logs.forEach(function (log) {
this.log(log.type, log.date, log.message)
}.bind(this))
}
}
ProcessData.prototype._appendUsage = function (arr, usage, time) {
if (this.usage[arr].length > this._config.graph.max) {
this.usage[arr].splice(0, this.usage[arr].length - this._config.graph.max)
}
this.usage[arr].push({
x: time,
y: usage
})
}
module.exports = ProcessData