Skip to content

Instantly share code, notes, and snippets.

@Fusl
Last active December 1, 2018 07:24
Rust server stats to InfluxDB
#!/usr/bin/env node
'use strict';
const Websocket = require('ws');
const async = require('async');
const Influx = require('influx');
const once = require('once');
const toml = require('toml');
const fs = require('fs');
let config = null;
let influx = null;
const cargo = async.cargo((buffer, cb) => influx.writePoints(buffer).then(cb).catch(err => console.log('InfluxDB error:', err) + cb(err)));
const influxschema = [{
measurement: null,
tags: [
'Hostname',
'Map',
'Name'
],
fields: {
MaxPlayers: Influx.FieldType.INTEGER,
Players: Influx.FieldType.INTEGER,
Queued: Influx.FieldType.INTEGER,
Joining: Influx.FieldType.INTEGER,
EntityCount: Influx.FieldType.INTEGER,
Uptime: Influx.FieldType.INTEGER,
Framerate: Influx.FieldType.INTEGER,
Memory: Influx.FieldType.INTEGER,
Collections: Influx.FieldType.INTEGER,
NetworkIn: Influx.FieldType.INTEGER,
NetworkOut: Influx.FieldType.INTEGER,
Restarting: Influx.FieldType.BOOLEAN
}
}];
const poll = serverconfig => {
let timer = null;
let timeouttimer = null;
const reopen = once((...msg) => {
ws.close();
clearInterval(timer);
clearTimeout(timeouttimer);
timer = null;
timeouttimer = null;
console.log.apply(null, msg);
setTimeout(poll.bind(null, serverconfig), 5000)
});
const resettimeout = timeout => {
timeouttimer = setTimeout(reopen.bind(null, `Websocket for ${serverconfig.name} (ws://${serverconfig.host}:${serverconfig.port}/***) timed out`), timeout || serverconfig.timeout || (serverconfig.pollinterval * 10) || 30000);
};
const ws = new Websocket(`ws://${serverconfig.host}:${serverconfig.port}/${serverconfig.pass}`);
ws.once('close', reopen.bind(null, `Websocket for ${serverconfig.name} (ws://${serverconfig.host}:${serverconfig.port}/***) was closed`));
ws.once('error', reopen.bind(null, `Error emitted on Websocket for ${serverconfig.name} (ws://${serverconfig.host}:${serverconfig.port}/***):`));
resettimeout(300000);
ws.on('message', msg => {
let data = null;
try {
data = JSON.parse(JSON.parse(msg).Message);
} catch(e) {
// do nothing
}
if (!data || !data.Hostname || !data.Map) return;
clearTimeout(timeouttimer);
resettimeout();
cargo.push({
measurement: Object.keys(influx.schema[Object.keys(influx.schema)[0]])[0],
tags: {
Hostname: data.Hostname,
Map: data.Map,
Name: serverconfig.name
}, fields: {
MaxPlayers: data.MaxPlayers,
Players: data.Players,
Queued: data.Queued,
Joining: data.Joining,
EntityCount: data.EntityCount,
Uptime: data.Uptime,
Framerate: data.Framerate,
Memory: data.Memory,
Collections: data.Collections,
NetworkIn: data.NetworkIn,
NetworkOut: data.NetworkOut,
Restarting: data.Restarting
},
timestamp: new Date()
});
});
ws.once('open', () => {
ws.once('message', msg => {
timer = setInterval(() => {
ws.send(JSON.stringify({
Message: 'serverinfo',
Name: 'InfluxDB'
}));
}, serverconfig.pollinterval || 1000);
console.log(`Polling from ${serverconfig.name} (ws://${serverconfig.host}:${serverconfig.port}/***)`);
});
ws.send(JSON.stringify({
Message: 'serverinfo',
Name: 'InfluxDB'
}));
});
};
fs.readFile('./ruststats.toml', (err, data) => {
if (err) throw err;
config = toml.parse(data.toString('utf8'));
const influxconfig = config.influxdb;
influxconfig.schema = influxschema;
influxconfig.schema[0].measurement = config.influxdb.measurement;
influx = new Influx.InfluxDB(influxconfig);
config.server.forEach(poll);
});
[influxdb]
database = "influxdb"
host = "localhost"
port = 8086
username = "username"
password = "password"
measurement = "rust"
[[server]]
name = "server1"
host = "123.45.67.89"
port = 28016
pass = "CHANGEME"
pollinterval = 500
[[server]]
name = "server2"
host = "also-supports-hostnames.example.com"
port = 28018
pass = "CHANGEMEAGAIN"
pollinterval = 1000
timeout = 15000
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment