Skip to content

Commit

Permalink
ran prettier (finally)
Browse files Browse the repository at this point in the history
  • Loading branch information
Pierre Awaragi committed Mar 20, 2022
1 parent 23f1b97 commit 1bfaea0
Show file tree
Hide file tree
Showing 7 changed files with 425 additions and 395 deletions.
3 changes: 3 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
node_modules/*
package-lock.json
yarn.lock

3 changes: 3 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"printWidth": 160
}
70 changes: 34 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,51 +1,48 @@
Prometheus MSSQL Exporter Docker Container
=============
# Prometheus MSSQL Exporter Docker Container

Prometheus exporter for Microsoft SQL Server (MSSQL). Exposes the following metrics

* mssql_instance_local_time Number of seconds since epoch on local instance
* mssql_connections{database,state} Number of active connections
* mssql_deadlocks Number of lock requests per second that resulted in a deadlock since last restart
* mssql_user_errors Number of user errors/sec since last restart
* mssql_kill_connection_errors Number of kill connection errors/sec since last restart
* mssql_database_state{database} State of each database (0=online 1=restoring 2=recovering 3=recovery pending 4=suspect 5=emergency 6=offline 7=copying 10=offline secondary)
* mssql_log_growths{database} Total number of times the transaction log for the database has been expanded last restart
* mssql_database_filesize{database,logicalname,type,filename} Physical sizes of files used by database in KB, their names and types (0=rows, 1=log, 2=filestream,3=n/a 4=fulltext(prior to version 2008 of MS SQL Server))
* mssql_page_life_expectancy Indicates the minimum number of seconds a page will stay in the buffer pool on this node without references. The traditional advice from Microsoft used to be that the PLE should remain above 300 seconds
* mssql_io_stall{database,type} Wait time (ms) of stall since last restart
* mssql_io_stall_total{database} Wait time (ms) of stall since last restart
* mssql_batch_requests Number of Transact-SQL command batches received per second. This statistic is affected by all constraints (such as I/O, number of users, cachesize, complexity of requests, and so on). High batch requests mean good throughput
* mssql_page_fault_count Number of page faults since last restart
* mssql_memory_utilization_percentage Percentage of memory utilization
* mssql_total_physical_memory_kb Total physical memory in KB
* mssql_available_physical_memory_kb Available physical memory in KB
* mssql_total_page_file_kb Total page file in KB
* mssql_available_page_file_kb Available page file in KB
- mssql_instance_local_time Number of seconds since epoch on local instance
- mssql_connections{database,state} Number of active connections
- mssql_deadlocks Number of lock requests per second that resulted in a deadlock since last restart
- mssql_user_errors Number of user errors/sec since last restart
- mssql_kill_connection_errors Number of kill connection errors/sec since last restart
- mssql_database_state{database} State of each database (0=online 1=restoring 2=recovering 3=recovery pending 4=suspect 5=emergency 6=offline 7=copying 10=offline secondary)
- mssql_log_growths{database} Total number of times the transaction log for the database has been expanded last restart
- mssql_database_filesize{database,logicalname,type,filename} Physical sizes of files used by database in KB, their names and types (0=rows, 1=log, 2=filestream,3=n/a 4=fulltext(prior to version 2008 of MS SQL Server))
- mssql_page_life_expectancy Indicates the minimum number of seconds a page will stay in the buffer pool on this node without references. The traditional advice from Microsoft used to be that the PLE should remain above 300 seconds
- mssql_io_stall{database,type} Wait time (ms) of stall since last restart
- mssql_io_stall_total{database} Wait time (ms) of stall since last restart
- mssql_batch_requests Number of Transact-SQL command batches received per second. This statistic is affected by all constraints (such as I/O, number of users, cachesize, complexity of requests, and so on). High batch requests mean good throughput
- mssql_page_fault_count Number of page faults since last restart
- mssql_memory_utilization_percentage Percentage of memory utilization
- mssql_total_physical_memory_kb Total physical memory in KB
- mssql_available_physical_memory_kb Available physical memory in KB
- mssql_total_page_file_kb Total page file in KB
- mssql_available_page_file_kb Available page file in KB

Please feel free to submit other interesting metrics to include.

> This exporter has been tested against MSSQL 2017 and 2019 docker images (only ones offered by Microsoft). Other versions might be work but have not been tested.
> This exporter has been tested against MSSQL 2017 and 2019 docker images (only ones offered by Microsoft). Other versions might be work but have not been tested.
Usage
-----
## Usage

`docker run -e SERVER=192.168.56.101 -e USERNAME=SA -e PASSWORD=qkD4x3yy -e DEBUG=app -p 4000:4000 --name prometheus-mssql-exporter awaragi/prometheus-mssql-exporter`

The image supports the following environments and exposes port 4000

* **SERVER** server ip or dns name (required)
* **PORT** server port (optional defaults to 1433)
* **USERNAME** access user (required)
* **PASSWORD** access password (required)
* **DEBUG** comma delimited list of enabled logs (optional currently supports app and metrics)
- **SERVER** server ip or dns name (required)
- **PORT** server port (optional defaults to 1433)
- **USERNAME** access user (required)
- **PASSWORD** access password (required)
- **DEBUG** comma delimited list of enabled logs (optional currently supports app and metrics)

It is **_required_** that the specified user has the following permissions

* GRANT VIEW ANY DEFINITION TO <user>
* GRANT VIEW SERVER STATE TO <user>
- GRANT VIEW ANY DEFINITION TO <user>
- GRANT VIEW SERVER STATE TO <user>

Development
-----------
## Development

## Launch a test mssql server

Expand All @@ -60,6 +57,7 @@ npm run test:mssql:2017
To use a persistent storage add `-v /mypath:/var/opt/mssql/data` to your version of package.json

## List all available metrics

```shell
node metrics.js
```
Expand All @@ -81,14 +79,14 @@ node metrics.js

### Using NodeJS

To execute and the application using locally running mssql (see above for how to launch a docker instance of mssql),
To execute and the application using locally running mssql (see above for how to launch a docker instance of mssql),
use the following command which will generate all a detailed logs

```shell
npm start
```

A more verbose execution with all queries and their results printed out
A more verbose execution with all queries and their results printed out

```shell
npm run start:verbose
Expand All @@ -110,7 +108,7 @@ Use curl or wget to fetch the metrics from launched web application.
curl http://localhost:4000/metrics
```

E2E test is available to execute against MSSQL 2017 or 2019 docker instances.
E2E test is available to execute against MSSQL 2017 or 2019 docker instances.
Any added metrics must get added to the e2e tests.

## Metric listing
Expand All @@ -123,4 +121,4 @@ node metrics.js

## building and pushing image to dockerhub

Use docker push or the bundled Github Workflows/Actions (see .github/workflows)
Use docker push or the bundled Github Workflows/Actions (see .github/workflows)
145 changes: 73 additions & 72 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,36 @@ const appLog = require("debug")("app");
const dbLog = require("debug")("db");
const queriesLog = require("debug")("queries");

const Connection = require('tedious').Connection;
const Request = require('tedious').Request;
const app = require('express')();
const Connection = require("tedious").Connection;
const Request = require("tedious").Request;
const app = require("express")();

const client = require('./metrics').client;
const mssql_up = require('./metrics').mssql_up;
const metrics = require('./metrics').metrics;
const client = require("./metrics").client;
const mssql_up = require("./metrics").mssql_up;
const metrics = require("./metrics").metrics;

let config = {
connect: {
server: process.env["SERVER"],
userName: process.env["USERNAME"],
password: process.env["PASSWORD"],
options: {
port: process.env["PORT"] || 1433,
encrypt: true,
rowCollectionOnRequestCompletion: true
}
connect: {
server: process.env["SERVER"],
userName: process.env["USERNAME"],
password: process.env["PASSWORD"],
options: {
port: parseInt(process.env["PORT"]) || 1433,
encrypt: true,
rowCollectionOnRequestCompletion: true,
},
port: process.env["EXPOSE"] || 4000
},
port: process.env["EXPOSE"] || 4000,
};

if (!config.connect.server) {
throw new Error("Missing SERVER information")
throw new Error("Missing SERVER information");
}
if (!config.connect.userName) {
throw new Error("Missing USERNAME information")
throw new Error("Missing USERNAME information");
}
if (!config.connect.password) {
throw new Error("Missing PASSWORD information")
throw new Error("Missing PASSWORD information");
}

/**
Expand All @@ -40,23 +40,22 @@ if (!config.connect.password) {
* @returns Promise<Connection>
*/
async function connect() {
return new Promise((resolve, reject) => {
dbLog("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 {
dbLog("Connected to database");
resolve(connection);
}
});
connection.on('end', () => {
dbLog("Connection to database ended");
});
return new Promise((resolve, reject) => {
dbLog("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 {
dbLog("Connected to database");
resolve(connection);
}
});

connection.on("end", () => {
dbLog("Connection to database ended");
});
});
}

