-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
129 lines (118 loc) · 3.78 KB
/
index.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
const debug = require("debug")("app");
const Connection = require('tedious').Connection;
const Request = require('tedious').Request;
const app = require('express')();
const client = require('./metrics').client;
const up = require('./metrics').up;
const metrics = require('./metrics').metrics;
let config = {
connect: {
server: process.env["SERVER"],
options: {
database: process.env["DATABASE"],
port: process.env["PORT"] || 1433,
rowCollectionOnRequestCompletion: true,
// If you're on Windows Azure, you will need this:
encrypt: true
},
authentication: {
type: "default",
options: {
userName: process.env["USERNAME"],
password: process.env["PASSWORD"]
}
}
},
port: process.env["EXPOSE"] || 4000
};
if (!config.connect.server) {
throw new Error("Missing SERVER information")
}
if (!config.connect.options.database) {
throw new Error("Missing DATABASE information")
}
if (!config.connect.authentication.options.userName) {
throw new Error("Missing USERNAME information")
}
if (!config.connect.authentication.options.password) {
throw new Error("Missing PASSWORD information")
}
/**
* Connects to a database server and if successful starts the metrics collection interval.
*
* @returns Promise<Connection>
*/
async function connect() {
return new Promise((resolve, reject) => {
debug("Connecting to database", config.connect.server);
let connection = new Connection(config.connect);
connection.on('connect', (error) => {
if (error) {
console.error("Failed to connect to database:", error.message || error);
reject(error);
} else {
debug("Connected to database");
resolve(connection);
}
});
connection.on('end', () => {
debug("Connection to database ended");
});
});
}
/**
* Recursive function that executes all collectors sequentially
*
* @param connection database connection
* @param collector single metric: {query: string, collect: function(rows, metric)}
*
* @returns Promise of collect operation (no value returned)
*/
async function measure(connection, collector) {
return new Promise((resolve) => {
let request = new Request(collector.query, (error, rowCount, rows) => {
if (!error) {
collector.collect(rows, collector.metrics);
resolve();
} else {
console.error("Error executing SQL query", collector.query, error);
resolve();
}
});
connection.execSql(request);
});
}
/**
* Function that collects from an active server. Should be called via setInterval setup.
*
* @param connection database connection
*
* @returns Promise of execution (no value returned)
*/
async function collect(connection) {
up.set(1);
for (let i = 0; i < metrics.length; i++) {
await measure(connection, metrics[i]);
}
}
app.get('/metrics', async (req, res) => {
res.contentType(client.register.contentType);
try {
let connection = await connect();
await collect(connection, metrics);
connection.close();
res.send(client.register.metrics());
} catch (error) {
// error connecting
up.set(0);
res.header("X-Error", error.message || error);
res.send(client.register.getSingleMetricAsString(up.name));
}
});
const server = app.listen(config.port, function () {
debug(`Prometheus-MSSQL Exporter listening on local port ${config.port} monitoring ${config.connect.userName}@${config.connect.server}:${config.connect.options.port}`);
});
process.on('SIGINT', function () {
server.close();
process.exit(0);
});