mirror of
https://github.com/BreizhHardware/express-prom-bundle.git
synced 2026-01-18 16:27:28 +01:00
intial
This commit is contained in:
42
.eslintrc
Normal file
42
.eslintrc
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"env": {
|
||||
"node": true,
|
||||
"es6": true
|
||||
},
|
||||
|
||||
"extends": "eslint:recommended",
|
||||
|
||||
"rules": {
|
||||
"no-cond-assign": 0,
|
||||
"no-constant-condition": 0,
|
||||
"no-empty": 0,
|
||||
"no-fallthrough": 0,
|
||||
"no-unused-vars": 1,
|
||||
"no-console": 1,
|
||||
|
||||
"semi": 2,
|
||||
"curly": 2,
|
||||
"consistent-this": [2, "self"],
|
||||
"indent": [ 2, 4, { "SwitchCase": 1 } ],
|
||||
"linebreak-style": [2, "unix"],
|
||||
"no-nested-ternary": 2,
|
||||
|
||||
"new-parens": 2,
|
||||
"no-dupe-class-members": 2,
|
||||
"require-yield": 2,
|
||||
"arrow-spacing": 1,
|
||||
"no-var": 2,
|
||||
|
||||
"no-multi-spaces": 1,
|
||||
"space-return-throw-case": 0,
|
||||
"space-infix-ops": [1, {"int32Hint": false}],
|
||||
"brace-style": 1,
|
||||
"space-before-blocks": 1,
|
||||
"operator-linebreak": [1, "before"],
|
||||
"no-unneeded-ternary": 1,
|
||||
"no-lonely-if": 1,
|
||||
"key-spacing": 1,
|
||||
"quotes": [1, "double", "avoid-escape"],
|
||||
"no-trailing-spaces": [1, { "skipBlankLines": true }]
|
||||
}
|
||||
}
|
||||
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
node_modules
|
||||
4
.npmignore
Normal file
4
.npmignore
Normal file
@@ -0,0 +1,4 @@
|
||||
docker-compose.yml
|
||||
test
|
||||
.travis.yml
|
||||
.eslintrc
|
||||
4
.travis.yml
Normal file
4
.travis.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "5"
|
||||
- "4"
|
||||
9
README.md
Normal file
9
README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# express prometheus bundle
|
||||
|
||||
A bundle of standard metrics for an express application.
|
||||
|
||||
Included metrics:
|
||||
|
||||
* **up**: normally is just 1
|
||||
* **nodejs_memory_heap_total_bytes** and **nodejs_memory_heap_used_bytes**
|
||||
* **http_request_total**: count of http requests labeled with status_code
|
||||
13
example.js
Normal file
13
example.js
Normal file
@@ -0,0 +1,13 @@
|
||||
"use strict";
|
||||
|
||||
const express = require("express"),
|
||||
app = express(),
|
||||
promBundle = require(".");
|
||||
|
||||
app.use(promBundle({
|
||||
prefix: "demo_app:something"
|
||||
}));
|
||||
|
||||
app.get("/hello", (req, res) => res.send("ok"));
|
||||
|
||||
app.listen(3000);
|
||||
21
package.json
Normal file
21
package.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "express-prom-bundle",
|
||||
"version": "1.0.0",
|
||||
"description": "express middleware with standard prometheus metrics in one bundle",
|
||||
"main": "src/index.js",
|
||||
"directories": {
|
||||
"test": "test"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "node_modules/jasme/run.js"
|
||||
},
|
||||
"author": "Konstantin Pogorelov <or@pluseq.com> (https://github.com/disjunction)",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"on-finished": "^2.3.0",
|
||||
"prom-client": "^3.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^2.8.0"
|
||||
}
|
||||
}
|
||||
51
src/PrometheusHelper.js
Normal file
51
src/PrometheusHelper.js
Normal file
@@ -0,0 +1,51 @@
|
||||
"use strict";
|
||||
|
||||
const onFinished = require("on-finished");
|
||||
|
||||
module.exports = class {
|
||||
constructor(opts, promClient) {
|
||||
this.opts = opts || {};
|
||||
this.promClient = this.opts.promClient || require("prom-client");
|
||||
this.metrics = {};
|
||||
}
|
||||
|
||||
metricExists(name) {
|
||||
return !!this.metrics[name];
|
||||
}
|
||||
|
||||
checkDuplicate(name) {
|
||||
if (this.metricExists(name)) {
|
||||
throw new Error("trying to add already existing metric: " + name);
|
||||
}
|
||||
}
|
||||
|
||||
makeRealName(name) {
|
||||
const prefix = this.opts.prefix ? (this.opts.prefix + ":") : "";
|
||||
return prefix + name;
|
||||
}
|
||||
|
||||
makeMetric(TheClass, name, description, param) {
|
||||
this.checkDuplicate(name);
|
||||
const realName = this.makeRealName(name);
|
||||
this.metrics[name] = new TheClass(
|
||||
realName, description, param
|
||||
);
|
||||
return this.metrics[name];
|
||||
}
|
||||
|
||||
newCounter(name, description, labels) {
|
||||
return this.makeMetric(this.promClient.Counter, name, description, labels);
|
||||
}
|
||||
|
||||
newGauge(name, description, labels) {
|
||||
return this.makeMetric(this.promClient.Gauge, name, description, labels);
|
||||
}
|
||||
|
||||
newHistogram(name, description, options) {
|
||||
return this.makeMetric(this.promClient.Histogram, name, description, options);
|
||||
}
|
||||
|
||||
newSummary(name, description, options) {
|
||||
return this.makeMetric(this.promClient.Histogram, name, description, options);
|
||||
}
|
||||
};
|
||||
84
src/index.js
Normal file
84
src/index.js
Normal file
@@ -0,0 +1,84 @@
|
||||
"use strict";
|
||||
|
||||
const
|
||||
PrometheusHelper = require("./PrometheusHelper"),
|
||||
onFinished = require("on-finished");
|
||||
|
||||
function filterArrayByRegExps(array, regexps) {
|
||||
let compiled = regexps.map(regexp => new RegExp(regexp));
|
||||
return array.filter(element => {
|
||||
for (let regexp of compiled) {
|
||||
if (element.match(regexp)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
function main(opts) {
|
||||
if (arguments[2] && arguments[1] && arguments[1].send) {
|
||||
arguments[1].status(500)
|
||||
.send("<h1>500 Error</h1>\n"
|
||||
+ "<p>Unexapected 3d param.\n"
|
||||
+ "<p>Did you just put express-prom-bundle into app.use "
|
||||
+ "without calling it as a function first?");
|
||||
return;
|
||||
}
|
||||
|
||||
let helper = new PrometheusHelper(opts);
|
||||
let metricTemplates = {
|
||||
"up": () => helper.newGauge(
|
||||
"up",
|
||||
"1 = up, 0 = not up"
|
||||
),
|
||||
"nodejs_memory_heap_total_bytes": () => helper.newGauge(
|
||||
"nodejs_memory_heap_total_bytes",
|
||||
"value of process.memoryUsage().heapTotal"
|
||||
),
|
||||
"nodejs_memory_heap_used_bytes": () => helper.newGauge(
|
||||
"nodejs_memory_heap_used_bytes",
|
||||
"value of process.memoryUsage().heapUsed"
|
||||
),
|
||||
"http_request_total": () => helper.newCounter(
|
||||
"http_request_total",
|
||||
"number of http responses labeled with status code",
|
||||
["status_code"]
|
||||
)
|
||||
};
|
||||
|
||||
const metrics = {};
|
||||
|
||||
for (let name of Object.keys(metricTemplates)) {
|
||||
metrics[name] = metricTemplates[name]();
|
||||
}
|
||||
|
||||
metrics.up.set(1);
|
||||
|
||||
let middleware = function (req, res, next) {
|
||||
if (req.path == "/metrics") {
|
||||
let memoryUsage = process.memoryUsage();
|
||||
metrics["nodejs_memory_heap_total_bytes"].set(memoryUsage.heapTotal);
|
||||
metrics["nodejs_memory_heap_used_bytes"].set(memoryUsage.heapUsed);
|
||||
|
||||
res.contentType("text/plain")
|
||||
.send(helper.promClient.register.metrics());
|
||||
return;
|
||||
}
|
||||
|
||||
onFinished(res, () => {
|
||||
if (res.statusCode) {
|
||||
metrics["http_request_total"].inc({"status_code": res.statusCode});
|
||||
}
|
||||
});
|
||||
|
||||
next();
|
||||
};
|
||||
|
||||
middleware.helper = helper;
|
||||
middleware.metricTemplates = metricTemplates;
|
||||
|
||||
return middleware;
|
||||
}
|
||||
|
||||
module.exports = main;
|
||||
Reference in New Issue
Block a user