spm-agent-os
Version:
SPM Agent for monitoring operating system metrics
240 lines (232 loc) • 9.05 kB
JavaScript
/*
* @copyright Copyright (c) Sematext Group, Inc. - All Rights Reserved
*
* @licence Sematext Agent for OS Metrics is free-to-use, proprietary software.
* THIS IS PROPRIETARY SOURCE CODE OF Sematext Group, Inc. (Sematext)
* This source code may not be copied, reverse engineered, or altered for any purpose.
* This source code is to be used exclusively by users and customers of Sematext.
* Please see the full license (found in LICENSE in this distribution) for details on its license and the licenses of its dependencies.
*/
var util = require('util')
var SpmAgent = require('spm-agent')
var Agent = SpmAgent.Agent
var config = SpmAgent.Config
var logger = SpmAgent.Logger
var os = require('os')
var cluster = require('cluster')
var linux = require('./linuxMetrics.js')
var lastValues = {}
function formatArray (a) {
if (a instanceof Array) {
if (a.length === 0) {
return ''
} else {
return a.join('\t')
}
} else {
return a + ''
}
}
function calcDiff (name, value) {
var diff = 0
if (!lastValues[name]) {
lastValues[name] = Number(value)
}
diff = value - lastValues[name]
lastValues[name] = value
return diff
}
/**
* This module generates Linux-OS Metrics. Names are compatible with collectd. SpmSender uses collectd format for OS Metrics
* @returns {Agent}
*/
module.exports = function () {
var cpuLastValues = {}
var linuxAgent = new Agent({
// osnet 1457010656149 lo 0 0
_formatLine: function (metric) {
var now = (new Date().getTime()).toFixed(0)
var line = null
if (metric.sct === 'OS' && /collectd/.test(metric.name)) {
line = this.collectdFormatLine(metric)
} else {
if (metric.sct === 'OS') {
// new OS metric format
if (metric.filters instanceof Array) {
line = util.format('%d\t%s\t%d\t%s\t%s', now, metric.name, metric.ts, formatArray(metric.filters), formatArray(metric.value))
} else {
line = util.format('%d\t%s\t%d\t%s', now, metric.name, metric.ts, formatArray(metric.value))
}
logger.log(line)
} else {
line = util.format('%d\t%s\t%d\t%s\t%s', now, (metric.type || this.defaultType) + '-' + metric.name, metric.ts, formatArray(metric.filters), formatArray(metric.value))
logger.log(line)
}
}
return line
},
start: function (agent) {
var statsInterval = Math.max(config.collectionInterval || 20000, 20000) || 20000
if (statsInterval < 20000) {
statsInterval = 20000
}
this.isLinux = (os.platform() === 'linux')
this.formatLine = this._formatLine.bind(agent)
this.agent = agent
if (cluster.isMaster || process.env.NODE_APP_INSTANCE === '0' || process.env.SPM_MASTER_MODE === '1') {
var timerId = setInterval(function () {
var time = Date.now()
var load = os.loadavg()
var loadAvg1min = 0
if (load && load.length > 0) {
loadAvg1min = load[0]
}
agent.addMetrics({ts: time, type: 'os', name: 'oslo', filters: '', value: [loadAvg1min], sct: 'OS'})
if (this.isLinux) {
cpuLastValues['cpu'] = {idle: 0, user: 0, system: 0, irq: 0, nice: 0, iowait: 0, softirq: 0, steal: 0, total: 0}
linux.cpuStats(function (cpu) {
if (!cpu || !cpu.cpu) {
return
}
var cpuProperties = ['user', 'nice', 'irq', 'system', 'idle', 'iowait', 'softirq', 'steal']
var key = 'cpu'
cpuProperties.forEach(function (property) {
cpuLastValues[key][property] = calcDiff(key + property, Number(cpu[key][property]))
cpuLastValues[key]['total'] = Number(cpuLastValues[key]['total']) + Number(cpuLastValues[key][property])
})
var cpuTotal = cpuLastValues[key]['total']
var oscpu = {
ts: time,
type: 'os',
name: 'oscpu',
filters: '',
value: [
(cpuLastValues[key].user / cpuTotal) * 100,
(cpuLastValues[key].nice / cpuTotal) * 100,
(cpuLastValues[key].system / cpuTotal) * 100,
(cpuLastValues[key].idle / cpuTotal) * 100,
(cpuLastValues[key].iowait / cpuTotal) * 100,
(cpuLastValues[key].irq / cpuTotal) * 100,
(cpuLastValues[key].softirq / cpuTotal) * 100,
(cpuLastValues[key].steal / cpuTotal) * 100
],
sct: 'OS'
}
if (!/null/.test(JSON.stringify(oscpu))) {
agent.addMetrics(oscpu)
}
})
linux.networkStats(function (data) {
if (data) {
data.forEach(function (netStat) {
if (netStat.bytes && netStat.Interface) {
agent.addMetrics({
ts: time,
name: 'osnet',
filters: [netStat.Interface || 'unknown'],
value: [calcDiff(netStat.Interface + 'tx', Number(netStat.bytes.Transmit)),
calcDiff(netStat.Interface + 'rx', Number(netStat.bytes.Receive))],
sct: 'OS'
})
}
})
}
})
linux.df(function dfMetrics (err, data) {
if (err) {
return logger.error('Error in df() for disk-usage metrics:' + err)
}
if (data && data.length > 0) {
data.forEach(function (disk) {
var dev = disk.filesystem
if (/\/dev\/.+/i.test(disk.filesystem)) {
dev = disk.filesystem.split('/')[2]
}
agent.addMetrics({
ts: time,
name: 'osdf',
filters: [dev],
value: [disk.available * 1024, disk.used * 1024],
sct: 'OS'
})
})
}
})
linux.vmstat(function (err, vmstat) {
SpmAgent.Logger.debug('vmstat ', vmstat)
if (err) {
SpmAgent.Logger.error('error calling vmstat ' + err)
return
}
linux.vmstatS(function (err, vmstats) {
if (err) {
SpmAgent.Logger.error('error calling vmstat ' + err)
return
}
var checkMemTotal = vmstats.memory.used + vmstats.memory.free + vmstats.memory.buffer + vmstats.memory.cache
if (checkMemTotal <= vmstats.memory.total) {
// should be equal on CentoOS 7.2
agent.addMetrics({
ts: time,
type: 'os',
name: 'osmem',
filters: '',
value: [
vmstats.memory.used * 1024,
vmstats.memory.free * 1024,
vmstats.memory.cache * 1024,
vmstats.memory.buffer * 1024,
vmstat.swapd * 1024,
vmstat.si,
vmstat.so],
sct: 'OS'
})
} else {
agent.addMetrics({
ts: time,
type: 'os',
name: 'osmem',
filters: '',
value: [
(vmstats.memory.used - (vmstats.memory.buffer + vmstats.memory.cache)) * 1024,
vmstats.memory.free * 1024,
vmstats.memory.cache * 1024,
vmstats.memory.buffer * 1024,
vmstat.swapd * 1024,
vmstat.si,
vmstat.so],
sct: 'OS'
})
}
if (vmstats.disks) {
try {
vmstats.disks.forEach(function (disk) {
agent.addMetrics({
ts: time,
type: 'os',
name: 'osdio',
filters: [disk.device],
value: [
(calcDiff(disk.device + 'sectors_read', disk.sectors_read) * 512),
(calcDiff(disk.device + 'sectors_written', disk.sectors_written) * 512)],
sct: 'OS'
})
})
} catch (diskInfoErr) {
console.log(diskInfoErr)
}
}
})
})
}
}.bind(this), statsInterval)
if (timerId.unref) {
timerId.unref()
}
}
}
}
)
return linuxAgent
}