@zenvark/prom 1.1.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -7
- package/dist/get-or-create-metric.d.ts +2 -1
- package/dist/get-or-create-metric.js +8 -1
- package/dist/get-or-create-metric.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/prometheus-breaker-metrics.d.ts +11 -1
- package/dist/prometheus-breaker-metrics.js +26 -1
- package/dist/prometheus-breaker-metrics.js.map +1 -1
- package/dist/prometheus-semaphore-metrics.d.ts +46 -0
- package/dist/prometheus-semaphore-metrics.js +89 -0
- package/dist/prometheus-semaphore-metrics.js.map +1 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @zenvark/prom
|
|
2
2
|
|
|
3
|
-
Prometheus metrics integration for [Zenvark
|
|
3
|
+
Prometheus metrics integration for the [Zenvark](https://www.npmjs.com/package/zenvark) circuit breaker and adaptive semaphore.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -40,19 +40,56 @@ const circuitBreaker = new CircuitBreaker({
|
|
|
40
40
|
await circuitBreaker.start();
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
+
For the adaptive semaphore, pass `PrometheusSemaphoreMetrics` the same way:
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { AdaptiveSemaphore } from "zenvark";
|
|
47
|
+
import { PrometheusSemaphoreMetrics } from "@zenvark/prom";
|
|
48
|
+
import { register } from "prom-client";
|
|
49
|
+
|
|
50
|
+
const semaphore = new AdaptiveSemaphore({
|
|
51
|
+
id: "my-provider-api",
|
|
52
|
+
redis,
|
|
53
|
+
initialLimit: 10,
|
|
54
|
+
maxLimit: 1000,
|
|
55
|
+
metrics: new PrometheusSemaphoreMetrics({
|
|
56
|
+
registry: register,
|
|
57
|
+
customLabels: { service: "my-api", environment: "production" },
|
|
58
|
+
}),
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
43
62
|
## Available Metrics
|
|
44
63
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
|
48
|
-
|
|
|
49
|
-
| `
|
|
64
|
+
### Circuit breaker
|
|
65
|
+
|
|
66
|
+
| Metric | Type | Description | Labels |
|
|
67
|
+
| -------------------------------------- | --------- | -------------------------------------------- | ------------------------------ |
|
|
68
|
+
| `zenvark_call_duration_seconds` | Histogram | Duration of protected calls | `breaker_id`, `result` |
|
|
69
|
+
| `zenvark_blocked_requests_total` | Counter | Requests blocked by open circuit | `breaker_id` |
|
|
70
|
+
| `zenvark_healthcheck_duration_seconds` | Histogram | Health check attempt duration | `breaker_id`, `type`, `result` |
|
|
71
|
+
| `zenvark_state` | Gauge | Circuit state (active state 1, all others 0) | `breaker_id`, `state` |
|
|
72
|
+
|
|
73
|
+
### Semaphore
|
|
74
|
+
|
|
75
|
+
| Metric | Type | Description | Labels |
|
|
76
|
+
| ----------------------------------------- | --------- | ------------------------------------------- | ---------------------------------- |
|
|
77
|
+
| `zenvark_semaphore_acquire_wait_seconds` | Histogram | Time spent waiting for a lease | `semaphore_id`, `class`, `result` |
|
|
78
|
+
| `zenvark_semaphore_hold_duration_seconds` | Histogram | Time a lease was held | `semaphore_id`, `class`, `outcome` |
|
|
79
|
+
| `zenvark_semaphore_limit` | Gauge | This process's view of the fleet-wide limit | `semaphore_id` |
|
|
80
|
+
| `zenvark_semaphore_throttle_events_total` | Counter | Caller-reported throttle events | `semaphore_id` |
|
|
81
|
+
|
|
82
|
+
The limit gauge is set on every process whose cached view changes, so a scrape of any instance reads the current fleet-wide limit. Sum or average across instances accordingly.
|
|
50
83
|
|
|
51
84
|
### Label Values
|
|
52
85
|
|
|
53
86
|
- `breaker_id` - Circuit breaker instance identifier
|
|
54
87
|
- `type` - Health check type: `recovery` or `idle`
|
|
55
|
-
- `result` -
|
|
88
|
+
- `result` - Breaker call outcome (`success` or `failure`), or semaphore acquire outcome (`acquired` or `timeout`)
|
|
89
|
+
- `state` - Circuit state: `closed` or `open`
|
|
90
|
+
- `semaphore_id` - Semaphore instance identifier
|
|
91
|
+
- `class` - Semaphore priority class (empty when acquired without a class)
|
|
92
|
+
- `outcome` - Lease release outcome: `success`, `throttled` or `failure`
|
|
56
93
|
- Custom labels - Additional key-value pairs from configuration
|
|
57
94
|
|
|
58
95
|
## Custom Labels
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import { Counter, type CounterConfiguration, Histogram, type HistogramConfiguration, type Registry } from 'prom-client';
|
|
1
|
+
import { Counter, type CounterConfiguration, Gauge, type GaugeConfiguration, Histogram, type HistogramConfiguration, type Registry } from 'prom-client';
|
|
2
2
|
export declare const getOrCreateCounter: <TLabels extends string>(register: Registry, config: CounterConfiguration<TLabels>) => Counter<TLabels>;
|
|
3
3
|
export declare const getOrCreateHistogram: <TLabels extends string>(register: Registry, config: HistogramConfiguration<TLabels>) => Histogram<TLabels>;
|
|
4
|
+
export declare const getOrCreateGauge: <TLabels extends string>(register: Registry, config: GaugeConfiguration<TLabels>) => Gauge<TLabels>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Counter, Histogram, } from 'prom-client';
|
|
1
|
+
import { Counter, Gauge, Histogram, } from 'prom-client';
|
|
2
2
|
const getTypeParam = (obj) => {
|
|
3
3
|
if (typeof obj === 'object' &&
|
|
4
4
|
obj !== null &&
|
|
@@ -21,4 +21,11 @@ export const getOrCreateHistogram = (register, config) => {
|
|
|
21
21
|
const existingMetric = register.getSingleMetric(config.name);
|
|
22
22
|
return isHistogram(existingMetric) ? existingMetric : new Histogram(config);
|
|
23
23
|
};
|
|
24
|
+
const isGauge = (metric) => {
|
|
25
|
+
return metric instanceof Gauge || getTypeParam(metric) === 'gauge';
|
|
26
|
+
};
|
|
27
|
+
export const getOrCreateGauge = (register, config) => {
|
|
28
|
+
const existingMetric = register.getSingleMetric(config.name);
|
|
29
|
+
return isGauge(existingMetric) ? existingMetric : new Gauge(config);
|
|
30
|
+
};
|
|
24
31
|
//# sourceMappingURL=get-or-create-metric.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-or-create-metric.js","sourceRoot":"","sources":["../src/get-or-create-metric.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EAEP,SAAS,GAGV,MAAM,aAAa,CAAC;AAErB,MAAM,YAAY,GAAG,CAAC,GAAY,EAAsB,EAAE;IACxD,IACE,OAAO,GAAG,KAAK,QAAQ;QACvB,GAAG,KAAK,IAAI;QACZ,MAAM,IAAI,GAAG;QACb,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,EAC5B,CAAC;QACD,OAAO,GAAG,CAAC,IAAI,CAAC;IAClB,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,SAAS,GAAG,CAAC,MAAe,EAAqB,EAAE;IACvD,OAAO,MAAM,YAAY,OAAO,IAAI,YAAY,CAAC,MAAM,CAAC,KAAK,SAAS,CAAC;AACzE,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,QAAkB,EAClB,MAAqC,EACnB,EAAE;IACpB,MAAM,cAAc,GAAG,QAAQ,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAE7D,OAAO,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;AAC1E,CAAC,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,MAAe,EAAuB,EAAE;IAC3D,OAAO,MAAM,YAAY,SAAS,IAAI,YAAY,CAAC,MAAM,CAAC,KAAK,WAAW,CAAC;AAC7E,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,QAAkB,EAClB,MAAuC,EACnB,EAAE;IACtB,MAAM,cAAc,GAAG,QAAQ,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAE7D,OAAO,WAAW,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC;AAC9E,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"get-or-create-metric.js","sourceRoot":"","sources":["../src/get-or-create-metric.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EAEP,KAAK,EAEL,SAAS,GAGV,MAAM,aAAa,CAAC;AAErB,MAAM,YAAY,GAAG,CAAC,GAAY,EAAsB,EAAE;IACxD,IACE,OAAO,GAAG,KAAK,QAAQ;QACvB,GAAG,KAAK,IAAI;QACZ,MAAM,IAAI,GAAG;QACb,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,EAC5B,CAAC;QACD,OAAO,GAAG,CAAC,IAAI,CAAC;IAClB,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,SAAS,GAAG,CAAC,MAAe,EAAqB,EAAE;IACvD,OAAO,MAAM,YAAY,OAAO,IAAI,YAAY,CAAC,MAAM,CAAC,KAAK,SAAS,CAAC;AACzE,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,QAAkB,EAClB,MAAqC,EACnB,EAAE;IACpB,MAAM,cAAc,GAAG,QAAQ,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAE7D,OAAO,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;AAC1E,CAAC,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,MAAe,EAAuB,EAAE;IAC3D,OAAO,MAAM,YAAY,SAAS,IAAI,YAAY,CAAC,MAAM,CAAC,KAAK,WAAW,CAAC;AAC7E,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,QAAkB,EAClB,MAAuC,EACnB,EAAE;IACtB,MAAM,cAAc,GAAG,QAAQ,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAE7D,OAAO,WAAW,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC;AAC9E,CAAC,CAAC;AAEF,MAAM,OAAO,GAAG,CAAC,MAAe,EAAmB,EAAE;IACnD,OAAO,MAAM,YAAY,KAAK,IAAI,YAAY,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC;AACrE,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,QAAkB,EAClB,MAAmC,EACnB,EAAE;IAClB,MAAM,cAAc,GAAG,QAAQ,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAE7D,OAAO,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC;AACtE,CAAC,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
export { getOrCreateCounter, getOrCreateHistogram, } from './get-or-create-metric.ts';
|
|
2
2
|
export { PrometheusBreakerMetrics, type PrometheusBreakerMetricsOptions, } from './prometheus-breaker-metrics.ts';
|
|
3
|
+
export { PrometheusSemaphoreMetrics, type PrometheusSemaphoreMetricsOptions, } from './prometheus-semaphore-metrics.ts';
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { getOrCreateCounter, getOrCreateHistogram, } from "./get-or-create-metric.js";
|
|
2
2
|
export { PrometheusBreakerMetrics, } from "./prometheus-breaker-metrics.js";
|
|
3
|
+
export { PrometheusSemaphoreMetrics, } from "./prometheus-semaphore-metrics.js";
|
|
3
4
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,wBAAwB,GAEzB,MAAM,iCAAiC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,wBAAwB,GAEzB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,0BAA0B,GAE3B,MAAM,mCAAmC,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Registry } from 'prom-client';
|
|
2
|
-
import type { BreakerMetricsRecorder, RecordBlockedRequestParams, RecordCallParams, RecordHealthCheckParams } from 'zenvark';
|
|
2
|
+
import type { BreakerMetricsRecorder, RecordBlockedRequestParams, RecordCallParams, RecordHealthCheckParams, RecordStateChangeParams } from 'zenvark';
|
|
3
3
|
export type PrometheusBreakerMetricsOptions = {
|
|
4
4
|
/**
|
|
5
5
|
* Prometheus registry instance
|
|
@@ -19,6 +19,7 @@ export declare class PrometheusBreakerMetrics implements BreakerMetricsRecorder
|
|
|
19
19
|
private readonly callDurationHistogram;
|
|
20
20
|
private readonly blockedRequestsCounter;
|
|
21
21
|
private readonly healthcheckDurationHistogram;
|
|
22
|
+
private readonly stateGauge;
|
|
22
23
|
constructor(options: PrometheusBreakerMetricsOptions);
|
|
23
24
|
/**
|
|
24
25
|
* Initialize metrics for a circuit breaker.
|
|
@@ -38,4 +39,13 @@ export declare class PrometheusBreakerMetrics implements BreakerMetricsRecorder
|
|
|
38
39
|
* Record healthcheck attempt
|
|
39
40
|
*/
|
|
40
41
|
recordHealthCheck(params: RecordHealthCheckParams): void;
|
|
42
|
+
/**
|
|
43
|
+
* Record a circuit state change. Sets the active state label to 1 and all others to 0.
|
|
44
|
+
*/
|
|
45
|
+
recordStateChange(params: RecordStateChangeParams): void;
|
|
46
|
+
/**
|
|
47
|
+
* Remove all state gauge series for a breaker. Called when this node loses leadership
|
|
48
|
+
* so the ex-leader's stale values disappear from scrapes.
|
|
49
|
+
*/
|
|
50
|
+
clearState(breakerId: string): void;
|
|
41
51
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CircuitState } from 'zenvark';
|
|
2
|
+
import { getOrCreateCounter, getOrCreateGauge, getOrCreateHistogram, } from "./get-or-create-metric.js";
|
|
2
3
|
export class PrometheusBreakerMetrics {
|
|
3
4
|
customLabels;
|
|
4
5
|
callDurationHistogram;
|
|
5
6
|
blockedRequestsCounter;
|
|
6
7
|
healthcheckDurationHistogram;
|
|
8
|
+
stateGauge;
|
|
7
9
|
constructor(options) {
|
|
8
10
|
const prefix = options.prefix ?? 'zenvark';
|
|
9
11
|
this.customLabels = options.customLabels ?? {};
|
|
@@ -28,6 +30,12 @@ export class PrometheusBreakerMetrics {
|
|
|
28
30
|
buckets: [0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10],
|
|
29
31
|
registers: [options.registry],
|
|
30
32
|
});
|
|
33
|
+
this.stateGauge = getOrCreateGauge(options.registry, {
|
|
34
|
+
name: `${prefix}_state`,
|
|
35
|
+
help: 'Current state of the circuit breaker. The active state label has value 1, all others 0.',
|
|
36
|
+
labelNames: ['breaker_id', 'state', ...customLabelNames],
|
|
37
|
+
registers: [options.registry],
|
|
38
|
+
});
|
|
31
39
|
}
|
|
32
40
|
/**
|
|
33
41
|
* Initialize metrics for a circuit breaker.
|
|
@@ -70,5 +78,22 @@ export class PrometheusBreakerMetrics {
|
|
|
70
78
|
});
|
|
71
79
|
this.healthcheckDurationHistogram.observe(labels, params.durationMs / 1000);
|
|
72
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* Record a circuit state change. Sets the active state label to 1 and all others to 0.
|
|
83
|
+
*/
|
|
84
|
+
recordStateChange(params) {
|
|
85
|
+
for (const state of Object.values(CircuitState)) {
|
|
86
|
+
this.stateGauge.set(this.getLabels(params.breakerId, { state }), params.state === state ? 1 : 0);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Remove all state gauge series for a breaker. Called when this node loses leadership
|
|
91
|
+
* so the ex-leader's stale values disappear from scrapes.
|
|
92
|
+
*/
|
|
93
|
+
clearState(breakerId) {
|
|
94
|
+
for (const state of Object.values(CircuitState)) {
|
|
95
|
+
this.stateGauge.remove(this.getLabels(breakerId, { state }));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
73
98
|
}
|
|
74
99
|
//# sourceMappingURL=prometheus-breaker-metrics.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prometheus-breaker-metrics.js","sourceRoot":"","sources":["../src/prometheus-breaker-metrics.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"prometheus-breaker-metrics.js","sourceRoot":"","sources":["../src/prometheus-breaker-metrics.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Registry } from 'prom-client';
|
|
2
|
+
import type { RecordAcquireParams, RecordLimitChangeParams, RecordReleaseParams, RecordThrottleParams, SemaphoreMetricsRecorder } from 'zenvark';
|
|
3
|
+
export type PrometheusSemaphoreMetricsOptions = {
|
|
4
|
+
/**
|
|
5
|
+
* Prometheus registry instance
|
|
6
|
+
*/
|
|
7
|
+
registry: Registry;
|
|
8
|
+
/**
|
|
9
|
+
* Prefix for all metric names (default: 'zenvark')
|
|
10
|
+
*/
|
|
11
|
+
prefix?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Custom labels to add to all metrics
|
|
14
|
+
*/
|
|
15
|
+
customLabels?: Record<string, string>;
|
|
16
|
+
};
|
|
17
|
+
export declare class PrometheusSemaphoreMetrics implements SemaphoreMetricsRecorder {
|
|
18
|
+
private readonly customLabels;
|
|
19
|
+
private readonly acquireWaitHistogram;
|
|
20
|
+
private readonly holdDurationHistogram;
|
|
21
|
+
private readonly limitGauge;
|
|
22
|
+
private readonly throttleEventsCounter;
|
|
23
|
+
constructor(options: PrometheusSemaphoreMetricsOptions);
|
|
24
|
+
/**
|
|
25
|
+
* Initialize metrics for a semaphore.
|
|
26
|
+
* Sets the throttle counter to 0 so the metric appears in scrapes immediately.
|
|
27
|
+
*/
|
|
28
|
+
initialize(id: string): void;
|
|
29
|
+
private getLabels;
|
|
30
|
+
/**
|
|
31
|
+
* Record the outcome of an acquire attempt and the time spent waiting
|
|
32
|
+
*/
|
|
33
|
+
recordAcquire(params: RecordAcquireParams): void;
|
|
34
|
+
/**
|
|
35
|
+
* Record a lease release with its outcome and hold duration
|
|
36
|
+
*/
|
|
37
|
+
recordRelease(params: RecordReleaseParams): void;
|
|
38
|
+
/**
|
|
39
|
+
* Record a change of the cached fleet-wide limit
|
|
40
|
+
*/
|
|
41
|
+
recordLimitChange(params: RecordLimitChangeParams): void;
|
|
42
|
+
/**
|
|
43
|
+
* Record a caller-reported throttle event
|
|
44
|
+
*/
|
|
45
|
+
recordThrottle(params: RecordThrottleParams): void;
|
|
46
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { getOrCreateCounter, getOrCreateGauge, getOrCreateHistogram, } from "./get-or-create-metric.js";
|
|
2
|
+
export class PrometheusSemaphoreMetrics {
|
|
3
|
+
customLabels;
|
|
4
|
+
acquireWaitHistogram;
|
|
5
|
+
holdDurationHistogram;
|
|
6
|
+
limitGauge;
|
|
7
|
+
throttleEventsCounter;
|
|
8
|
+
constructor(options) {
|
|
9
|
+
const prefix = options.prefix ?? 'zenvark';
|
|
10
|
+
this.customLabels = options.customLabels ?? {};
|
|
11
|
+
const customLabelNames = Object.keys(this.customLabels);
|
|
12
|
+
this.acquireWaitHistogram = getOrCreateHistogram(options.registry, {
|
|
13
|
+
name: `${prefix}_semaphore_acquire_wait_seconds`,
|
|
14
|
+
help: 'Time spent waiting for a semaphore lease in seconds, by acquire result.',
|
|
15
|
+
labelNames: ['semaphore_id', 'class', 'result', ...customLabelNames],
|
|
16
|
+
buckets: [0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10],
|
|
17
|
+
registers: [options.registry],
|
|
18
|
+
});
|
|
19
|
+
this.holdDurationHistogram = getOrCreateHistogram(options.registry, {
|
|
20
|
+
name: `${prefix}_semaphore_hold_duration_seconds`,
|
|
21
|
+
help: 'Time a semaphore lease was held in seconds, by release outcome.',
|
|
22
|
+
labelNames: ['semaphore_id', 'class', 'outcome', ...customLabelNames],
|
|
23
|
+
buckets: [0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 30, 60],
|
|
24
|
+
registers: [options.registry],
|
|
25
|
+
});
|
|
26
|
+
this.limitGauge = getOrCreateGauge(options.registry, {
|
|
27
|
+
name: `${prefix}_semaphore_limit`,
|
|
28
|
+
help: "This process's cached view of the fleet-wide semaphore limit.",
|
|
29
|
+
labelNames: ['semaphore_id', ...customLabelNames],
|
|
30
|
+
registers: [options.registry],
|
|
31
|
+
});
|
|
32
|
+
this.throttleEventsCounter = getOrCreateCounter(options.registry, {
|
|
33
|
+
name: `${prefix}_semaphore_throttle_events_total`,
|
|
34
|
+
help: 'Total number of THROTTLED releases reported by callers.',
|
|
35
|
+
labelNames: ['semaphore_id', ...customLabelNames],
|
|
36
|
+
registers: [options.registry],
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Initialize metrics for a semaphore.
|
|
41
|
+
* Sets the throttle counter to 0 so the metric appears in scrapes immediately.
|
|
42
|
+
*/
|
|
43
|
+
initialize(id) {
|
|
44
|
+
const labels = this.getLabels(id);
|
|
45
|
+
this.throttleEventsCounter.inc(labels, 0);
|
|
46
|
+
}
|
|
47
|
+
getLabels(semaphoreId, additionalLabels = {}) {
|
|
48
|
+
return {
|
|
49
|
+
...this.customLabels,
|
|
50
|
+
semaphore_id: semaphoreId,
|
|
51
|
+
...additionalLabels,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Record the outcome of an acquire attempt and the time spent waiting
|
|
56
|
+
*/
|
|
57
|
+
recordAcquire(params) {
|
|
58
|
+
const labels = this.getLabels(params.id, {
|
|
59
|
+
class: params.class ?? '',
|
|
60
|
+
result: params.result,
|
|
61
|
+
});
|
|
62
|
+
this.acquireWaitHistogram.observe(labels, params.waitMs / 1000);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Record a lease release with its outcome and hold duration
|
|
66
|
+
*/
|
|
67
|
+
recordRelease(params) {
|
|
68
|
+
const labels = this.getLabels(params.id, {
|
|
69
|
+
class: params.class ?? '',
|
|
70
|
+
outcome: params.outcome,
|
|
71
|
+
});
|
|
72
|
+
this.holdDurationHistogram.observe(labels, params.heldMs / 1000);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Record a change of the cached fleet-wide limit
|
|
76
|
+
*/
|
|
77
|
+
recordLimitChange(params) {
|
|
78
|
+
const labels = this.getLabels(params.id);
|
|
79
|
+
this.limitGauge.set(labels, params.limit);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Record a caller-reported throttle event
|
|
83
|
+
*/
|
|
84
|
+
recordThrottle(params) {
|
|
85
|
+
const labels = this.getLabels(params.id);
|
|
86
|
+
this.throttleEventsCounter.inc(labels, 1);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=prometheus-semaphore-metrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prometheus-semaphore-metrics.js","sourceRoot":"","sources":["../src/prometheus-semaphore-metrics.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zenvark/prom",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Prometheus metrics for Zenvark Circuit Breaker",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"zenvark",
|
|
@@ -54,10 +54,10 @@
|
|
|
54
54
|
"rimraf": "^6.0.1",
|
|
55
55
|
"typescript": "5.9.3",
|
|
56
56
|
"vitest": "^4.0.15",
|
|
57
|
-
"zenvark": "^1.
|
|
57
|
+
"zenvark": "^1.3.0"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
60
|
"prom-client": "^15.0.0",
|
|
61
|
-
"zenvark": "^1.
|
|
61
|
+
"zenvark": "^1.2.0"
|
|
62
62
|
}
|
|
63
63
|
}
|