/**
Expand All @@ -68,20 +67,20 @@ async function connect() {
* @returns Promise of collect operation (no value returned)
*/
async function measure(connection, collector) {
return new Promise((resolve) => {
queriesLog(`Executing query: ${collector.query}`);
let request = new Request(collector.query, (error, rowCount, rows) => {
if (!error) {
queriesLog(`Retrieved rows ${JSON.stringify(rows, null, 2)}`);
collector.collect(rows, collector.metrics);
resolve();
} else {
console.error("Error executing SQL query", collector.query, error);
resolve();
}
});
connection.execSql(request);
return new Promise((resolve) => {
queriesLog(`Executing query: ${collector.query}`);
let request = new Request(collector.query, (error, rowCount, rows) => {
if (!error) {
queriesLog(`Retrieved rows ${JSON.stringify(rows, null, 2)}`);
collector.collect(rows, collector.metrics);
resolve();
} else {
console.error("Error executing SQL query", collector.query, error);
resolve();
}
});
connection.execSql(request);
});
}

/**
Expand All @@ -92,36 +91,38 @@ async function measure(connection, collector) {
* @returns Promise of execution (no value returned)
*/
async function collect(connection) {
mssql_up.set(1);
for (let i = 0; i < metrics.length; i++) {
await measure(connection, metrics[i]);
}
mssql_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);
app.get("/metrics", async (req, res) => {
res.contentType(client.register.contentType);

try {
appLog("Received metrics request");
let connection = await connect();
await collect(connection, metrics);
connection.close();
res.send(client.register.metrics());
appLog("Successfully processed metrics request");
} catch (error) {
// error connecting
appLog("Error handling metrics request");
mssql_up.set(0);
res.header("X-Error", error.message || error);
res.send(client.register.getSingleMetricAsString(mssql_up.name));
}
try {
appLog("Received metrics request");
let connection = await connect();
await collect(connection, metrics);
connection.close();
res.send(client.register.metrics());
appLog("Successfully processed metrics request");
} catch (error) {
// error connecting
appLog("Error handling metrics request");
mssql_up.set(0);
res.header("X-Error", error.message || error);
res.send(client.register.getSingleMetricAsString(mssql_up.name));
}
});

const server = app.listen(config.port, function () {
appLog(`Prometheus-MSSQL Exporter listening on local port ${config.port} monitoring ${config.connect.userName}@${config.connect.server}:${config.connect.options.port}`);
appLog(
`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);
process.on("SIGINT", function () {
server.close();
process.exit(0);
});
Loading

0 comments on commit 1bfaea0

Please sign in to comment.