added whie-black-listing, http counter is a histogram now

This commit is contained in:
Konstantin Pogorelov
2016-04-19 00:48:23 +02:00
parent 32490462c0
commit 5ead531a59
6 changed files with 100 additions and 28 deletions

View File

@@ -1,4 +1,5 @@
advanced-example.js
docker-compose.yml
spec
.travis.yml
.eslintrc
.eslintrc

28
advanced-example.js Normal file
View File

@@ -0,0 +1,28 @@
"use strict";
const express = require("express"),
app = express(),
promBundle = require("express-prom-bundle"),
promClient = require("prom-client");
const bundle = promBundle({
prefix: "demo_app:something:",
blacklist: [/up/]
});
app.use(bundle);
let c1 = new bundle.promClient.Counter("c1", "c1 help");
c1.inc(10);
let c2 = bundle.factory.newCounter("c2", "c2 help");
c2.inc(20);
app.get("/foo", (req, res) => {
setTimeout(() => {
res.send("foo response");
}, 500);
});
app.get("/bar", (req, res) => res.send("bar response"));
app.listen(3001);

View File

@@ -1,6 +1,6 @@
{
"name": "express-prom-bundle",
"version": "1.0.0",
"version": "1.1.0",
"description": "express middleware with popular prometheus metrics in one bundle",
"main": "src/index.js",
"keywords": [

View File

@@ -9,7 +9,7 @@ describe("index", () => {
const app = express();
app.use(bundle({
prefix: "hello"
prefix: "hello:"
}));
it("/metrics returns up=1", done => {

View File

@@ -18,8 +18,7 @@ module.exports = class {
}
makeRealName(name) {
const prefix = this.opts.prefix ? (this.opts.prefix + ":") : "";
return prefix + name;
return (this.opts.prefix || "") + name;
}
makeMetric(TheClass, name, description, param) {

View File

@@ -1,7 +1,7 @@
"use strict";
const
PrometheusHelper = require("./PrometheusHelper"),
PromFactory = require("./PromFactory"),
onFinished = require("on-finished");
function filterArrayByRegExps(array, regexps) {
@@ -16,6 +16,21 @@ function filterArrayByRegExps(array, regexps) {
});
}
function prepareMetricNames(opts, metricTemplates) {
let names = Object.keys(metricTemplates);
if (opts.whitelist) {
if (opts.blacklist) {
throw new Error("you cannot have whitelist and blacklist at the same time");
}
return filterArrayByRegExps(names, opts.whitelist);
}
if (opts.blacklist) {
const blacklisted = filterArrayByRegExps(names, opts.blacklist);
return names.filter(name => blacklisted.indexOf(name) === -1);
}
return names;
}
function main(opts) {
if (arguments[2] && arguments[1] && arguments[1].send) {
arguments[1].status(500)
@@ -26,57 +41,86 @@ function main(opts) {
return;
}
let helper = new PrometheusHelper(opts);
let metricTemplates = {
"up": () => helper.newGauge(
let factory = new PromFactory(opts);
const metricTemplates = {
"up": () => factory.newGauge(
"up",
"1 = up, 0 = not up"
),
"nodejs_memory_heap_total_bytes": () => helper.newGauge(
"nodejs_memory_heap_total_bytes": () => factory.newGauge(
"nodejs_memory_heap_total_bytes",
"value of process.memoryUsage().heapTotal"
),
"nodejs_memory_heap_used_bytes": () => helper.newGauge(
"nodejs_memory_heap_used_bytes": () => factory.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"]
)
"http_request_duration": () => {
const metric = factory.newHistogram(
"http_request_duration",
"number of http responses labeled with status code",
{
labels: ["bar"],
buckets: [0.003, 0.03, 0.1, 0.3, 1.5, 10]
}
);
metric.labelNames = ["status_code"];
return metric;
}
};
const metrics = {};
const
metrics = {},
names = prepareMetricNames(opts, metricTemplates);
for (let name of Object.keys(metricTemplates)) {
for (let name of names) {
metrics[name] = metricTemplates[name]();
}
metrics.up.set(1);
if (metrics.up) {
metrics.up.set(1);
}
let middleware = function (req, res, next) {
let timer, labels;
if (metrics["http_request_duration"]) {
timer = metrics["http_request_duration"].startTimer(labels);
labels = {"status_code": 0};
}
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);
if (metrics["nodejs_memory_heap_total_bytes"]) {
metrics["nodejs_memory_heap_total_bytes"].set(memoryUsage.heapTotal);
}
if (metrics["nodejs_memory_heap_used_bytes"]) {
metrics["nodejs_memory_heap_used_bytes"].set(memoryUsage.heapUsed);
}
res.contentType("text/plain")
.send(helper.promClient.register.metrics());
.send(factory.promClient.register.metrics());
return;
}
onFinished(res, () => {
if (res.statusCode) {
metrics["http_request_total"].inc({"status_code": res.statusCode});
}
});
if (timer) {
onFinished(res, () => {
if (res.statusCode) {
labels["status_code"] = res.statusCode;
timer();
}
});
}
next();
};
middleware.helper = helper;
middleware.factory = factory;
middleware.metricTemplates = metricTemplates;
middleware.metrics = metrics;
middleware.promClient = factory.promClient;
return middleware;
}