Compare commits
272 commits
Author | SHA1 | Date | |
---|---|---|---|
|
1a35138ed2 | ||
|
898adfbdc9 | ||
|
c1cbbc07ab | ||
|
709f74baf8 | ||
|
c09be24f0f | ||
|
50fd37ef54 | ||
|
3b582ea7b8 | ||
|
3fed2ecf7d | ||
|
58e71351ab | ||
|
a0a8f7301f | ||
|
9e789fc347 | ||
|
5925fedb53 | ||
|
f382e4e9a8 | ||
|
11f69ceb55 | ||
|
2849cd732c | ||
|
92f92e81fd | ||
|
99e03d73d0 | ||
|
ef35642f10 | ||
|
c37fad86f6 | ||
|
1349b4da25 | ||
|
c5c1434c77 | ||
|
26188855bb | ||
|
4f80e744b2 | ||
|
dac42d5ead | ||
|
3589832ad6 | ||
|
54cf7f5f24 | ||
|
b73f025548 | ||
|
fce96663db | ||
|
064d09ff70 | ||
|
af0296b7b3 | ||
|
3079103d03 | ||
|
3f15bae6a8 | ||
|
f72862b955 | ||
|
3bd5d1da4d | ||
|
9f94d50f1e | ||
|
cedf9b7af7 | ||
|
2b093b0fa2 | ||
|
ac5eb866d8 | ||
|
c0654ce76f | ||
|
52857f987c | ||
|
37246fa512 | ||
|
06222b4846 | ||
|
73d4b44522 | ||
|
9df9d347ad | ||
|
9379ec63fa | ||
|
0e29b88c32 | ||
|
2363bf25c4 | ||
|
d5b3fbdbb1 | ||
|
c36a5af463 | ||
|
2b859d8322 | ||
|
06c48fb317 | ||
|
a72d5948ab | ||
|
440b8455d3 | ||
|
fcb3767093 | ||
|
40c0a61ba6 | ||
|
9d9fbfb6b7 | ||
|
96084208bf | ||
|
60373593bf | ||
|
84b75d8c24 | ||
|
f7a753a86d | ||
|
cc162d9a56 | ||
|
704a353667 | ||
|
fc838ad93e | ||
|
303f397c83 | ||
|
72e7d6310d | ||
|
8425ab99db | ||
|
455844a4ed | ||
|
e5d9b7bfb9 | ||
|
fdbcfc27cf | ||
|
2641d455c1 | ||
|
d15fcfe557 | ||
|
2466225145 | ||
|
91592d5e21 | ||
|
77169d3f06 | ||
|
366e31ce17 | ||
|
543c130543 | ||
|
b7e0eae52f | ||
|
3d78d1cbc3 | ||
|
bba1ceb04a | ||
|
27d9c954ba | ||
|
3d31ca39ea | ||
|
995cec0974 | ||
|
9fae4246d0 | ||
|
7db8afc51c | ||
|
e0f3d4ca87 | ||
|
3a6fe1390d | ||
|
eca3bff6c3 | ||
|
7b110d609b | ||
|
486587fc86 | ||
|
c54cd9b871 | ||
|
b4210ec85d | ||
|
252fab726a | ||
|
e7343bd194 | ||
|
c4626d0186 | ||
|
03843eacf2 | ||
|
7b0be18923 | ||
|
9ce1163bc0 | ||
|
717b27c4e2 | ||
|
945568d91c | ||
|
ae9dc17e0f | ||
|
c18d79e662 | ||
|
17bcf3d4cf | ||
|
c8b70eeb27 | ||
|
a8c4a19808 | ||
|
05ad26f999 | ||
|
d1cf71869e | ||
|
d2cfdef13a | ||
|
539c202a83 | ||
|
d63f3fb465 | ||
|
6d217c3e95 | ||
|
d3f77a7180 | ||
|
be61660ab7 | ||
|
9126d38fea | ||
|
5515aaf590 | ||
|
2d5ba1d8f1 | ||
|
92155ae9b2 | ||
|
e216174dce | ||
|
dd983f9926 | ||
|
dc4c8d8d39 | ||
|
ec2025b768 | ||
|
c3f519ae4a | ||
|
acfb6e689e | ||
|
ccb89a9889 | ||
|
cb77478841 | ||
|
20b362a90c | ||
|
c392a82084 | ||
|
cbc6d971ac | ||
|
409c477d63 | ||
|
ea238c97f6 | ||
|
5ed6ee7d1e | ||
|
1c57adc4a0 | ||
|
890d1ef780 | ||
|
92f88d1fe9 | ||
|
bad4fa08b5 | ||
|
8646f816fc | ||
|
47eb77c6fd | ||
|
796eec97c2 | ||
|
b4512f25cc | ||
|
c2997d04d5 | ||
|
9c4964c1ae | ||
|
1ead5e54ef | ||
|
c73299f7b1 | ||
|
5d8dee811a | ||
|
d176ad2c9d | ||
|
d1a39d9838 | ||
|
a85bf04d0e | ||
|
0ccc4a8579 | ||
|
719ff9edd1 | ||
|
106daf044b | ||
|
f97a52b0a7 | ||
|
c07b8fdff8 | ||
|
84b23d6b14 | ||
|
9446ff2a16 | ||
|
92594538fa | ||
|
37a8545c5e | ||
|
47a097cc4d | ||
|
b5f8df30d8 | ||
|
df991fe5e5 | ||
|
eba5c42871 | ||
|
87721ec82a | ||
|
d76faf9197 | ||
|
dc71ce5ca4 | ||
|
579e973c66 | ||
|
9ea9576aa2 | ||
|
b88630e1ea | ||
|
82983a2827 | ||
|
0a58df5386 | ||
|
789f0ffea8 | ||
|
3063ea575c | ||
|
ddac01aea3 | ||
|
d4d0f412e4 | ||
|
5e0472c1f6 | ||
|
b254a33d47 | ||
|
b3eea21ecb | ||
|
454e3d1e89 | ||
|
2a578c5d1b | ||
|
0131f8a3f7 | ||
|
9bce041750 | ||
|
6f20f49855 | ||
|
fe6804d1e9 | ||
|
4008da12a8 | ||
|
49291172ac | ||
|
daf064caee | ||
|
ad5fe8b853 | ||
|
970b7129c0 | ||
|
520725ecd9 | ||
|
bcd798a057 | ||
|
9faea4df2c | ||
|
d6ca56b6e5 | ||
|
ab9c4fb17d | ||
|
00ccd46018 | ||
|
705c7f4f4f | ||
|
29801d3f81 | ||
|
8e71014357 | ||
|
e086844f3f | ||
|
80c64cf0e3 | ||
|
3b15f7f37a | ||
|
ac8caabcda | ||
|
cb415fa855 | ||
|
001aaf069a | ||
|
1ff3300a85 | ||
|
55b67bc1dd | ||
|
736cc88149 | ||
|
2f6f6c816c | ||
|
c85023b9d6 | ||
|
0322126616 | ||
|
6fe53182aa | ||
|
a7a39a4a1c | ||
|
9ab7f7f442 | ||
|
9e34c098cc | ||
|
5f25da655a | ||
|
710f2b07e7 | ||
|
93cf430c19 | ||
|
41ae48102c | ||
|
e08596d098 | ||
|
5166af0d25 | ||
|
e9c4c8fb29 | ||
|
540fad5757 | ||
|
891ae81a2c | ||
|
4af4035ce9 | ||
|
9213eb707b | ||
|
a794d7bf39 | ||
|
0df74d8ff0 | ||
|
e480235537 | ||
|
484280f497 | ||
|
5707c03cd4 | ||
|
4b7d9ee94e | ||
|
eddc283983 | ||
|
438ec423c4 | ||
|
a8cc8290e2 | ||
|
d70eb9064a | ||
|
06d74c57ce | ||
|
e99c4c57a2 | ||
|
744cd7ed4c | ||
|
cb8d04a2b2 | ||
|
317b8b598b | ||
|
c9c9ba45eb | ||
|
fe524c1f0a | ||
|
bbc21f4c6e | ||
|
bd17d79c0d | ||
|
de6ff2decd | ||
|
76a3ad9c7f | ||
|
33a7c9d0cf | ||
|
8935a2402c | ||
|
c5f289946c | ||
|
be7210d375 | ||
|
70468821ea | ||
|
cc19c0fe40 | ||
|
b4a263e4e4 | ||
|
f1746e47b3 | ||
|
3c9ecc1f65 | ||
|
67824f6a37 | ||
|
626ff1951b | ||
|
3f405e1a70 | ||
|
0b98217d3b | ||
|
8d16187a0a | ||
|
a850d1cbdf | ||
|
13d3867522 | ||
|
23a891be36 | ||
|
2acb8da732 | ||
|
92070192d8 | ||
|
3e9803c106 | ||
|
e780b319c7 | ||
|
f971f044b6 | ||
|
abba84e44b | ||
|
ed69818d61 | ||
|
64b180c059 | ||
|
482aa769a1 | ||
|
f8d4e43aef | ||
|
82506f8b45 | ||
|
b31833ad61 | ||
|
62f3bea6cb |
14 changed files with 5772 additions and 4235 deletions
1
.envrc
Normal file
1
.envrc
Normal file
|
@ -0,0 +1 @@
|
|||
use flake
|
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
|
@ -1 +1,2 @@
|
|||
github: lstrojny
|
||||
custom: ["https://paypal.me/larsstrojny"]
|
||||
|
|
14
.github/workflows/build.yml
vendored
14
.github/workflows/build.yml
vendored
|
@ -20,16 +20,16 @@ jobs:
|
|||
name: nodejs ${{ matrix.node-version }} (${{ matrix.lint && 'lint → ' || '' }}${{ matrix.tests && 'test → ' || '' }}build)
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3.2.0
|
||||
- uses: actions/checkout@v4.1.0
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v3.5.1
|
||||
uses: actions/setup-node@v3.8.1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: Cache node modules
|
||||
id: cache-npm
|
||||
uses: actions/cache@v3.0.11
|
||||
uses: actions/cache@v3.3.2
|
||||
env:
|
||||
cache-name: cache-node-modules
|
||||
with:
|
||||
|
@ -38,7 +38,7 @@ jobs:
|
|||
|
||||
- name: Cache eslint
|
||||
id: cache-eslint
|
||||
uses: actions/cache@v3.0.11
|
||||
uses: actions/cache@v3.3.2
|
||||
env:
|
||||
cache-name: cache-eslint
|
||||
with:
|
||||
|
@ -47,7 +47,7 @@ jobs:
|
|||
|
||||
- name: Cache TypeScript
|
||||
id: cache-typescript
|
||||
uses: actions/cache@v3.0.11
|
||||
uses: actions/cache@v3.3.2
|
||||
env:
|
||||
cache-name: cache-typescript
|
||||
with:
|
||||
|
@ -56,7 +56,7 @@ jobs:
|
|||
|
||||
- name: Cache prettier
|
||||
id: cache-prettier
|
||||
uses: actions/cache@v3.0.11
|
||||
uses: actions/cache@v3.3.2
|
||||
env:
|
||||
cache-name: cache-prettier
|
||||
with:
|
||||
|
@ -76,7 +76,7 @@ jobs:
|
|||
if: ${{ matrix.tests }}
|
||||
|
||||
- name: Upload code coverage
|
||||
uses: actions/upload-artifact@v3.1.1
|
||||
uses: actions/upload-artifact@v3.1.3
|
||||
with:
|
||||
name: code-coverage
|
||||
path: coverage/lcov.info
|
||||
|
|
28
.github/workflows/dependabot-automerge.yml
vendored
Normal file
28
.github/workflows/dependabot-automerge.yml
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
name: Dependabot auto merge
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: [CI]
|
||||
types:
|
||||
- completed
|
||||
|
||||
jobs:
|
||||
automerge:
|
||||
name: Auto merge "${{ github.event.workflow_run.head_branch }}"
|
||||
runs-on: ubuntu-22.04
|
||||
if: >
|
||||
github.event.workflow_run.event == 'pull_request'
|
||||
&& github.event.workflow_run.conclusion == 'success'
|
||||
&& github.actor == 'dependabot[bot]'
|
||||
&& startsWith(github.event.workflow_run.head_branch, 'dependabot/')
|
||||
steps:
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@v4.1.0
|
||||
with:
|
||||
ref: ${{ github.event.workflow_run.head_commit.id }}
|
||||
|
||||
- name: Instruct @dependabot to merge
|
||||
run: "gh issue comment $ISSUE_ID --body \"(This is an automated comment from workflow $WORKFLOW_URL)\n\n@dependabot squash and merge\""
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.DEPENDABOT_COMMENT_TOKEN }}
|
||||
ISSUE_ID: ${{ github.event.workflow_run.pull_requests[0].number }}
|
||||
WORKFLOW_URL: ${{ github.event.repository.html_url }}/actions/runs/${{ github.run_id }}
|
6
.github/workflows/sonar.yml
vendored
6
.github/workflows/sonar.yml
vendored
|
@ -1,4 +1,4 @@
|
|||
name: Sonar
|
||||
name: Sonar scan
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
|
@ -7,12 +7,12 @@ on:
|
|||
|
||||
jobs:
|
||||
sonar:
|
||||
name: Sonar
|
||||
name: Sonar scan on "${{ github.event.workflow_run.head_branch }}"
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.workflow_run.conclusion == 'success'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4.1.0
|
||||
with:
|
||||
repository: ${{ github.event.workflow_run.head_repository.full_name }}
|
||||
ref: ${{ github.event.workflow_run.head_branch }}
|
||||
|
|
14
README.md
14
README.md
|
@ -133,16 +133,22 @@ Once *Prometheus* is restarted, metrics with the `homebridge_` prefix should sta
|
|||
|
||||
|
||||
// Debug
|
||||
//
|
||||
// Default: false
|
||||
"debug": "<boolean>",
|
||||
|
||||
|
||||
// Metrics prefix
|
||||
//
|
||||
// Default: "homebridge"
|
||||
"prefix": "<string>",
|
||||
|
||||
|
||||
// Metrics server port
|
||||
//
|
||||
// TCP port where the Prometheus metrics server listens
|
||||
//
|
||||
// Default: 36123
|
||||
"port": "<integer>",
|
||||
|
||||
|
||||
|
@ -151,24 +157,32 @@ Once *Prometheus* is restarted, metrics with the `homebridge_` prefix should sta
|
|||
// Interface where the Prometheus metrics server listens. Can be an IP, a
|
||||
// hostname, "0.0.0.0" for all IPv4 interfaces, "::1" for all IPv6 interfaces.
|
||||
// Default is "::" which means "any interface"
|
||||
//
|
||||
// Default: "::"
|
||||
"interface": "<string>",
|
||||
|
||||
|
||||
// Service refresh interval
|
||||
//
|
||||
// Discover new services every <interval> seconds
|
||||
//
|
||||
// Default: 60
|
||||
"refresh_interval": "<integer>",
|
||||
|
||||
|
||||
// Request timeout
|
||||
//
|
||||
// Request timeout when interacting with homebridge instances
|
||||
//
|
||||
// Default: 10
|
||||
"request_timeout": "<integer>",
|
||||
|
||||
|
||||
// Service discovery timeout
|
||||
//
|
||||
// Discovery timeout after which the current discovery is considered failed
|
||||
//
|
||||
// Default: 20
|
||||
"discovery_timeout": "<integer>",
|
||||
|
||||
|
||||
|
|
|
@ -56,6 +56,9 @@ function generateDocs(schema) {
|
|||
if (definition.description) {
|
||||
lines.push(`//\n// ${wordwrap(definition.description, 80, '\n// ')}`)
|
||||
}
|
||||
if (definition.default !== undefined) {
|
||||
lines.push(`//\n// Default: ${JSON.stringify(definition.default)}`)
|
||||
}
|
||||
|
||||
lines.push(`${JSON.stringify(property)}: ${JSON.stringify('<' + definition.type + '>')}`)
|
||||
|
||||
|
|
9810
package-lock.json
generated
9810
package-lock.json
generated
File diff suppressed because it is too large
Load diff
21
package.json
21
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "homebridge-prometheus-exporter",
|
||||
"version": "1.0.1",
|
||||
"version": "1.0.5",
|
||||
"description": "Prometheus exporter for homebridge accessories.",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
|
@ -16,9 +16,10 @@
|
|||
},
|
||||
"main": "dist/src/index.js",
|
||||
"scripts": {
|
||||
"lint": "ifNotCi() { test \"$CI\" && echo \"$2\" || echo \"$1\"; }; npx tsc --noEmit && npx prettier --ignore-path=.gitignore `ifNotCi --write \"--check --cache --cache-strategy content\"` '**/**.{ts,js,json}' && npx eslint `ifNotCi --fix \"--cache --cache-strategy content\"` --ignore-path=.gitignore '**/**.{ts,js,json}'",
|
||||
"_portable_exec": "npmPortableExec() { `npm root`/.bin/$@; }; npmPortableExec",
|
||||
"lint": "ifNotCi() { test \"$CI\" && echo \"$2\" || echo \"$1\"; }; npm run _portable_exec -- tsc --noEmit && npm run _portable_exec -- prettier --ignore-path=.gitignore `ifNotCi --write \"--check --cache --cache-strategy content\"` '**/**.{ts,js,json}' && npm run _portable_exec -- eslint `ifNotCi --fix \"--cache --cache-strategy content\"` --ignore-path=.gitignore '**/**.{ts,js,json}'",
|
||||
"start": "npm run build && npm run link && nodemon",
|
||||
"test": "ifNotCi() { test \"$CI\" && echo \"$2\" || echo \"$1\"; }; npm run code-generation && npx jest `ifNotCi --watchAll --collect-coverage`",
|
||||
"test": "ifNotCi() { test \"$CI\" && echo \"$2\" || echo \"$1\"; }; npm run code-generation && npm run _portable_exec -- jest `ifNotCi --watchAll --collect-coverage`",
|
||||
"link": "npm install --no-save file:///$PWD/",
|
||||
"build": "rimraf ./dist .tsbuildinfo && npm run code-generation && tsc",
|
||||
"code-generation": "./code-generation/hap-gen.js && ./code-generation/config-scheme-gen.js",
|
||||
|
@ -34,10 +35,11 @@
|
|||
"devDependencies": {
|
||||
"@jest/globals": "^29.3.0",
|
||||
"@types/bcrypt": "^5.0.0",
|
||||
"@types/node": "^18.11.9",
|
||||
"@types/node": "^20.2.3",
|
||||
"@types/supertest": "^2.0.12",
|
||||
"@typescript-eslint/eslint-plugin": "^5.42.0",
|
||||
"@typescript-eslint/parser": "^5.42.0",
|
||||
"array.prototype.flatmap": "^1.3.1",
|
||||
"eslint": "^8.0.1",
|
||||
"eslint-import-resolver-typescript": "^3.5.2",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
|
@ -47,21 +49,22 @@
|
|||
"homebridge-cmdswitch2": "^0.2.10",
|
||||
"jest": "^29.3.0",
|
||||
"json-schema-to-zod": "^0.6.0",
|
||||
"nodemon": "^2.0.13",
|
||||
"nodemon": "^3.0.1",
|
||||
"prettier": "^2.7.1",
|
||||
"release-it": "^15.5.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"release-it": "^16.0.0",
|
||||
"rimraf": "^5.0.0",
|
||||
"supertest": "^6.3.1",
|
||||
"ts-jest": "^29.0.3",
|
||||
"ts-node": "^10.3.0",
|
||||
"typescript": "^4.4.4"
|
||||
"typescript": "^5.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fastify/auth": "^4.1.0",
|
||||
"@fastify/basic-auth": "^5.0.0",
|
||||
"array.prototype.group": "^1.1.2",
|
||||
"bcrypt": "^5.1.0",
|
||||
"fastify": "^4.9.2",
|
||||
"hap-node-client": "^0.1.25",
|
||||
"hap-node-client": "^0.2.1",
|
||||
"zod": "^3.19.1"
|
||||
}
|
||||
}
|
||||
|
|
10
src/ambient.d.ts
vendored
10
src/ambient.d.ts
vendored
|
@ -14,7 +14,11 @@ declare module 'hap-node-client' {
|
|||
}
|
||||
}
|
||||
|
||||
// Workaround for "node_modules/hap-nodejs/dist/lib/Advertiser.d.ts:5:29 - error TS7016: Could not find a declaration file for module '@homebridge/dbus-native'. '…/node_modules/@homebridge/dbus-native/index.js' implicitly has an 'any' type."
|
||||
declare module '@homebridge/dbus-native' {
|
||||
type InvokeError = unknown
|
||||
declare module 'array.prototype.group' {
|
||||
function shim(): void
|
||||
}
|
||||
|
||||
interface Array<T> {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
group<U>(fn: (value: T, index: number, array: T[]) => U, thisArg?: any): { U: T[] }
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ import type { Logger } from 'homebridge'
|
|||
import type { HttpConfig, HttpResponse, HttpServer } from './adapters/http'
|
||||
import type { Metric } from './metrics'
|
||||
import { strTrimRight } from './std'
|
||||
import { shim } from 'array.prototype.group'
|
||||
shim()
|
||||
|
||||
export class MetricsRenderer {
|
||||
private readonly prefix: string
|
||||
|
@ -10,17 +12,26 @@ export class MetricsRenderer {
|
|||
this.prefix = strTrimRight(prefix, '_')
|
||||
}
|
||||
|
||||
render(metric: Metric): string {
|
||||
const name = this.metricName(metric.name)
|
||||
return [
|
||||
`# TYPE ${name} ${name.endsWith('_total') ? 'counter' : 'gauge'}`,
|
||||
`${name}${this.renderLabels(metric.labels)} ${metric.value}${
|
||||
metric.timestamp !== null ? ' ' + String(metric.timestamp.getTime()) : ''
|
||||
}`,
|
||||
].join('\n')
|
||||
render(metrics: Metric[]): string {
|
||||
return (
|
||||
Object.entries(metrics.sort().group((metric) => this.metricName(metric.name)))
|
||||
.map(([name, metrics]) => {
|
||||
return [
|
||||
`# TYPE ${name} ${name.endsWith('_total') ? 'counter' : 'gauge'}`,
|
||||
metrics.map((metric) => this.formatMetric(metric)).join('\n'),
|
||||
].join('\n')
|
||||
})
|
||||
.join('\n\n') + '\n'
|
||||
)
|
||||
}
|
||||
|
||||
private renderLabels(labels: Metric['labels']): string {
|
||||
private formatMetric(metric: Metric): string {
|
||||
return `${this.metricName(metric.name)}${MetricsRenderer.renderLabels(metric.labels)} ${metric.value}${
|
||||
metric.timestamp !== null ? ' ' + String(metric.timestamp.getTime()) : ''
|
||||
}`
|
||||
}
|
||||
|
||||
private static renderLabels(labels: Metric['labels']): string {
|
||||
const rendered = Object.entries(labels)
|
||||
.map(([label, val]) => `${sanitizePrometheusMetricName(label)}="${escapeAttributeValue(val)}"`)
|
||||
.join(',')
|
||||
|
@ -91,7 +102,7 @@ export class PrometheusServer implements HttpServer {
|
|||
}
|
||||
|
||||
onMetricsDiscovery(metrics: Metric[]): void {
|
||||
this.metricsResponse = metrics.map((metric) => this.renderer.render(metric)).join('\n')
|
||||
this.metricsResponse = this.renderer.render(metrics)
|
||||
this.metricsDiscovered = true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,8 +71,10 @@ describe('Fastify HTTP adapter', () => {
|
|||
[
|
||||
'# TYPE homebridge_metric gauge',
|
||||
'homebridge_metric{name="metric"} 0.1 1577836800000',
|
||||
'',
|
||||
'# TYPE homebridge_something_total counter',
|
||||
'homebridge_something_total{name="counter"} 100 1577836800000',
|
||||
'',
|
||||
].join('\n'),
|
||||
)
|
||||
})
|
||||
|
@ -117,8 +119,10 @@ describe('Fastify HTTP adapter', () => {
|
|||
[
|
||||
'# TYPE homebridge_metric gauge',
|
||||
'homebridge_metric{name="metric"} 0.1 1577836800000',
|
||||
'',
|
||||
'# TYPE homebridge_something_total counter',
|
||||
'homebridge_something_total{name="counter"} 100 1577836800000',
|
||||
'',
|
||||
].join('\n'),
|
||||
)
|
||||
})
|
||||
|
|
|
@ -6,68 +6,94 @@ describe('Render prometheus metrics', () => {
|
|||
const renderer = new MetricsRenderer('prefix')
|
||||
|
||||
test('Renders simple metric', () => {
|
||||
expect(renderer.render(new Metric('metric', 0.000001))).toEqual(
|
||||
expect(renderer.render([new Metric('metric', 0.000001)])).toEqual(
|
||||
`# TYPE prefix_metric gauge
|
||||
prefix_metric 0.000001`,
|
||||
prefix_metric 0.000001
|
||||
`,
|
||||
)
|
||||
})
|
||||
|
||||
test('Renders simple metric with timestamp', () => {
|
||||
expect(renderer.render(new Metric('metric', 0.000001, new Date('2000-01-01 00:00:00 UTC')))).toEqual(
|
||||
expect(renderer.render([new Metric('metric', 0.000001, new Date('2000-01-01 00:00:00 UTC'))])).toEqual(
|
||||
`# TYPE prefix_metric gauge
|
||||
prefix_metric 0.000001 946684800000`,
|
||||
prefix_metric 0.000001 946684800000
|
||||
`,
|
||||
)
|
||||
})
|
||||
|
||||
test('Renders simple metric with labels', () => {
|
||||
expect(
|
||||
renderer.render(
|
||||
renderer.render([
|
||||
new Metric('metric', 0.000001, new Date('2000-01-01 00:00:00 UTC'), { label: 'Some Label' }),
|
||||
),
|
||||
]),
|
||||
).toEqual(
|
||||
`# TYPE prefix_metric gauge
|
||||
prefix_metric{label="Some Label"} 0.000001 946684800000`,
|
||||
prefix_metric{label="Some Label"} 0.000001 946684800000
|
||||
`,
|
||||
)
|
||||
})
|
||||
|
||||
test('Renders total as counter', () => {
|
||||
for (const metricName of ['some_total_metric', 'some_metric_total', 'total_some_metric']) {
|
||||
expect(
|
||||
renderer.render(
|
||||
renderer.render([
|
||||
new Metric(metricName, 42, new Date('2000-01-01 00:00:00 UTC'), { label: 'Some Label' }),
|
||||
),
|
||||
]),
|
||||
).toEqual(
|
||||
`# TYPE prefix_some_metric_total counter
|
||||
prefix_some_metric_total{label="Some Label"} 42 946684800000`,
|
||||
prefix_some_metric_total{label="Some Label"} 42 946684800000
|
||||
`,
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
test('Renders multiple metrics correctly', () => {
|
||||
expect(
|
||||
renderer.render([
|
||||
new Metric('some_gauge', 10, new Date('2000-01-01 00:00:00 UTC')),
|
||||
new Metric('another_gauge', 30, new Date('2000-01-01 00:00:00 UTC')),
|
||||
new Metric('some_gauge', 20, new Date('2000-01-01 00:00:00 UTC')),
|
||||
]),
|
||||
).toEqual(
|
||||
`# TYPE prefix_some_gauge gauge
|
||||
prefix_some_gauge 10 946684800000
|
||||
prefix_some_gauge 20 946684800000
|
||||
|
||||
# TYPE prefix_another_gauge gauge
|
||||
prefix_another_gauge 30 946684800000
|
||||
`,
|
||||
)
|
||||
})
|
||||
|
||||
test('Sanitizes metric names', () => {
|
||||
expect(renderer.render(new Metric('mätric name', 0))).toEqual(
|
||||
expect(renderer.render([new Metric('mätric name', 0)])).toEqual(
|
||||
`# TYPE prefix_m_tric_name gauge
|
||||
prefix_m_tric_name 0`,
|
||||
prefix_m_tric_name 0
|
||||
`,
|
||||
)
|
||||
})
|
||||
|
||||
test('Sanitizes label names', () => {
|
||||
expect(renderer.render(new Metric('metric', 0, null, { 'yet another label': 'foo' }))).toEqual(
|
||||
expect(renderer.render([new Metric('metric', 0, null, { 'yet another label': 'foo' })])).toEqual(
|
||||
`# TYPE prefix_metric gauge
|
||||
prefix_metric{yet_another_label="foo"} 0`,
|
||||
prefix_metric{yet_another_label="foo"} 0
|
||||
`,
|
||||
)
|
||||
})
|
||||
|
||||
test('Escapes newlines in attribute value', () => {
|
||||
expect(renderer.render(new Metric('metric', 0, null, { label: 'foo\nbar' }))).toEqual(
|
||||
expect(renderer.render([new Metric('metric', 0, null, { label: 'foo\nbar' })])).toEqual(
|
||||
`# TYPE prefix_metric gauge
|
||||
prefix_metric{label="foo\\nbar"} 0`,
|
||||
prefix_metric{label="foo\\nbar"} 0
|
||||
`,
|
||||
)
|
||||
})
|
||||
|
||||
test('Escapes quotes in attribute value', () => {
|
||||
expect(renderer.render(new Metric('metric', 0, null, { label: 'foo"bar' }))).toEqual(
|
||||
expect(renderer.render([new Metric('metric', 0, null, { label: 'foo"bar' })])).toEqual(
|
||||
`# TYPE prefix_metric gauge
|
||||
prefix_metric{label="foo\\"bar"} 0`,
|
||||
prefix_metric{label="foo\\"bar"} 0
|
||||
`,
|
||||
)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
"rootDir": "./",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"importsNotUsedAsValues": "error",
|
||||
"verbatimModuleSyntax": false,
|
||||
"noImplicitAny": true,
|
||||
"resolveJsonModule": true,
|
||||
"tsBuildInfoFile": ".tsbuildinfo",
|
||||
|
|
Loading…
Add table
Reference in a new issue