{"_id":"@anxolin/express-prom-bundle","_rev":"1-f21aa21b9a1d88b46f6dba130779806c","name":"@anxolin/express-prom-bundle","dist-tags":{"latest":"6.0.0"},"versions":{"6.0.0":{"name":"@anxolin/express-prom-bundle","version":"6.0.0","description":"express middleware with popular prometheus metrics in one bundle","main":"src/index.js","keywords":["prometheus","metrics","express","path","method"],"types":"types","scripts":{"test":"node_modules/jasme/run.js","coverage":"make coverage","dtslint":"dtslint types"},"author":{"name":"Konstantin Pogorelov","email":"or@pluseq.com"},"license":"MIT","dependencies":{"on-finished":"^2.3.0","url-value-parser":"^2.0.0"},"devDependencies":{"@types/express":"^4.16.1","coveralls":"^3.0.2","dtslint":"^0.7.1","eslint":"^5.11.0","express":"^4.16.4","istanbul":"^0.4.5","jasme":"^6.0.0","koa":"^2.6.2","koa-connect":"^2.0.1","prom-client":"^12.0.0","supertest":"^3.3.0","supertest-koa-agent":"^0.3.0","typescript":"^3.4.5"},"peerDependencies":{"prom-client":"^12.0.0"},"repository":{"type":"git","url":"git+https://github.com/jochen-schweizer/express-prom-bundle.git"},"engines":{"node":">=10"},"gitHead":"f1f36f0fb71630b979f24a576d3cf6db7d59961b","bugs":{"url":"https://github.com/jochen-schweizer/express-prom-bundle/issues"},"homepage":"https://github.com/jochen-schweizer/express-prom-bundle#readme","_id":"@anxolin/express-prom-bundle@6.0.0","_npmVersion":"6.4.1","_nodeVersion":"10.15.1","_npmUser":{"name":"anxolin","email":"anxolin@gmail.com"},"dist":{"integrity":"sha512-/1EJ1ej9zL1Bc/mnbyafh67QbZ5lLNwZK7TfpJ93gSzqohoFad//9BxyVEuDoVMxTacZGn7wK/Ue3+nj/FZ1AA==","shasum":"1969682c1c8f009dd99ab414986565f59501c5fe","tarball":"https://registry.npmjs.org/@anxolin/express-prom-bundle/-/express-prom-bundle-6.0.0.tgz","fileCount":7,"unpackedSize":20346,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJesRlECRA9TVsSAnZWagAACP8P/1pxvHq3kD3/ZP6CvDFL\n14GxyMDvMa6hm+qgw3bM2886yENKE+yMoKde8IivbTDwao845V+d0blav7Ds\nmb3BQyk9o4YKpB7ykM8FdcigvWLIyfEafECL418cPGgTXFjIbJeuxsuc7Mbv\nfBmcKtJRfjR+IAThlNLUJCLtTyVSn09La4uWd/qrRE/NnxE+LIeRAN8Ld0Xa\noOL0QZ4j+4hiVMkRrBvIO4buS76KxS+F5o9VZMre2HMMyOVfsO9LUJeIFefD\nTG51R5cR978Rgn+SJoSrfQPrvHlN8/mNKEwbHYE2XKLCivjQUnqDD0dIL4lk\nMPXO9ar0zMZlZ2eI+rHxj3G/TKD2wND2dNUOF+7FAPD6YL/jcLPcEC18zUcc\nDgSwFFP3tOEorL4KQY3PTuyeh6Bx3FR+AhtBtMUHOMUWDyoG9Cr3sp/J5qfu\n6OFEFya9OjpDKz8GFoBTQU/eWI0sFgJnKYrq4YwUsQC2aTmcUKT6xgoaiEoN\nBkXoJsvB6/Lid4R4JtCoaGz+I4nQQQvNGNnBAieVryxZIZI7EKm0FieX2uOM\n3DDNGVmRUKkn0rOzv2uVyxY6MFsb9rzlyDYVd+2mJf7Q8jOcSEbMSO2LhN0n\nHp9+78r2wRfFhjgyQSOXfSOuirwm6JIfNWZ7E37fvQGbFimlQH4LVkBI9RR4\nksA0\r\n=k54v\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCtiw30VkWjceRAjM8cYhv0HTD9gQDhEGUyDvlgpZ9uuwIga7oohNFOOhXcO4xKLeYqFamuNTeo655XriPeWd5OZ7k="}]},"maintainers":[{"name":"anxolin","email":"anxolin@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/express-prom-bundle_6.0.0_1588664644218_0.4394777209112266"},"_hasShrinkwrap":false}},"time":{"created":"2020-05-05T07:44:04.180Z","6.0.0":"2020-05-05T07:44:04.335Z","modified":"2022-04-04T14:26:15.373Z"},"maintainers":[{"name":"anxolin","email":"anxolin@gmail.com"}],"description":"express middleware with popular prometheus metrics in one bundle","homepage":"https://github.com/jochen-schweizer/express-prom-bundle#readme","keywords":["prometheus","metrics","express","path","method"],"repository":{"type":"git","url":"git+https://github.com/jochen-schweizer/express-prom-bundle.git"},"author":{"name":"Konstantin Pogorelov","email":"or@pluseq.com"},"bugs":{"url":"https://github.com/jochen-schweizer/express-prom-bundle/issues"},"license":"MIT","readme":"[![build status](https://travis-ci.org/jochen-schweizer/express-prom-bundle.png)](https://travis-ci.org/jochen-schweizer/express-prom-bundle) [![Coverage Status](https://coveralls.io/repos/github/jochen-schweizer/express-prom-bundle/badge.svg?branch=master)](https://coveralls.io/github/jochen-schweizer/express-prom-bundle?branch=master) [![license](https://img.shields.io/github/license/mashape/apistatus.svg?maxAge=2592000)](https://www.tldrlegal.com/l/mit) [![NPM version](https://badge.fury.io/js/express-prom-bundle.png)](http://badge.fury.io/js/express-prom-bundle)\n\n# express prometheus bundle\n\nExpress middleware with popular prometheus metrics in one bundle. It's also compatible with koa v1 and v2 (see below).\n\nSince version 5 it uses **prom-client** as a peer dependency. See: https://github.com/siimon/prom-client\n\nIncluded metrics:\n\n* `up`: normally is just 1\n* `http_request_duration_seconds`: http latency histogram/summary labeled with `status_code`, `method` and `path`\n\n## Install\n\n```\nnpm install prom-client express-prom-bundle\n```\n\n## Sample Usage\n\n```javascript\nconst promBundle = require(\"express-prom-bundle\");\nconst app = require(\"express\")();\nconst metricsMiddleware = promBundle({includeMethod: true});\n\napp.use(metricsMiddleware);\napp.use(/* your middleware */);\napp.listen(3000);\n```\n\n* call your endpoints\n* see your metrics here: [http://localhost:3000/metrics](http://localhost:3000/metrics)\n\n**ALERT!**\n\nThe order in which the routes are registered is important, since\n**only the routes registered after the express-prom-bundle will be measured**\n\nYou can use this to your advantage to bypass some of the routes.\nSee the example below.\n\n## Options\n\nWhich labels to include in `http_request_duration_seconds` metric:\n\n* **includeStatusCode**: HTTP status code (200, 400, 404 etc.), default: **true**\n* **includeMethod**: HTTP method (GET, PUT, ...), default: **false**\n* **includePath**: URL path (see importent details below), default: **false**\n* **customLabels**: an object containing extra labels, e.g. ```{project_name: 'hello_world'}```.\n  Most useful together with **transformLabels** callback, otherwise it's better to use native Prometheus relabeling.\n* **includeUp**: include an auxiliary \"up\"-metric which always returns 1, default: **true**\n* **metricsPath**: replace the `/metrics` route with a **regex** or exact **string**. Note: it is highly recommended to just stick to the default\n* **metricType**: histogram/summary selection. See more details below\n\n### metricType option ###\n\nTwo metric types are supported for `http_request_duration_seconds` metric:\n* [histogram](https://prometheus.io/docs/concepts/metric_types/#histogram) (default)\n* [summary](https://prometheus.io/docs/concepts/metric_types/#summary)\n\nAdditional options for **histogram**:\n* **buckets**: buckets used for the `http_request_duration_seconds` histogram\n\nAdditional options for **summary**:\n* **percentiles**: percentiles used for `http_request_duration_seconds` summary\n* **ageBuckets**: ageBuckets configures how many buckets we have in our sliding window for the summary\n* **maxAgeSeconds**: the maxAgeSeconds will tell how old a bucket can be before it is reset\n\n### Transformation callbacks ###\n\n* **normalizePath**: `function(req)`  or `Array`\n  * if function is provided, then it should generate path value from express `req`\n  * if array is provided, then it should be an array of tuples `[regex, replacement]`. The `regex` can be a string and is automatically converted into JS regex.\n  * ... see more details in the section below\n* **urlValueParser**: options passed when instantiating [url-value-parser](https://github.com/disjunction/url-value-parser).\n  This is the easiest way to customize which parts of the URL should be replaced with \"#val\".\n  See the [docs](https://github.com/disjunction/url-value-parser) of url-value-parser module for details.\n* **formatStatusCode**: `function(res)` producing final status code from express `res` object, e.g. you can combine `200`, `201` and `204` to just `2xx`.\n* **transformLabels**: `function(labels, req, res)` transforms the **labels** object, e.g. setting dynamic values to **customLabels**\n\n### Other options ###\n\n* **autoregister**: if `/metrics` endpoint should be registered. (Default: **true**)\n* **promClient**: options for promClient startup, e.g. **collectDefaultMetrics**. This option was added\n  to keep `express-prom-bundle` runnable using confit (e.g. with kraken.js) without writing any JS code,\n  see [advanced example](https://github.com/jochen-schweizer/express-prom-bundle/blob/master/advanced-example.js)\n\n### More details on includePath option\n\nLet's say you want to have  latency statistics by URL path,\ne.g. separate metrics for `/my-app/user/`, `/products/by-category` etc.\n\nJust taking `req.path` as a label value won't work as IDs are often part of the URL,\nlike `/user/12352/profile`. So what we actually need is a path template.\nThe module tries to figure out what parts of the path are values or IDs,\nand what is an actual path. The example mentioned before would be\nnormalized to `/user/#val/profile` and that will become the value for the label.\nThese conversions are handled by `normalizePath` function.\n\nYou can extend this magical behavior by providing\nadditional RegExp rules to be performed,\nor override `normalizePath` with your own function.\n\n#### Example 1 (add custom RegExp):\n\n```javascript\napp.use(promBundle({\n  normalizePath: [\n    // collect paths like \"/customer/johnbobson\" as just one \"/custom/#name\"\n    ['^/customer/.*', '/customer/#name'],\n\n    // collect paths like \"/bobjohnson/order-list\" as just one \"/#name/order-list\"\n    ['^.*/order-list', '/#name/order-list']\n  ],\n  urlValueParser: {\n    minHexLength: 5,\n    extraMasks: [\n      'ORD[0-9]{5,}' // replace strings like ORD1243423, ORD673562 as #val\n    ]\n  }\n}));\n```\n\n#### Example 2 (override normalizePath function):\n\n```javascript\napp.use(promBundle(/* options? */));\n\n// let's reuse the existing one and just add some\n// functionality on top\nconst originalNormalize = promBundle.normalizePath;\npromBundle.normalizePath = (req, opts) => {\n  const path = originalNormalize(req, opts);\n  // count all docs as one path, but /docs/login as a separate one\n  return (path.match(/^\\/docs/) && !path.match(/^\\/login/)) ? '/docs/*' : path;\n};\n```\n\nFor more details:\n * [url-value-parser](https://www.npmjs.com/package/url-value-parser) - magic behind automatic path normalization\n * [normalizePath.js](https://github.com/jochen-schweizer/express-prom-bundle/blob/master/src/normalizePath.js) - source code for path processing\n\n\n## express example\n\nsetup std. metrics but exclude `up`-metric:\n\n```javascript\nconst express = require(\"express\");\nconst app = express();\nconst promBundle = require(\"express-prom-bundle\");\n\n// calls to this route will not appear in metrics\n// because it's applied before promBundle\napp.get(\"/status\", (req, res) => res.send(\"i am healthy\"));\n\n// register metrics collection for all routes\n// ... except those starting with /foo\napp.use(\"/((?!foo))*\", promBundle({includePath: true}));\n\n// this call will NOT appear in metrics,\n// because express will skip the metrics middleware\napp.get(\"/foo\", (req, res) => res.send(\"bar\"));\n\n// calls to this route will appear in metrics\napp.get(\"/hello\", (req, res) => res.send(\"ok\"));\n\napp.listen(3000);\n```\n\nSee an [advanced example on github](https://github.com/jochen-schweizer/express-prom-bundle/blob/master/advanced-example.js)\n\n## koa v2 example\n\n```javascript\nconst promBundle = require(\"express-prom-bundle\");\nconst Koa = require(\"koa\");\nconst c2k = require(\"koa-connect\");\nconst metricsMiddleware = promBundle({/* options */ });\n\nconst app = new Koa();\n\napp.use(c2k(metricsMiddleware));\napp.use(/* your middleware */);\napp.listen(3000);\n```\n\n## using with cluster\n\nYou'll need to use an additional **clusterMetrics()** middleware.\n\nIn the example below the master process will expose an API with a single endpoint `/metrics`\nwhich returns an aggregate of all metrics from all the workers.\n\n``` javascript\nconst cluster = require('cluster');\nconst promBundle = require('./src/index');\nconst numCPUs = Math.max(2, require('os').cpus().length);\nconst express = require('express');\n\nif (cluster.isMaster) {\n    for (let i = 1; i < numCPUs; i++) {\n        cluster.fork();\n    }\n\n    const metricsApp = express();\n    metricsApp.use('/metrics', promBundle.clusterMetrics());\n    metricsApp.listen(9999);\n\n    console.log('cluster metrics listening on 9999');\n    console.log('call localhost:9999/metrics for aggregated metrics');\n} else {\n    const app = express();\n    app.use(promBundle({\n        autoregister: false, // disable /metrics for single workers\n        includeMethod: true\n    }));\n    app.use((req, res) => res.send(`hello from pid ${process.pid}\\n`));\n    app.listen(3000);\n    console.log(`worker ${process.pid} listening on 3000`);\n}\n```\n\n## using with kraken.js\n\nHere is meddleware config sample, which can be used in a standard **kraken.js** application.\nIn this case the stats for URI paths and HTTP methods are collected separately,\nwhile replacing all HEX values starting from 5 characters and all IP addresses in the path as #val.\n\n```json\n{\n  \"middleware\": {\n    \"expressPromBundle\": {\n      \"route\": \"/((?!status|favicon.ico|robots.txt))*\",\n      \"priority\": 0,\n      \"module\": {\n        \"name\": \"express-prom-bundle\",\n        \"arguments\": [\n          {\n            \"includeMethod\": true,\n            \"includePath\": true,\n            \"buckets\": [0.1, 1, 5],\n            \"promClient\": {\n              \"collectDefaultMetrics\": {\n              }\n            },\n            \"urlValueParser\": {\n              \"minHexLength\": 5,\n              \"extraMasks\": [\n                \"^[0-9]+\\\\.[0-9]+\\\\.[0-9]+\\\\.[0-9]+$\"\n              ]\n            }\n          }\n        ]\n      }\n    }\n  }\n}\n```\n\n## License\n\nMIT\n","readmeFilename":"README.md"}