@nestjs-redisx/metrics 1.0.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/LICENSE +21 -0
- package/README.md +46 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +352 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +325 -0
- package/dist/index.mjs.map +1 -0
- package/dist/metrics/api/controllers/metrics.controller.d.ts +7 -0
- package/dist/metrics/api/controllers/metrics.controller.d.ts.map +1 -0
- package/dist/metrics/application/ports/index.d.ts +2 -0
- package/dist/metrics/application/ports/index.d.ts.map +1 -0
- package/dist/metrics/application/ports/metrics-service.port.d.ts +15 -0
- package/dist/metrics/application/ports/metrics-service.port.d.ts.map +1 -0
- package/dist/metrics/application/services/metrics.service.d.ts +31 -0
- package/dist/metrics/application/services/metrics.service.d.ts.map +1 -0
- package/dist/metrics.plugin.d.ts +47 -0
- package/dist/metrics.plugin.d.ts.map +1 -0
- package/dist/shared/constants/index.d.ts +4 -0
- package/dist/shared/constants/index.d.ts.map +1 -0
- package/dist/shared/errors/index.d.ts +8 -0
- package/dist/shared/errors/index.d.ts.map +1 -0
- package/dist/shared/types/index.d.ts +68 -0
- package/dist/shared/types/index.d.ts.map +1 -0
- package/package.json +73 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 NestJS RedisX Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/nestjs-redisx/nestjs-redisx/main/website/public/images/logo.png" alt="NestJS RedisX" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# @nestjs-redisx/metrics
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/@nestjs-redisx/metrics)
|
|
8
|
+
[](https://www.npmjs.com/package/@nestjs-redisx/metrics)
|
|
9
|
+
[](https://opensource.org/licenses/MIT)
|
|
10
|
+
|
|
11
|
+
Prometheus metrics plugin for NestJS RedisX. Exposes Redis command latencies, connection pool stats, cache hit rates, and custom metrics via a `/metrics` endpoint. `prom-client` is bundled.
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @nestjs-redisx/core @nestjs-redisx/metrics ioredis
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Example
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { RedisModule } from '@nestjs-redisx/core';
|
|
23
|
+
import { MetricsPlugin } from '@nestjs-redisx/metrics';
|
|
24
|
+
|
|
25
|
+
@Module({
|
|
26
|
+
imports: [
|
|
27
|
+
RedisModule.forRoot({
|
|
28
|
+
clients: { host: 'localhost', port: 6379 },
|
|
29
|
+
plugins: [
|
|
30
|
+
new MetricsPlugin({ prefix: 'redisx_', exposeEndpoint: true }),
|
|
31
|
+
],
|
|
32
|
+
}),
|
|
33
|
+
],
|
|
34
|
+
})
|
|
35
|
+
export class AppModule {}
|
|
36
|
+
|
|
37
|
+
// Scrape: curl http://localhost:3000/metrics
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Documentation
|
|
41
|
+
|
|
42
|
+
Full documentation: [nestjs-redisx.dev/en/reference/metrics/](https://nestjs-redisx.dev/en/reference/metrics/)
|
|
43
|
+
|
|
44
|
+
## License
|
|
45
|
+
|
|
46
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { MetricsPlugin } from './metrics.plugin';
|
|
2
|
+
export { MetricsService } from './metrics/application/services/metrics.service';
|
|
3
|
+
export type { IMetricsService } from './metrics/application/ports';
|
|
4
|
+
export { MetricsController } from './metrics/api/controllers/metrics.controller';
|
|
5
|
+
export type { IMetricsPluginOptions, IMetricsJson } from './shared/types';
|
|
6
|
+
export { MetricsError, MetricRegistrationError } from './shared/errors';
|
|
7
|
+
export { METRICS_PLUGIN_OPTIONS, METRICS_SERVICE, METRICS_REGISTRY } from './shared/constants';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGjD,OAAO,EAAE,cAAc,EAAE,MAAM,gDAAgD,CAAC;AAGhF,YAAY,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAGnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,8CAA8C,CAAC;AAGjF,YAAY,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG1E,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAGxE,OAAO,EAAE,sBAAsB,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var common = require('@nestjs/common');
|
|
4
|
+
var promClient = require('prom-client');
|
|
5
|
+
var core = require('@nestjs-redisx/core');
|
|
6
|
+
|
|
7
|
+
function _interopNamespace(e) {
|
|
8
|
+
if (e && e.__esModule) return e;
|
|
9
|
+
var n = Object.create(null);
|
|
10
|
+
if (e) {
|
|
11
|
+
Object.keys(e).forEach(function (k) {
|
|
12
|
+
if (k !== 'default') {
|
|
13
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
14
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
get: function () { return e[k]; }
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
n.default = e;
|
|
22
|
+
return Object.freeze(n);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
var promClient__namespace = /*#__PURE__*/_interopNamespace(promClient);
|
|
26
|
+
|
|
27
|
+
var __defProp = Object.defineProperty;
|
|
28
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
29
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
30
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
31
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
32
|
+
if (decorator = decorators[i])
|
|
33
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
34
|
+
if (kind && result) __defProp(target, key, result);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
|
|
38
|
+
|
|
39
|
+
// src/shared/constants/index.ts
|
|
40
|
+
var METRICS_PLUGIN_OPTIONS = /* @__PURE__ */ Symbol.for("METRICS_PLUGIN_OPTIONS");
|
|
41
|
+
var METRICS_SERVICE = /* @__PURE__ */ Symbol.for("METRICS_SERVICE");
|
|
42
|
+
var METRICS_REGISTRY = /* @__PURE__ */ Symbol.for("METRICS_REGISTRY");
|
|
43
|
+
var MetricsError = class extends core.RedisXError {
|
|
44
|
+
constructor(message, cause) {
|
|
45
|
+
super(message, core.ErrorCode.OP_FAILED, cause);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
var MetricRegistrationError = class extends MetricsError {
|
|
49
|
+
constructor(metricName, cause) {
|
|
50
|
+
super(`Failed to register metric "${metricName}"`, cause);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// src/metrics/application/services/metrics.service.ts
|
|
55
|
+
exports.MetricsService = class MetricsService {
|
|
56
|
+
constructor(config) {
|
|
57
|
+
this.config = config;
|
|
58
|
+
this.enabled = config.enabled !== false;
|
|
59
|
+
this.prefix = config.prefix ?? "redisx_";
|
|
60
|
+
this.defaultLabels = config.defaultLabels ?? {};
|
|
61
|
+
this.latencyBuckets = config.histogramBuckets ?? [1e-3, 5e-3, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10];
|
|
62
|
+
this.registry = new promClient__namespace.Registry();
|
|
63
|
+
this.registry.setDefaultLabels(this.defaultLabels);
|
|
64
|
+
}
|
|
65
|
+
registry;
|
|
66
|
+
counters = /* @__PURE__ */ new Map();
|
|
67
|
+
histograms = /* @__PURE__ */ new Map();
|
|
68
|
+
gauges = /* @__PURE__ */ new Map();
|
|
69
|
+
prefix;
|
|
70
|
+
defaultLabels;
|
|
71
|
+
latencyBuckets;
|
|
72
|
+
enabled;
|
|
73
|
+
defaultMetricsInterval;
|
|
74
|
+
onModuleInit() {
|
|
75
|
+
if (!this.enabled) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
this.registerStandardMetrics();
|
|
79
|
+
if (this.config.collectDefaultMetrics !== false) {
|
|
80
|
+
const collectInterval = this.config.collectInterval ?? 15e3;
|
|
81
|
+
promClient__namespace.collectDefaultMetrics({
|
|
82
|
+
register: this.registry,
|
|
83
|
+
prefix: this.prefix,
|
|
84
|
+
...collectInterval > 0 ? { timeout: collectInterval } : {}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
onModuleDestroy() {
|
|
89
|
+
this.registry.clear();
|
|
90
|
+
}
|
|
91
|
+
registerStandardMetrics() {
|
|
92
|
+
const commandMetrics = this.config.commandMetrics !== false;
|
|
93
|
+
const pluginMetrics = this.config.pluginMetrics !== false;
|
|
94
|
+
if (commandMetrics) {
|
|
95
|
+
this.registerCounter(`${this.prefix}commands_total`, "Total Redis commands executed", ["command", "client", "status"]);
|
|
96
|
+
this.registerHistogram(`${this.prefix}command_duration_seconds`, "Redis command latency in seconds", ["command", "client"], this.latencyBuckets);
|
|
97
|
+
this.registerGauge(`${this.prefix}connections_active`, "Number of active Redis connections", ["client"]);
|
|
98
|
+
this.registerCounter(`${this.prefix}errors_total`, "Total Redis errors", ["client", "error_type"]);
|
|
99
|
+
}
|
|
100
|
+
if (pluginMetrics) {
|
|
101
|
+
this.registerCounter(`${this.prefix}cache_hits_total`, "Total cache hits", ["layer"]);
|
|
102
|
+
this.registerCounter(`${this.prefix}cache_misses_total`, "Total cache misses", ["layer"]);
|
|
103
|
+
this.registerGauge(`${this.prefix}cache_hit_ratio`, "Cache hit ratio (0-1)", ["layer"]);
|
|
104
|
+
this.registerGauge(`${this.prefix}cache_size`, "Current cache size", ["layer"]);
|
|
105
|
+
this.registerCounter(`${this.prefix}cache_stampede_prevented_total`, "Total cache stampede prevention activations");
|
|
106
|
+
this.registerCounter(`${this.prefix}lock_acquisitions_total`, "Total lock acquisition attempts", ["status"]);
|
|
107
|
+
this.registerHistogram(`${this.prefix}lock_wait_duration_seconds`, "Lock wait time in seconds", [], this.latencyBuckets);
|
|
108
|
+
this.registerHistogram(`${this.prefix}lock_hold_duration_seconds`, "Lock hold time in seconds", [], this.latencyBuckets);
|
|
109
|
+
this.registerGauge(`${this.prefix}locks_active`, "Number of currently held locks");
|
|
110
|
+
this.registerCounter(`${this.prefix}ratelimit_requests_total`, "Total rate limit requests", ["status"]);
|
|
111
|
+
this.registerCounter(`${this.prefix}stream_messages_published_total`, "Total stream messages published", ["stream"]);
|
|
112
|
+
this.registerCounter(`${this.prefix}stream_messages_consumed_total`, "Total stream messages consumed", ["stream", "group", "status"]);
|
|
113
|
+
this.registerHistogram(`${this.prefix}stream_publish_duration_seconds`, "Stream publish latency in seconds", ["stream"], this.latencyBuckets);
|
|
114
|
+
this.registerCounter(`${this.prefix}stream_publish_errors_total`, "Total stream publish errors", ["stream"]);
|
|
115
|
+
this.registerHistogram(`${this.prefix}stream_processing_duration_seconds`, "Stream message processing time in seconds", ["stream", "group"], this.latencyBuckets);
|
|
116
|
+
this.registerCounter(`${this.prefix}idempotency_requests_total`, "Total idempotency requests", ["status"]);
|
|
117
|
+
this.registerHistogram(`${this.prefix}idempotency_duration_seconds`, "Idempotency check duration in seconds", [], this.latencyBuckets);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
incrementCounter(name, labels, value = 1) {
|
|
121
|
+
if (!this.enabled) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const counter = this.counters.get(name);
|
|
125
|
+
if (!counter) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (labels) {
|
|
129
|
+
counter.inc(labels, value);
|
|
130
|
+
} else {
|
|
131
|
+
counter.inc(value);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
observeHistogram(name, value, labels) {
|
|
135
|
+
if (!this.enabled) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const histogram = this.histograms.get(name);
|
|
139
|
+
if (!histogram) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (labels) {
|
|
143
|
+
histogram.observe(labels, value);
|
|
144
|
+
} else {
|
|
145
|
+
histogram.observe(value);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
startTimer(name, labels) {
|
|
149
|
+
if (!this.enabled) {
|
|
150
|
+
return () => 0;
|
|
151
|
+
}
|
|
152
|
+
const histogram = this.histograms.get(name);
|
|
153
|
+
if (!histogram) {
|
|
154
|
+
return () => 0;
|
|
155
|
+
}
|
|
156
|
+
const startTime = Date.now();
|
|
157
|
+
return () => {
|
|
158
|
+
const duration = (Date.now() - startTime) / 1e3;
|
|
159
|
+
this.observeHistogram(name, duration, labels);
|
|
160
|
+
return duration;
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
setGauge(name, value, labels) {
|
|
164
|
+
if (!this.enabled) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
const gauge = this.gauges.get(name);
|
|
168
|
+
if (!gauge) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
if (labels) {
|
|
172
|
+
gauge.set(labels, value);
|
|
173
|
+
} else {
|
|
174
|
+
gauge.set(value);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
incrementGauge(name, labels, value = 1) {
|
|
178
|
+
if (!this.enabled) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const gauge = this.gauges.get(name);
|
|
182
|
+
if (!gauge) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (labels) {
|
|
186
|
+
gauge.inc(labels, value);
|
|
187
|
+
} else {
|
|
188
|
+
gauge.inc(value);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
decrementGauge(name, labels, value = 1) {
|
|
192
|
+
if (!this.enabled) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
const gauge = this.gauges.get(name);
|
|
196
|
+
if (!gauge) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (labels) {
|
|
200
|
+
gauge.dec(labels, value);
|
|
201
|
+
} else {
|
|
202
|
+
gauge.dec(value);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
async getMetrics() {
|
|
206
|
+
if (!this.enabled) {
|
|
207
|
+
return "";
|
|
208
|
+
}
|
|
209
|
+
return this.registry.metrics();
|
|
210
|
+
}
|
|
211
|
+
async getMetricsJson() {
|
|
212
|
+
if (!this.enabled) {
|
|
213
|
+
return [];
|
|
214
|
+
}
|
|
215
|
+
const metrics = await this.registry.getMetricsAsJSON();
|
|
216
|
+
return metrics.map((metric) => ({
|
|
217
|
+
name: metric.name,
|
|
218
|
+
help: metric.help,
|
|
219
|
+
type: String(metric.type),
|
|
220
|
+
values: metric.values.map((v) => ({
|
|
221
|
+
labels: v.labels ?? {},
|
|
222
|
+
value: v.value
|
|
223
|
+
}))
|
|
224
|
+
}));
|
|
225
|
+
}
|
|
226
|
+
registerCounter(name, help, labelNames = []) {
|
|
227
|
+
if (!this.enabled) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
try {
|
|
231
|
+
const counter = new promClient__namespace.Counter({
|
|
232
|
+
name,
|
|
233
|
+
help,
|
|
234
|
+
labelNames,
|
|
235
|
+
registers: [this.registry]
|
|
236
|
+
});
|
|
237
|
+
this.counters.set(name, counter);
|
|
238
|
+
} catch (error) {
|
|
239
|
+
throw new MetricRegistrationError(name, error instanceof Error ? error : void 0);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
registerHistogram(name, help, labelNames = [], buckets) {
|
|
243
|
+
if (!this.enabled) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
try {
|
|
247
|
+
const histogram = new promClient__namespace.Histogram({
|
|
248
|
+
name,
|
|
249
|
+
help,
|
|
250
|
+
labelNames,
|
|
251
|
+
buckets: buckets ?? this.latencyBuckets,
|
|
252
|
+
registers: [this.registry]
|
|
253
|
+
});
|
|
254
|
+
this.histograms.set(name, histogram);
|
|
255
|
+
} catch (error) {
|
|
256
|
+
throw new MetricRegistrationError(name, error instanceof Error ? error : void 0);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
registerGauge(name, help, labelNames = []) {
|
|
260
|
+
if (!this.enabled) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
try {
|
|
264
|
+
const gauge = new promClient__namespace.Gauge({
|
|
265
|
+
name,
|
|
266
|
+
help,
|
|
267
|
+
labelNames,
|
|
268
|
+
registers: [this.registry]
|
|
269
|
+
});
|
|
270
|
+
this.gauges.set(name, gauge);
|
|
271
|
+
} catch (error) {
|
|
272
|
+
throw new MetricRegistrationError(name, error instanceof Error ? error : void 0);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
exports.MetricsService = __decorateClass([
|
|
277
|
+
common.Injectable(),
|
|
278
|
+
__decorateParam(0, common.Inject(METRICS_PLUGIN_OPTIONS))
|
|
279
|
+
], exports.MetricsService);
|
|
280
|
+
exports.MetricsController = class MetricsController {
|
|
281
|
+
constructor(metricsService) {
|
|
282
|
+
this.metricsService = metricsService;
|
|
283
|
+
}
|
|
284
|
+
async getMetrics() {
|
|
285
|
+
return this.metricsService.getMetrics();
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
__decorateClass([
|
|
289
|
+
common.Get(),
|
|
290
|
+
common.Header("Content-Type", "text/plain; version=0.0.4; charset=utf-8")
|
|
291
|
+
], exports.MetricsController.prototype, "getMetrics", 1);
|
|
292
|
+
exports.MetricsController = __decorateClass([
|
|
293
|
+
common.Controller("metrics"),
|
|
294
|
+
__decorateParam(0, common.Inject(METRICS_SERVICE))
|
|
295
|
+
], exports.MetricsController);
|
|
296
|
+
|
|
297
|
+
// src/metrics.plugin.ts
|
|
298
|
+
var DEFAULT_METRICS_CONFIG = {
|
|
299
|
+
enabled: true,
|
|
300
|
+
prefix: "redisx_",
|
|
301
|
+
exposeEndpoint: true,
|
|
302
|
+
endpoint: "/metrics",
|
|
303
|
+
histogramBuckets: [1e-3, 5e-3, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10],
|
|
304
|
+
collectDefaultMetrics: true,
|
|
305
|
+
commandMetrics: true,
|
|
306
|
+
pluginMetrics: true,
|
|
307
|
+
collectInterval: 15e3
|
|
308
|
+
};
|
|
309
|
+
var MetricsPlugin = class {
|
|
310
|
+
constructor(options = {}) {
|
|
311
|
+
this.options = options;
|
|
312
|
+
}
|
|
313
|
+
name = "metrics";
|
|
314
|
+
version = "0.1.0";
|
|
315
|
+
description = "Prometheus metrics collection and export";
|
|
316
|
+
getProviders() {
|
|
317
|
+
const config = {
|
|
318
|
+
enabled: this.options.enabled ?? DEFAULT_METRICS_CONFIG.enabled,
|
|
319
|
+
prefix: this.options.prefix ?? DEFAULT_METRICS_CONFIG.prefix,
|
|
320
|
+
exposeEndpoint: this.options.exposeEndpoint ?? DEFAULT_METRICS_CONFIG.exposeEndpoint,
|
|
321
|
+
endpoint: this.options.endpoint ?? DEFAULT_METRICS_CONFIG.endpoint,
|
|
322
|
+
histogramBuckets: this.options.histogramBuckets ?? DEFAULT_METRICS_CONFIG.histogramBuckets,
|
|
323
|
+
collectDefaultMetrics: this.options.collectDefaultMetrics ?? DEFAULT_METRICS_CONFIG.collectDefaultMetrics,
|
|
324
|
+
commandMetrics: this.options.commandMetrics ?? DEFAULT_METRICS_CONFIG.commandMetrics,
|
|
325
|
+
pluginMetrics: this.options.pluginMetrics ?? DEFAULT_METRICS_CONFIG.pluginMetrics,
|
|
326
|
+
collectInterval: this.options.collectInterval ?? DEFAULT_METRICS_CONFIG.collectInterval,
|
|
327
|
+
defaultLabels: this.options.defaultLabels
|
|
328
|
+
};
|
|
329
|
+
return [
|
|
330
|
+
{ provide: METRICS_PLUGIN_OPTIONS, useValue: config },
|
|
331
|
+
{ provide: METRICS_SERVICE, useClass: exports.MetricsService }
|
|
332
|
+
];
|
|
333
|
+
}
|
|
334
|
+
getExports() {
|
|
335
|
+
return [METRICS_SERVICE];
|
|
336
|
+
}
|
|
337
|
+
getControllers() {
|
|
338
|
+
if (this.options.exposeEndpoint !== false) {
|
|
339
|
+
return [exports.MetricsController];
|
|
340
|
+
}
|
|
341
|
+
return [];
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
exports.METRICS_PLUGIN_OPTIONS = METRICS_PLUGIN_OPTIONS;
|
|
346
|
+
exports.METRICS_REGISTRY = METRICS_REGISTRY;
|
|
347
|
+
exports.METRICS_SERVICE = METRICS_SERVICE;
|
|
348
|
+
exports.MetricRegistrationError = MetricRegistrationError;
|
|
349
|
+
exports.MetricsError = MetricsError;
|
|
350
|
+
exports.MetricsPlugin = MetricsPlugin;
|
|
351
|
+
//# sourceMappingURL=index.js.map
|
|
352
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/constants/index.ts","../src/shared/errors/index.ts","../src/metrics/application/services/metrics.service.ts","../src/metrics/api/controllers/metrics.controller.ts","../src/metrics.plugin.ts"],"names":["RedisXError","ErrorCode","MetricsService","promClient","Injectable","MetricsController","Get","Header","Controller","Inject"],"mappings":"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","file":"index.js","sourcesContent":["export const METRICS_PLUGIN_OPTIONS = Symbol.for('METRICS_PLUGIN_OPTIONS');\nexport const METRICS_SERVICE = Symbol.for('METRICS_SERVICE');\nexport const METRICS_REGISTRY = Symbol.for('METRICS_REGISTRY');\n","import { RedisXError, ErrorCode } from '@nestjs-redisx/core';\n\nexport class MetricsError extends RedisXError {\n constructor(message: string, cause?: Error) {\n super(message, ErrorCode.OP_FAILED, cause);\n }\n}\n\nexport class MetricRegistrationError extends MetricsError {\n constructor(metricName: string, cause?: Error) {\n super(`Failed to register metric \"${metricName}\"`, cause);\n }\n}\n","import { Injectable, Inject, OnModuleInit, OnModuleDestroy } from '@nestjs/common';\nimport * as promClient from 'prom-client';\n\nimport { METRICS_PLUGIN_OPTIONS } from '../../../shared/constants';\nimport { MetricRegistrationError } from '../../../shared/errors';\nimport { IMetricsPluginOptions, IMetricsJson } from '../../../shared/types';\nimport { IMetricsService } from '../ports/metrics-service.port';\n\n@Injectable()\nexport class MetricsService implements IMetricsService, OnModuleInit, OnModuleDestroy {\n private readonly registry: promClient.Registry;\n private readonly counters = new Map<string, promClient.Counter>();\n private readonly histograms = new Map<string, promClient.Histogram>();\n private readonly gauges = new Map<string, promClient.Gauge>();\n private readonly prefix: string;\n private readonly defaultLabels: Record<string, string>;\n private readonly latencyBuckets: number[];\n private readonly enabled: boolean;\n private defaultMetricsInterval?: ReturnType<typeof setInterval>;\n\n constructor(\n @Inject(METRICS_PLUGIN_OPTIONS)\n private readonly config: IMetricsPluginOptions,\n ) {\n this.enabled = config.enabled !== false;\n this.prefix = config.prefix ?? 'redisx_';\n this.defaultLabels = config.defaultLabels ?? {};\n this.latencyBuckets = config.histogramBuckets ?? [0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10];\n\n this.registry = new promClient.Registry();\n this.registry.setDefaultLabels(this.defaultLabels);\n }\n\n onModuleInit(): void {\n if (!this.enabled) {\n return;\n }\n\n this.registerStandardMetrics();\n\n if (this.config.collectDefaultMetrics !== false) {\n const collectInterval = this.config.collectInterval ?? 15000;\n promClient.collectDefaultMetrics({\n register: this.registry,\n prefix: this.prefix,\n ...(collectInterval > 0 ? { timeout: collectInterval } : {}),\n });\n }\n }\n\n onModuleDestroy(): void {\n this.registry.clear();\n }\n\n private registerStandardMetrics(): void {\n const commandMetrics = this.config.commandMetrics !== false;\n const pluginMetrics = this.config.pluginMetrics !== false;\n\n // Core metrics\n if (commandMetrics) {\n this.registerCounter(`${this.prefix}commands_total`, 'Total Redis commands executed', ['command', 'client', 'status']);\n\n this.registerHistogram(`${this.prefix}command_duration_seconds`, 'Redis command latency in seconds', ['command', 'client'], this.latencyBuckets);\n\n this.registerGauge(`${this.prefix}connections_active`, 'Number of active Redis connections', ['client']);\n\n this.registerCounter(`${this.prefix}errors_total`, 'Total Redis errors', ['client', 'error_type']);\n }\n\n // Plugin-specific metrics\n if (pluginMetrics) {\n // Cache metrics\n this.registerCounter(`${this.prefix}cache_hits_total`, 'Total cache hits', ['layer']);\n\n this.registerCounter(`${this.prefix}cache_misses_total`, 'Total cache misses', ['layer']);\n\n this.registerGauge(`${this.prefix}cache_hit_ratio`, 'Cache hit ratio (0-1)', ['layer']);\n\n this.registerGauge(`${this.prefix}cache_size`, 'Current cache size', ['layer']);\n\n this.registerCounter(`${this.prefix}cache_stampede_prevented_total`, 'Total cache stampede prevention activations');\n\n // Lock metrics\n this.registerCounter(`${this.prefix}lock_acquisitions_total`, 'Total lock acquisition attempts', ['status']);\n\n this.registerHistogram(`${this.prefix}lock_wait_duration_seconds`, 'Lock wait time in seconds', [], this.latencyBuckets);\n\n this.registerHistogram(`${this.prefix}lock_hold_duration_seconds`, 'Lock hold time in seconds', [], this.latencyBuckets);\n\n this.registerGauge(`${this.prefix}locks_active`, 'Number of currently held locks');\n\n // Rate limit metrics\n this.registerCounter(`${this.prefix}ratelimit_requests_total`, 'Total rate limit requests', ['status']);\n\n // Stream metrics\n this.registerCounter(`${this.prefix}stream_messages_published_total`, 'Total stream messages published', ['stream']);\n\n this.registerCounter(`${this.prefix}stream_messages_consumed_total`, 'Total stream messages consumed', ['stream', 'group', 'status']);\n\n this.registerHistogram(`${this.prefix}stream_publish_duration_seconds`, 'Stream publish latency in seconds', ['stream'], this.latencyBuckets);\n\n this.registerCounter(`${this.prefix}stream_publish_errors_total`, 'Total stream publish errors', ['stream']);\n\n this.registerHistogram(`${this.prefix}stream_processing_duration_seconds`, 'Stream message processing time in seconds', ['stream', 'group'], this.latencyBuckets);\n\n // Idempotency metrics\n this.registerCounter(`${this.prefix}idempotency_requests_total`, 'Total idempotency requests', ['status']);\n\n this.registerHistogram(`${this.prefix}idempotency_duration_seconds`, 'Idempotency check duration in seconds', [], this.latencyBuckets);\n }\n }\n\n incrementCounter(name: string, labels?: Record<string, string>, value = 1): void {\n if (!this.enabled) {\n return;\n }\n\n const counter = this.counters.get(name);\n if (!counter) {\n return;\n }\n\n if (labels) {\n counter.inc(labels, value);\n } else {\n counter.inc(value);\n }\n }\n\n observeHistogram(name: string, value: number, labels?: Record<string, string>): void {\n if (!this.enabled) {\n return;\n }\n\n const histogram = this.histograms.get(name);\n if (!histogram) {\n return;\n }\n\n if (labels) {\n histogram.observe(labels, value);\n } else {\n histogram.observe(value);\n }\n }\n\n startTimer(name: string, labels?: Record<string, string>): () => number {\n if (!this.enabled) {\n return () => 0;\n }\n\n const histogram = this.histograms.get(name);\n if (!histogram) {\n return () => 0;\n }\n\n const startTime = Date.now();\n\n return () => {\n const duration = (Date.now() - startTime) / 1000;\n this.observeHistogram(name, duration, labels);\n return duration;\n };\n }\n\n setGauge(name: string, value: number, labels?: Record<string, string>): void {\n if (!this.enabled) {\n return;\n }\n\n const gauge = this.gauges.get(name);\n if (!gauge) {\n return;\n }\n\n if (labels) {\n gauge.set(labels, value);\n } else {\n gauge.set(value);\n }\n }\n\n incrementGauge(name: string, labels?: Record<string, string>, value = 1): void {\n if (!this.enabled) {\n return;\n }\n\n const gauge = this.gauges.get(name);\n if (!gauge) {\n return;\n }\n\n if (labels) {\n gauge.inc(labels, value);\n } else {\n gauge.inc(value);\n }\n }\n\n decrementGauge(name: string, labels?: Record<string, string>, value = 1): void {\n if (!this.enabled) {\n return;\n }\n\n const gauge = this.gauges.get(name);\n if (!gauge) {\n return;\n }\n\n if (labels) {\n gauge.dec(labels, value);\n } else {\n gauge.dec(value);\n }\n }\n\n async getMetrics(): Promise<string> {\n if (!this.enabled) {\n return '';\n }\n\n return this.registry.metrics();\n }\n\n async getMetricsJson(): Promise<IMetricsJson[]> {\n if (!this.enabled) {\n return [];\n }\n\n const metrics = await this.registry.getMetricsAsJSON();\n\n return metrics.map((metric: promClient.MetricObjectWithValues<promClient.MetricValue<string>>) => ({\n name: metric.name,\n help: metric.help,\n type: String(metric.type),\n values: metric.values.map((v: promClient.MetricValue<string>) => ({\n labels: (v.labels as Record<string, string>) ?? {},\n value: v.value,\n })),\n }));\n }\n\n registerCounter(name: string, help: string, labelNames: string[] = []): void {\n if (!this.enabled) {\n return;\n }\n\n try {\n const counter = new promClient.Counter({\n name,\n help,\n labelNames,\n registers: [this.registry],\n });\n\n this.counters.set(name, counter);\n } catch (error) {\n throw new MetricRegistrationError(name, error instanceof Error ? error : undefined);\n }\n }\n\n registerHistogram(name: string, help: string, labelNames: string[] = [], buckets?: number[]): void {\n if (!this.enabled) {\n return;\n }\n\n try {\n const histogram = new promClient.Histogram({\n name,\n help,\n labelNames,\n buckets: buckets ?? this.latencyBuckets,\n registers: [this.registry],\n });\n\n this.histograms.set(name, histogram);\n } catch (error) {\n throw new MetricRegistrationError(name, error instanceof Error ? error : undefined);\n }\n }\n\n registerGauge(name: string, help: string, labelNames: string[] = []): void {\n if (!this.enabled) {\n return;\n }\n\n try {\n const gauge = new promClient.Gauge({\n name,\n help,\n labelNames,\n registers: [this.registry],\n });\n\n this.gauges.set(name, gauge);\n } catch (error) {\n throw new MetricRegistrationError(name, error instanceof Error ? error : undefined);\n }\n }\n}\n","import { Controller, Get, Header, Inject } from '@nestjs/common';\n\nimport { METRICS_SERVICE } from '../../../shared/constants';\nimport { IMetricsService } from '../../application/ports/metrics-service.port';\n\n@Controller('metrics')\nexport class MetricsController {\n constructor(@Inject(METRICS_SERVICE) private readonly metricsService: IMetricsService) {}\n\n @Get()\n @Header('Content-Type', 'text/plain; version=0.0.4; charset=utf-8')\n async getMetrics(): Promise<string> {\n return this.metricsService.getMetrics();\n }\n}\n","/**\n * Metrics plugin for NestJS RedisX.\n * Provides Prometheus metrics collection and export.\n */\n\nimport { Provider, Type } from '@nestjs/common';\nimport { IRedisXPlugin } from '@nestjs-redisx/core';\nimport { METRICS_PLUGIN_OPTIONS, METRICS_SERVICE } from './shared/constants';\nimport { IMetricsPluginOptions } from './shared/types';\nimport { MetricsService } from './metrics/application/services/metrics.service';\nimport { MetricsController } from './metrics/api/controllers/metrics.controller';\n\nconst DEFAULT_METRICS_CONFIG: Required<Omit<IMetricsPluginOptions, 'isGlobal' | 'defaultLabels'>> = {\n enabled: true,\n prefix: 'redisx_',\n exposeEndpoint: true,\n endpoint: '/metrics',\n histogramBuckets: [0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10],\n collectDefaultMetrics: true,\n commandMetrics: true,\n pluginMetrics: true,\n collectInterval: 15000,\n};\n\n/**\n * Metrics plugin for NestJS RedisX.\n *\n * Provides Prometheus metrics:\n * - Redis command latency\n * - Connection pool stats\n * - Cache hit/miss rates\n * - Error counts\n * - HTTP endpoint for Prometheus scraping\n *\n * @example\n * ```typescript\n * @Module({\n * imports: [\n * RedisModule.forRoot({\n * clients: { host: 'localhost', port: 6379 },\n * plugins: [\n * new MetricsPlugin({\n * enabled: true,\n * exposeEndpoint: true,\n * endpoint: '/metrics',\n * }),\n * ],\n * }),\n * ],\n * })\n * export class AppModule {}\n * ```\n */\nexport class MetricsPlugin implements IRedisXPlugin {\n readonly name = 'metrics';\n readonly version = '0.1.0';\n readonly description = 'Prometheus metrics collection and export';\n\n constructor(private readonly options: IMetricsPluginOptions = {}) {}\n\n getProviders(): Provider[] {\n const config: IMetricsPluginOptions = {\n enabled: this.options.enabled ?? DEFAULT_METRICS_CONFIG.enabled,\n prefix: this.options.prefix ?? DEFAULT_METRICS_CONFIG.prefix,\n exposeEndpoint: this.options.exposeEndpoint ?? DEFAULT_METRICS_CONFIG.exposeEndpoint,\n endpoint: this.options.endpoint ?? DEFAULT_METRICS_CONFIG.endpoint,\n histogramBuckets: this.options.histogramBuckets ?? DEFAULT_METRICS_CONFIG.histogramBuckets,\n collectDefaultMetrics: this.options.collectDefaultMetrics ?? DEFAULT_METRICS_CONFIG.collectDefaultMetrics,\n commandMetrics: this.options.commandMetrics ?? DEFAULT_METRICS_CONFIG.commandMetrics,\n pluginMetrics: this.options.pluginMetrics ?? DEFAULT_METRICS_CONFIG.pluginMetrics,\n collectInterval: this.options.collectInterval ?? DEFAULT_METRICS_CONFIG.collectInterval,\n defaultLabels: this.options.defaultLabels,\n };\n\n return [\n { provide: METRICS_PLUGIN_OPTIONS, useValue: config },\n { provide: METRICS_SERVICE, useClass: MetricsService },\n ];\n }\n\n getExports(): Array<string | symbol | Provider> {\n return [METRICS_SERVICE];\n }\n\n getControllers(): Type[] {\n // Only expose controller if endpoint is enabled\n if (this.options.exposeEndpoint !== false) {\n return [MetricsController];\n }\n return [];\n }\n}\n"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
import { Injectable, Inject, Get, Header, Controller } from '@nestjs/common';
|
|
2
|
+
import * as promClient from 'prom-client';
|
|
3
|
+
import { RedisXError, ErrorCode } from '@nestjs-redisx/core';
|
|
4
|
+
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
8
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
9
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
10
|
+
if (decorator = decorators[i])
|
|
11
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
12
|
+
if (kind && result) __defProp(target, key, result);
|
|
13
|
+
return result;
|
|
14
|
+
};
|
|
15
|
+
var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
|
|
16
|
+
|
|
17
|
+
// src/shared/constants/index.ts
|
|
18
|
+
var METRICS_PLUGIN_OPTIONS = /* @__PURE__ */ Symbol.for("METRICS_PLUGIN_OPTIONS");
|
|
19
|
+
var METRICS_SERVICE = /* @__PURE__ */ Symbol.for("METRICS_SERVICE");
|
|
20
|
+
var METRICS_REGISTRY = /* @__PURE__ */ Symbol.for("METRICS_REGISTRY");
|
|
21
|
+
var MetricsError = class extends RedisXError {
|
|
22
|
+
constructor(message, cause) {
|
|
23
|
+
super(message, ErrorCode.OP_FAILED, cause);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
var MetricRegistrationError = class extends MetricsError {
|
|
27
|
+
constructor(metricName, cause) {
|
|
28
|
+
super(`Failed to register metric "${metricName}"`, cause);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// src/metrics/application/services/metrics.service.ts
|
|
33
|
+
var MetricsService = class {
|
|
34
|
+
constructor(config) {
|
|
35
|
+
this.config = config;
|
|
36
|
+
this.enabled = config.enabled !== false;
|
|
37
|
+
this.prefix = config.prefix ?? "redisx_";
|
|
38
|
+
this.defaultLabels = config.defaultLabels ?? {};
|
|
39
|
+
this.latencyBuckets = config.histogramBuckets ?? [1e-3, 5e-3, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10];
|
|
40
|
+
this.registry = new promClient.Registry();
|
|
41
|
+
this.registry.setDefaultLabels(this.defaultLabels);
|
|
42
|
+
}
|
|
43
|
+
registry;
|
|
44
|
+
counters = /* @__PURE__ */ new Map();
|
|
45
|
+
histograms = /* @__PURE__ */ new Map();
|
|
46
|
+
gauges = /* @__PURE__ */ new Map();
|
|
47
|
+
prefix;
|
|
48
|
+
defaultLabels;
|
|
49
|
+
latencyBuckets;
|
|
50
|
+
enabled;
|
|
51
|
+
defaultMetricsInterval;
|
|
52
|
+
onModuleInit() {
|
|
53
|
+
if (!this.enabled) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
this.registerStandardMetrics();
|
|
57
|
+
if (this.config.collectDefaultMetrics !== false) {
|
|
58
|
+
const collectInterval = this.config.collectInterval ?? 15e3;
|
|
59
|
+
promClient.collectDefaultMetrics({
|
|
60
|
+
register: this.registry,
|
|
61
|
+
prefix: this.prefix,
|
|
62
|
+
...collectInterval > 0 ? { timeout: collectInterval } : {}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
onModuleDestroy() {
|
|
67
|
+
this.registry.clear();
|
|
68
|
+
}
|
|
69
|
+
registerStandardMetrics() {
|
|
70
|
+
const commandMetrics = this.config.commandMetrics !== false;
|
|
71
|
+
const pluginMetrics = this.config.pluginMetrics !== false;
|
|
72
|
+
if (commandMetrics) {
|
|
73
|
+
this.registerCounter(`${this.prefix}commands_total`, "Total Redis commands executed", ["command", "client", "status"]);
|
|
74
|
+
this.registerHistogram(`${this.prefix}command_duration_seconds`, "Redis command latency in seconds", ["command", "client"], this.latencyBuckets);
|
|
75
|
+
this.registerGauge(`${this.prefix}connections_active`, "Number of active Redis connections", ["client"]);
|
|
76
|
+
this.registerCounter(`${this.prefix}errors_total`, "Total Redis errors", ["client", "error_type"]);
|
|
77
|
+
}
|
|
78
|
+
if (pluginMetrics) {
|
|
79
|
+
this.registerCounter(`${this.prefix}cache_hits_total`, "Total cache hits", ["layer"]);
|
|
80
|
+
this.registerCounter(`${this.prefix}cache_misses_total`, "Total cache misses", ["layer"]);
|
|
81
|
+
this.registerGauge(`${this.prefix}cache_hit_ratio`, "Cache hit ratio (0-1)", ["layer"]);
|
|
82
|
+
this.registerGauge(`${this.prefix}cache_size`, "Current cache size", ["layer"]);
|
|
83
|
+
this.registerCounter(`${this.prefix}cache_stampede_prevented_total`, "Total cache stampede prevention activations");
|
|
84
|
+
this.registerCounter(`${this.prefix}lock_acquisitions_total`, "Total lock acquisition attempts", ["status"]);
|
|
85
|
+
this.registerHistogram(`${this.prefix}lock_wait_duration_seconds`, "Lock wait time in seconds", [], this.latencyBuckets);
|
|
86
|
+
this.registerHistogram(`${this.prefix}lock_hold_duration_seconds`, "Lock hold time in seconds", [], this.latencyBuckets);
|
|
87
|
+
this.registerGauge(`${this.prefix}locks_active`, "Number of currently held locks");
|
|
88
|
+
this.registerCounter(`${this.prefix}ratelimit_requests_total`, "Total rate limit requests", ["status"]);
|
|
89
|
+
this.registerCounter(`${this.prefix}stream_messages_published_total`, "Total stream messages published", ["stream"]);
|
|
90
|
+
this.registerCounter(`${this.prefix}stream_messages_consumed_total`, "Total stream messages consumed", ["stream", "group", "status"]);
|
|
91
|
+
this.registerHistogram(`${this.prefix}stream_publish_duration_seconds`, "Stream publish latency in seconds", ["stream"], this.latencyBuckets);
|
|
92
|
+
this.registerCounter(`${this.prefix}stream_publish_errors_total`, "Total stream publish errors", ["stream"]);
|
|
93
|
+
this.registerHistogram(`${this.prefix}stream_processing_duration_seconds`, "Stream message processing time in seconds", ["stream", "group"], this.latencyBuckets);
|
|
94
|
+
this.registerCounter(`${this.prefix}idempotency_requests_total`, "Total idempotency requests", ["status"]);
|
|
95
|
+
this.registerHistogram(`${this.prefix}idempotency_duration_seconds`, "Idempotency check duration in seconds", [], this.latencyBuckets);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
incrementCounter(name, labels, value = 1) {
|
|
99
|
+
if (!this.enabled) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const counter = this.counters.get(name);
|
|
103
|
+
if (!counter) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (labels) {
|
|
107
|
+
counter.inc(labels, value);
|
|
108
|
+
} else {
|
|
109
|
+
counter.inc(value);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
observeHistogram(name, value, labels) {
|
|
113
|
+
if (!this.enabled) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const histogram = this.histograms.get(name);
|
|
117
|
+
if (!histogram) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (labels) {
|
|
121
|
+
histogram.observe(labels, value);
|
|
122
|
+
} else {
|
|
123
|
+
histogram.observe(value);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
startTimer(name, labels) {
|
|
127
|
+
if (!this.enabled) {
|
|
128
|
+
return () => 0;
|
|
129
|
+
}
|
|
130
|
+
const histogram = this.histograms.get(name);
|
|
131
|
+
if (!histogram) {
|
|
132
|
+
return () => 0;
|
|
133
|
+
}
|
|
134
|
+
const startTime = Date.now();
|
|
135
|
+
return () => {
|
|
136
|
+
const duration = (Date.now() - startTime) / 1e3;
|
|
137
|
+
this.observeHistogram(name, duration, labels);
|
|
138
|
+
return duration;
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
setGauge(name, value, labels) {
|
|
142
|
+
if (!this.enabled) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const gauge = this.gauges.get(name);
|
|
146
|
+
if (!gauge) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
if (labels) {
|
|
150
|
+
gauge.set(labels, value);
|
|
151
|
+
} else {
|
|
152
|
+
gauge.set(value);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
incrementGauge(name, labels, value = 1) {
|
|
156
|
+
if (!this.enabled) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const gauge = this.gauges.get(name);
|
|
160
|
+
if (!gauge) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
if (labels) {
|
|
164
|
+
gauge.inc(labels, value);
|
|
165
|
+
} else {
|
|
166
|
+
gauge.inc(value);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
decrementGauge(name, labels, value = 1) {
|
|
170
|
+
if (!this.enabled) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const gauge = this.gauges.get(name);
|
|
174
|
+
if (!gauge) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
if (labels) {
|
|
178
|
+
gauge.dec(labels, value);
|
|
179
|
+
} else {
|
|
180
|
+
gauge.dec(value);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
async getMetrics() {
|
|
184
|
+
if (!this.enabled) {
|
|
185
|
+
return "";
|
|
186
|
+
}
|
|
187
|
+
return this.registry.metrics();
|
|
188
|
+
}
|
|
189
|
+
async getMetricsJson() {
|
|
190
|
+
if (!this.enabled) {
|
|
191
|
+
return [];
|
|
192
|
+
}
|
|
193
|
+
const metrics = await this.registry.getMetricsAsJSON();
|
|
194
|
+
return metrics.map((metric) => ({
|
|
195
|
+
name: metric.name,
|
|
196
|
+
help: metric.help,
|
|
197
|
+
type: String(metric.type),
|
|
198
|
+
values: metric.values.map((v) => ({
|
|
199
|
+
labels: v.labels ?? {},
|
|
200
|
+
value: v.value
|
|
201
|
+
}))
|
|
202
|
+
}));
|
|
203
|
+
}
|
|
204
|
+
registerCounter(name, help, labelNames = []) {
|
|
205
|
+
if (!this.enabled) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
try {
|
|
209
|
+
const counter = new promClient.Counter({
|
|
210
|
+
name,
|
|
211
|
+
help,
|
|
212
|
+
labelNames,
|
|
213
|
+
registers: [this.registry]
|
|
214
|
+
});
|
|
215
|
+
this.counters.set(name, counter);
|
|
216
|
+
} catch (error) {
|
|
217
|
+
throw new MetricRegistrationError(name, error instanceof Error ? error : void 0);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
registerHistogram(name, help, labelNames = [], buckets) {
|
|
221
|
+
if (!this.enabled) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
try {
|
|
225
|
+
const histogram = new promClient.Histogram({
|
|
226
|
+
name,
|
|
227
|
+
help,
|
|
228
|
+
labelNames,
|
|
229
|
+
buckets: buckets ?? this.latencyBuckets,
|
|
230
|
+
registers: [this.registry]
|
|
231
|
+
});
|
|
232
|
+
this.histograms.set(name, histogram);
|
|
233
|
+
} catch (error) {
|
|
234
|
+
throw new MetricRegistrationError(name, error instanceof Error ? error : void 0);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
registerGauge(name, help, labelNames = []) {
|
|
238
|
+
if (!this.enabled) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
try {
|
|
242
|
+
const gauge = new promClient.Gauge({
|
|
243
|
+
name,
|
|
244
|
+
help,
|
|
245
|
+
labelNames,
|
|
246
|
+
registers: [this.registry]
|
|
247
|
+
});
|
|
248
|
+
this.gauges.set(name, gauge);
|
|
249
|
+
} catch (error) {
|
|
250
|
+
throw new MetricRegistrationError(name, error instanceof Error ? error : void 0);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
MetricsService = __decorateClass([
|
|
255
|
+
Injectable(),
|
|
256
|
+
__decorateParam(0, Inject(METRICS_PLUGIN_OPTIONS))
|
|
257
|
+
], MetricsService);
|
|
258
|
+
var MetricsController = class {
|
|
259
|
+
constructor(metricsService) {
|
|
260
|
+
this.metricsService = metricsService;
|
|
261
|
+
}
|
|
262
|
+
async getMetrics() {
|
|
263
|
+
return this.metricsService.getMetrics();
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
__decorateClass([
|
|
267
|
+
Get(),
|
|
268
|
+
Header("Content-Type", "text/plain; version=0.0.4; charset=utf-8")
|
|
269
|
+
], MetricsController.prototype, "getMetrics", 1);
|
|
270
|
+
MetricsController = __decorateClass([
|
|
271
|
+
Controller("metrics"),
|
|
272
|
+
__decorateParam(0, Inject(METRICS_SERVICE))
|
|
273
|
+
], MetricsController);
|
|
274
|
+
|
|
275
|
+
// src/metrics.plugin.ts
|
|
276
|
+
var DEFAULT_METRICS_CONFIG = {
|
|
277
|
+
enabled: true,
|
|
278
|
+
prefix: "redisx_",
|
|
279
|
+
exposeEndpoint: true,
|
|
280
|
+
endpoint: "/metrics",
|
|
281
|
+
histogramBuckets: [1e-3, 5e-3, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10],
|
|
282
|
+
collectDefaultMetrics: true,
|
|
283
|
+
commandMetrics: true,
|
|
284
|
+
pluginMetrics: true,
|
|
285
|
+
collectInterval: 15e3
|
|
286
|
+
};
|
|
287
|
+
var MetricsPlugin = class {
|
|
288
|
+
constructor(options = {}) {
|
|
289
|
+
this.options = options;
|
|
290
|
+
}
|
|
291
|
+
name = "metrics";
|
|
292
|
+
version = "0.1.0";
|
|
293
|
+
description = "Prometheus metrics collection and export";
|
|
294
|
+
getProviders() {
|
|
295
|
+
const config = {
|
|
296
|
+
enabled: this.options.enabled ?? DEFAULT_METRICS_CONFIG.enabled,
|
|
297
|
+
prefix: this.options.prefix ?? DEFAULT_METRICS_CONFIG.prefix,
|
|
298
|
+
exposeEndpoint: this.options.exposeEndpoint ?? DEFAULT_METRICS_CONFIG.exposeEndpoint,
|
|
299
|
+
endpoint: this.options.endpoint ?? DEFAULT_METRICS_CONFIG.endpoint,
|
|
300
|
+
histogramBuckets: this.options.histogramBuckets ?? DEFAULT_METRICS_CONFIG.histogramBuckets,
|
|
301
|
+
collectDefaultMetrics: this.options.collectDefaultMetrics ?? DEFAULT_METRICS_CONFIG.collectDefaultMetrics,
|
|
302
|
+
commandMetrics: this.options.commandMetrics ?? DEFAULT_METRICS_CONFIG.commandMetrics,
|
|
303
|
+
pluginMetrics: this.options.pluginMetrics ?? DEFAULT_METRICS_CONFIG.pluginMetrics,
|
|
304
|
+
collectInterval: this.options.collectInterval ?? DEFAULT_METRICS_CONFIG.collectInterval,
|
|
305
|
+
defaultLabels: this.options.defaultLabels
|
|
306
|
+
};
|
|
307
|
+
return [
|
|
308
|
+
{ provide: METRICS_PLUGIN_OPTIONS, useValue: config },
|
|
309
|
+
{ provide: METRICS_SERVICE, useClass: MetricsService }
|
|
310
|
+
];
|
|
311
|
+
}
|
|
312
|
+
getExports() {
|
|
313
|
+
return [METRICS_SERVICE];
|
|
314
|
+
}
|
|
315
|
+
getControllers() {
|
|
316
|
+
if (this.options.exposeEndpoint !== false) {
|
|
317
|
+
return [MetricsController];
|
|
318
|
+
}
|
|
319
|
+
return [];
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
export { METRICS_PLUGIN_OPTIONS, METRICS_REGISTRY, METRICS_SERVICE, MetricRegistrationError, MetricsController, MetricsError, MetricsPlugin, MetricsService };
|
|
324
|
+
//# sourceMappingURL=index.mjs.map
|
|
325
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/constants/index.ts","../src/shared/errors/index.ts","../src/metrics/application/services/metrics.service.ts","../src/metrics/api/controllers/metrics.controller.ts","../src/metrics.plugin.ts"],"names":["Inject"],"mappings":"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","file":"index.mjs","sourcesContent":["export const METRICS_PLUGIN_OPTIONS = Symbol.for('METRICS_PLUGIN_OPTIONS');\nexport const METRICS_SERVICE = Symbol.for('METRICS_SERVICE');\nexport const METRICS_REGISTRY = Symbol.for('METRICS_REGISTRY');\n","import { RedisXError, ErrorCode } from '@nestjs-redisx/core';\n\nexport class MetricsError extends RedisXError {\n constructor(message: string, cause?: Error) {\n super(message, ErrorCode.OP_FAILED, cause);\n }\n}\n\nexport class MetricRegistrationError extends MetricsError {\n constructor(metricName: string, cause?: Error) {\n super(`Failed to register metric \"${metricName}\"`, cause);\n }\n}\n","import { Injectable, Inject, OnModuleInit, OnModuleDestroy } from '@nestjs/common';\nimport * as promClient from 'prom-client';\n\nimport { METRICS_PLUGIN_OPTIONS } from '../../../shared/constants';\nimport { MetricRegistrationError } from '../../../shared/errors';\nimport { IMetricsPluginOptions, IMetricsJson } from '../../../shared/types';\nimport { IMetricsService } from '../ports/metrics-service.port';\n\n@Injectable()\nexport class MetricsService implements IMetricsService, OnModuleInit, OnModuleDestroy {\n private readonly registry: promClient.Registry;\n private readonly counters = new Map<string, promClient.Counter>();\n private readonly histograms = new Map<string, promClient.Histogram>();\n private readonly gauges = new Map<string, promClient.Gauge>();\n private readonly prefix: string;\n private readonly defaultLabels: Record<string, string>;\n private readonly latencyBuckets: number[];\n private readonly enabled: boolean;\n private defaultMetricsInterval?: ReturnType<typeof setInterval>;\n\n constructor(\n @Inject(METRICS_PLUGIN_OPTIONS)\n private readonly config: IMetricsPluginOptions,\n ) {\n this.enabled = config.enabled !== false;\n this.prefix = config.prefix ?? 'redisx_';\n this.defaultLabels = config.defaultLabels ?? {};\n this.latencyBuckets = config.histogramBuckets ?? [0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10];\n\n this.registry = new promClient.Registry();\n this.registry.setDefaultLabels(this.defaultLabels);\n }\n\n onModuleInit(): void {\n if (!this.enabled) {\n return;\n }\n\n this.registerStandardMetrics();\n\n if (this.config.collectDefaultMetrics !== false) {\n const collectInterval = this.config.collectInterval ?? 15000;\n promClient.collectDefaultMetrics({\n register: this.registry,\n prefix: this.prefix,\n ...(collectInterval > 0 ? { timeout: collectInterval } : {}),\n });\n }\n }\n\n onModuleDestroy(): void {\n this.registry.clear();\n }\n\n private registerStandardMetrics(): void {\n const commandMetrics = this.config.commandMetrics !== false;\n const pluginMetrics = this.config.pluginMetrics !== false;\n\n // Core metrics\n if (commandMetrics) {\n this.registerCounter(`${this.prefix}commands_total`, 'Total Redis commands executed', ['command', 'client', 'status']);\n\n this.registerHistogram(`${this.prefix}command_duration_seconds`, 'Redis command latency in seconds', ['command', 'client'], this.latencyBuckets);\n\n this.registerGauge(`${this.prefix}connections_active`, 'Number of active Redis connections', ['client']);\n\n this.registerCounter(`${this.prefix}errors_total`, 'Total Redis errors', ['client', 'error_type']);\n }\n\n // Plugin-specific metrics\n if (pluginMetrics) {\n // Cache metrics\n this.registerCounter(`${this.prefix}cache_hits_total`, 'Total cache hits', ['layer']);\n\n this.registerCounter(`${this.prefix}cache_misses_total`, 'Total cache misses', ['layer']);\n\n this.registerGauge(`${this.prefix}cache_hit_ratio`, 'Cache hit ratio (0-1)', ['layer']);\n\n this.registerGauge(`${this.prefix}cache_size`, 'Current cache size', ['layer']);\n\n this.registerCounter(`${this.prefix}cache_stampede_prevented_total`, 'Total cache stampede prevention activations');\n\n // Lock metrics\n this.registerCounter(`${this.prefix}lock_acquisitions_total`, 'Total lock acquisition attempts', ['status']);\n\n this.registerHistogram(`${this.prefix}lock_wait_duration_seconds`, 'Lock wait time in seconds', [], this.latencyBuckets);\n\n this.registerHistogram(`${this.prefix}lock_hold_duration_seconds`, 'Lock hold time in seconds', [], this.latencyBuckets);\n\n this.registerGauge(`${this.prefix}locks_active`, 'Number of currently held locks');\n\n // Rate limit metrics\n this.registerCounter(`${this.prefix}ratelimit_requests_total`, 'Total rate limit requests', ['status']);\n\n // Stream metrics\n this.registerCounter(`${this.prefix}stream_messages_published_total`, 'Total stream messages published', ['stream']);\n\n this.registerCounter(`${this.prefix}stream_messages_consumed_total`, 'Total stream messages consumed', ['stream', 'group', 'status']);\n\n this.registerHistogram(`${this.prefix}stream_publish_duration_seconds`, 'Stream publish latency in seconds', ['stream'], this.latencyBuckets);\n\n this.registerCounter(`${this.prefix}stream_publish_errors_total`, 'Total stream publish errors', ['stream']);\n\n this.registerHistogram(`${this.prefix}stream_processing_duration_seconds`, 'Stream message processing time in seconds', ['stream', 'group'], this.latencyBuckets);\n\n // Idempotency metrics\n this.registerCounter(`${this.prefix}idempotency_requests_total`, 'Total idempotency requests', ['status']);\n\n this.registerHistogram(`${this.prefix}idempotency_duration_seconds`, 'Idempotency check duration in seconds', [], this.latencyBuckets);\n }\n }\n\n incrementCounter(name: string, labels?: Record<string, string>, value = 1): void {\n if (!this.enabled) {\n return;\n }\n\n const counter = this.counters.get(name);\n if (!counter) {\n return;\n }\n\n if (labels) {\n counter.inc(labels, value);\n } else {\n counter.inc(value);\n }\n }\n\n observeHistogram(name: string, value: number, labels?: Record<string, string>): void {\n if (!this.enabled) {\n return;\n }\n\n const histogram = this.histograms.get(name);\n if (!histogram) {\n return;\n }\n\n if (labels) {\n histogram.observe(labels, value);\n } else {\n histogram.observe(value);\n }\n }\n\n startTimer(name: string, labels?: Record<string, string>): () => number {\n if (!this.enabled) {\n return () => 0;\n }\n\n const histogram = this.histograms.get(name);\n if (!histogram) {\n return () => 0;\n }\n\n const startTime = Date.now();\n\n return () => {\n const duration = (Date.now() - startTime) / 1000;\n this.observeHistogram(name, duration, labels);\n return duration;\n };\n }\n\n setGauge(name: string, value: number, labels?: Record<string, string>): void {\n if (!this.enabled) {\n return;\n }\n\n const gauge = this.gauges.get(name);\n if (!gauge) {\n return;\n }\n\n if (labels) {\n gauge.set(labels, value);\n } else {\n gauge.set(value);\n }\n }\n\n incrementGauge(name: string, labels?: Record<string, string>, value = 1): void {\n if (!this.enabled) {\n return;\n }\n\n const gauge = this.gauges.get(name);\n if (!gauge) {\n return;\n }\n\n if (labels) {\n gauge.inc(labels, value);\n } else {\n gauge.inc(value);\n }\n }\n\n decrementGauge(name: string, labels?: Record<string, string>, value = 1): void {\n if (!this.enabled) {\n return;\n }\n\n const gauge = this.gauges.get(name);\n if (!gauge) {\n return;\n }\n\n if (labels) {\n gauge.dec(labels, value);\n } else {\n gauge.dec(value);\n }\n }\n\n async getMetrics(): Promise<string> {\n if (!this.enabled) {\n return '';\n }\n\n return this.registry.metrics();\n }\n\n async getMetricsJson(): Promise<IMetricsJson[]> {\n if (!this.enabled) {\n return [];\n }\n\n const metrics = await this.registry.getMetricsAsJSON();\n\n return metrics.map((metric: promClient.MetricObjectWithValues<promClient.MetricValue<string>>) => ({\n name: metric.name,\n help: metric.help,\n type: String(metric.type),\n values: metric.values.map((v: promClient.MetricValue<string>) => ({\n labels: (v.labels as Record<string, string>) ?? {},\n value: v.value,\n })),\n }));\n }\n\n registerCounter(name: string, help: string, labelNames: string[] = []): void {\n if (!this.enabled) {\n return;\n }\n\n try {\n const counter = new promClient.Counter({\n name,\n help,\n labelNames,\n registers: [this.registry],\n });\n\n this.counters.set(name, counter);\n } catch (error) {\n throw new MetricRegistrationError(name, error instanceof Error ? error : undefined);\n }\n }\n\n registerHistogram(name: string, help: string, labelNames: string[] = [], buckets?: number[]): void {\n if (!this.enabled) {\n return;\n }\n\n try {\n const histogram = new promClient.Histogram({\n name,\n help,\n labelNames,\n buckets: buckets ?? this.latencyBuckets,\n registers: [this.registry],\n });\n\n this.histograms.set(name, histogram);\n } catch (error) {\n throw new MetricRegistrationError(name, error instanceof Error ? error : undefined);\n }\n }\n\n registerGauge(name: string, help: string, labelNames: string[] = []): void {\n if (!this.enabled) {\n return;\n }\n\n try {\n const gauge = new promClient.Gauge({\n name,\n help,\n labelNames,\n registers: [this.registry],\n });\n\n this.gauges.set(name, gauge);\n } catch (error) {\n throw new MetricRegistrationError(name, error instanceof Error ? error : undefined);\n }\n }\n}\n","import { Controller, Get, Header, Inject } from '@nestjs/common';\n\nimport { METRICS_SERVICE } from '../../../shared/constants';\nimport { IMetricsService } from '../../application/ports/metrics-service.port';\n\n@Controller('metrics')\nexport class MetricsController {\n constructor(@Inject(METRICS_SERVICE) private readonly metricsService: IMetricsService) {}\n\n @Get()\n @Header('Content-Type', 'text/plain; version=0.0.4; charset=utf-8')\n async getMetrics(): Promise<string> {\n return this.metricsService.getMetrics();\n }\n}\n","/**\n * Metrics plugin for NestJS RedisX.\n * Provides Prometheus metrics collection and export.\n */\n\nimport { Provider, Type } from '@nestjs/common';\nimport { IRedisXPlugin } from '@nestjs-redisx/core';\nimport { METRICS_PLUGIN_OPTIONS, METRICS_SERVICE } from './shared/constants';\nimport { IMetricsPluginOptions } from './shared/types';\nimport { MetricsService } from './metrics/application/services/metrics.service';\nimport { MetricsController } from './metrics/api/controllers/metrics.controller';\n\nconst DEFAULT_METRICS_CONFIG: Required<Omit<IMetricsPluginOptions, 'isGlobal' | 'defaultLabels'>> = {\n enabled: true,\n prefix: 'redisx_',\n exposeEndpoint: true,\n endpoint: '/metrics',\n histogramBuckets: [0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10],\n collectDefaultMetrics: true,\n commandMetrics: true,\n pluginMetrics: true,\n collectInterval: 15000,\n};\n\n/**\n * Metrics plugin for NestJS RedisX.\n *\n * Provides Prometheus metrics:\n * - Redis command latency\n * - Connection pool stats\n * - Cache hit/miss rates\n * - Error counts\n * - HTTP endpoint for Prometheus scraping\n *\n * @example\n * ```typescript\n * @Module({\n * imports: [\n * RedisModule.forRoot({\n * clients: { host: 'localhost', port: 6379 },\n * plugins: [\n * new MetricsPlugin({\n * enabled: true,\n * exposeEndpoint: true,\n * endpoint: '/metrics',\n * }),\n * ],\n * }),\n * ],\n * })\n * export class AppModule {}\n * ```\n */\nexport class MetricsPlugin implements IRedisXPlugin {\n readonly name = 'metrics';\n readonly version = '0.1.0';\n readonly description = 'Prometheus metrics collection and export';\n\n constructor(private readonly options: IMetricsPluginOptions = {}) {}\n\n getProviders(): Provider[] {\n const config: IMetricsPluginOptions = {\n enabled: this.options.enabled ?? DEFAULT_METRICS_CONFIG.enabled,\n prefix: this.options.prefix ?? DEFAULT_METRICS_CONFIG.prefix,\n exposeEndpoint: this.options.exposeEndpoint ?? DEFAULT_METRICS_CONFIG.exposeEndpoint,\n endpoint: this.options.endpoint ?? DEFAULT_METRICS_CONFIG.endpoint,\n histogramBuckets: this.options.histogramBuckets ?? DEFAULT_METRICS_CONFIG.histogramBuckets,\n collectDefaultMetrics: this.options.collectDefaultMetrics ?? DEFAULT_METRICS_CONFIG.collectDefaultMetrics,\n commandMetrics: this.options.commandMetrics ?? DEFAULT_METRICS_CONFIG.commandMetrics,\n pluginMetrics: this.options.pluginMetrics ?? DEFAULT_METRICS_CONFIG.pluginMetrics,\n collectInterval: this.options.collectInterval ?? DEFAULT_METRICS_CONFIG.collectInterval,\n defaultLabels: this.options.defaultLabels,\n };\n\n return [\n { provide: METRICS_PLUGIN_OPTIONS, useValue: config },\n { provide: METRICS_SERVICE, useClass: MetricsService },\n ];\n }\n\n getExports(): Array<string | symbol | Provider> {\n return [METRICS_SERVICE];\n }\n\n getControllers(): Type[] {\n // Only expose controller if endpoint is enabled\n if (this.options.exposeEndpoint !== false) {\n return [MetricsController];\n }\n return [];\n }\n}\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { IMetricsService } from '../../application/ports/metrics-service.port';
|
|
2
|
+
export declare class MetricsController {
|
|
3
|
+
private readonly metricsService;
|
|
4
|
+
constructor(metricsService: IMetricsService);
|
|
5
|
+
getMetrics(): Promise<string>;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=metrics.controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.controller.d.ts","sourceRoot":"","sources":["../../../../src/metrics/api/controllers/metrics.controller.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,8CAA8C,CAAC;AAE/E,qBACa,iBAAiB;IACS,OAAO,CAAC,QAAQ,CAAC,cAAc;gBAAd,cAAc,EAAE,eAAe;IAI/E,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;CAGpC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/metrics/application/ports/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { IMetricsJson } from '../../../shared/types';
|
|
2
|
+
export interface IMetricsService {
|
|
3
|
+
incrementCounter(name: string, labels?: Record<string, string>, value?: number): void;
|
|
4
|
+
observeHistogram(name: string, value: number, labels?: Record<string, string>): void;
|
|
5
|
+
startTimer(name: string, labels?: Record<string, string>): () => number;
|
|
6
|
+
setGauge(name: string, value: number, labels?: Record<string, string>): void;
|
|
7
|
+
incrementGauge(name: string, labels?: Record<string, string>, value?: number): void;
|
|
8
|
+
decrementGauge(name: string, labels?: Record<string, string>, value?: number): void;
|
|
9
|
+
getMetrics(): Promise<string>;
|
|
10
|
+
getMetricsJson(): Promise<IMetricsJson[]>;
|
|
11
|
+
registerCounter(name: string, help: string, labelNames?: string[]): void;
|
|
12
|
+
registerHistogram(name: string, help: string, labelNames?: string[], buckets?: number[]): void;
|
|
13
|
+
registerGauge(name: string, help: string, labelNames?: string[]): void;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=metrics-service.port.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics-service.port.d.ts","sourceRoot":"","sources":["../../../../src/metrics/application/ports/metrics-service.port.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAErD,MAAM,WAAW,eAAe;IAE9B,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAGtF,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IACrF,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC;IAGxE,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IAC7E,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpF,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAGpF,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9B,cAAc,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IAG1C,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACzE,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC/F,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;CACxE"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { OnModuleInit, OnModuleDestroy } from '@nestjs/common';
|
|
2
|
+
import { IMetricsPluginOptions, IMetricsJson } from '../../../shared/types';
|
|
3
|
+
import { IMetricsService } from '../ports/metrics-service.port';
|
|
4
|
+
export declare class MetricsService implements IMetricsService, OnModuleInit, OnModuleDestroy {
|
|
5
|
+
private readonly config;
|
|
6
|
+
private readonly registry;
|
|
7
|
+
private readonly counters;
|
|
8
|
+
private readonly histograms;
|
|
9
|
+
private readonly gauges;
|
|
10
|
+
private readonly prefix;
|
|
11
|
+
private readonly defaultLabels;
|
|
12
|
+
private readonly latencyBuckets;
|
|
13
|
+
private readonly enabled;
|
|
14
|
+
private defaultMetricsInterval?;
|
|
15
|
+
constructor(config: IMetricsPluginOptions);
|
|
16
|
+
onModuleInit(): void;
|
|
17
|
+
onModuleDestroy(): void;
|
|
18
|
+
private registerStandardMetrics;
|
|
19
|
+
incrementCounter(name: string, labels?: Record<string, string>, value?: number): void;
|
|
20
|
+
observeHistogram(name: string, value: number, labels?: Record<string, string>): void;
|
|
21
|
+
startTimer(name: string, labels?: Record<string, string>): () => number;
|
|
22
|
+
setGauge(name: string, value: number, labels?: Record<string, string>): void;
|
|
23
|
+
incrementGauge(name: string, labels?: Record<string, string>, value?: number): void;
|
|
24
|
+
decrementGauge(name: string, labels?: Record<string, string>, value?: number): void;
|
|
25
|
+
getMetrics(): Promise<string>;
|
|
26
|
+
getMetricsJson(): Promise<IMetricsJson[]>;
|
|
27
|
+
registerCounter(name: string, help: string, labelNames?: string[]): void;
|
|
28
|
+
registerHistogram(name: string, help: string, labelNames?: string[], buckets?: number[]): void;
|
|
29
|
+
registerGauge(name: string, help: string, labelNames?: string[]): void;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=metrics.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.service.d.ts","sourceRoot":"","sources":["../../../../src/metrics/application/services/metrics.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAKnF,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAEhE,qBACa,cAAe,YAAW,eAAe,EAAE,YAAY,EAAE,eAAe;IAajF,OAAO,CAAC,QAAQ,CAAC,MAAM;IAZzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsB;IAC/C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAyC;IAClE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA2C;IACtE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuC;IAC9D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAyB;IACvD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAW;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAClC,OAAO,CAAC,sBAAsB,CAAC,CAAiC;gBAI7C,MAAM,EAAE,qBAAqB;IAWhD,YAAY,IAAI,IAAI;IAiBpB,eAAe,IAAI,IAAI;IAIvB,OAAO,CAAC,uBAAuB;IA0D/B,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,SAAI,GAAG,IAAI;IAiBhF,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI;IAiBpF,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,MAAM;IAmBvE,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI;IAiB5E,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,SAAI,GAAG,IAAI;IAiB9E,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,SAAI,GAAG,IAAI;IAiBxE,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAQ7B,cAAc,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAkB/C,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,GAAE,MAAM,EAAO,GAAG,IAAI;IAmB5E,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,GAAE,MAAM,EAAO,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI;IAoBlG,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,GAAE,MAAM,EAAO,GAAG,IAAI;CAkB3E"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metrics plugin for NestJS RedisX.
|
|
3
|
+
* Provides Prometheus metrics collection and export.
|
|
4
|
+
*/
|
|
5
|
+
import { Provider, Type } from '@nestjs/common';
|
|
6
|
+
import { IRedisXPlugin } from '@nestjs-redisx/core';
|
|
7
|
+
import { IMetricsPluginOptions } from './shared/types';
|
|
8
|
+
/**
|
|
9
|
+
* Metrics plugin for NestJS RedisX.
|
|
10
|
+
*
|
|
11
|
+
* Provides Prometheus metrics:
|
|
12
|
+
* - Redis command latency
|
|
13
|
+
* - Connection pool stats
|
|
14
|
+
* - Cache hit/miss rates
|
|
15
|
+
* - Error counts
|
|
16
|
+
* - HTTP endpoint for Prometheus scraping
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* @Module({
|
|
21
|
+
* imports: [
|
|
22
|
+
* RedisModule.forRoot({
|
|
23
|
+
* clients: { host: 'localhost', port: 6379 },
|
|
24
|
+
* plugins: [
|
|
25
|
+
* new MetricsPlugin({
|
|
26
|
+
* enabled: true,
|
|
27
|
+
* exposeEndpoint: true,
|
|
28
|
+
* endpoint: '/metrics',
|
|
29
|
+
* }),
|
|
30
|
+
* ],
|
|
31
|
+
* }),
|
|
32
|
+
* ],
|
|
33
|
+
* })
|
|
34
|
+
* export class AppModule {}
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare class MetricsPlugin implements IRedisXPlugin {
|
|
38
|
+
private readonly options;
|
|
39
|
+
readonly name = "metrics";
|
|
40
|
+
readonly version = "0.1.0";
|
|
41
|
+
readonly description = "Prometheus metrics collection and export";
|
|
42
|
+
constructor(options?: IMetricsPluginOptions);
|
|
43
|
+
getProviders(): Provider[];
|
|
44
|
+
getExports(): Array<string | symbol | Provider>;
|
|
45
|
+
getControllers(): Type[];
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=metrics.plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.plugin.d.ts","sourceRoot":"","sources":["../src/metrics.plugin.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAgBvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qBAAa,aAAc,YAAW,aAAa;IAKrC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJpC,QAAQ,CAAC,IAAI,aAAa;IAC1B,QAAQ,CAAC,OAAO,WAAW;IAC3B,QAAQ,CAAC,WAAW,8CAA8C;gBAErC,OAAO,GAAE,qBAA0B;IAEhE,YAAY,IAAI,QAAQ,EAAE;IAoB1B,UAAU,IAAI,KAAK,CAAC,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;IAI/C,cAAc,IAAI,IAAI,EAAE;CAOzB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shared/constants/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,eAAuC,CAAC;AAC3E,eAAO,MAAM,eAAe,eAAgC,CAAC;AAC7D,eAAO,MAAM,gBAAgB,eAAiC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { RedisXError } from '@nestjs-redisx/core';
|
|
2
|
+
export declare class MetricsError extends RedisXError {
|
|
3
|
+
constructor(message: string, cause?: Error);
|
|
4
|
+
}
|
|
5
|
+
export declare class MetricRegistrationError extends MetricsError {
|
|
6
|
+
constructor(metricName: string, cause?: Error);
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shared/errors/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAa,MAAM,qBAAqB,CAAC;AAE7D,qBAAa,YAAa,SAAQ,WAAW;gBAC/B,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAG3C;AAED,qBAAa,uBAAwB,SAAQ,YAAY;gBAC3C,UAAU,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAG9C"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export interface IMetricsPluginOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Make the module global.
|
|
4
|
+
* @default false
|
|
5
|
+
*/
|
|
6
|
+
isGlobal?: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Enable metrics collection.
|
|
9
|
+
* @default true
|
|
10
|
+
*/
|
|
11
|
+
enabled?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Metrics prefix.
|
|
14
|
+
* @default 'redisx_'
|
|
15
|
+
*/
|
|
16
|
+
prefix?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Default labels added to all metrics.
|
|
19
|
+
*/
|
|
20
|
+
defaultLabels?: Record<string, string>;
|
|
21
|
+
/**
|
|
22
|
+
* Histogram buckets for latency (in seconds).
|
|
23
|
+
* @default [0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10]
|
|
24
|
+
*/
|
|
25
|
+
histogramBuckets?: number[];
|
|
26
|
+
/**
|
|
27
|
+
* Expose /metrics endpoint.
|
|
28
|
+
* @default true
|
|
29
|
+
*/
|
|
30
|
+
exposeEndpoint?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Metrics endpoint path.
|
|
33
|
+
* Note: NestJS `@Controller()` path is a compile-time constant.
|
|
34
|
+
* This option is reserved for future use. The endpoint is always `/metrics`.
|
|
35
|
+
* @default '/metrics'
|
|
36
|
+
*/
|
|
37
|
+
endpoint?: string;
|
|
38
|
+
/**
|
|
39
|
+
* Collect default Node.js metrics.
|
|
40
|
+
* @default true
|
|
41
|
+
*/
|
|
42
|
+
collectDefaultMetrics?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Enable detailed command metrics.
|
|
45
|
+
* @default true
|
|
46
|
+
*/
|
|
47
|
+
commandMetrics?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Enable plugin-specific metrics (cache, locks, etc).
|
|
50
|
+
* @default true
|
|
51
|
+
*/
|
|
52
|
+
pluginMetrics?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Collection interval for gauges (ms).
|
|
55
|
+
* @default 15000
|
|
56
|
+
*/
|
|
57
|
+
collectInterval?: number;
|
|
58
|
+
}
|
|
59
|
+
export interface IMetricsJson {
|
|
60
|
+
name: string;
|
|
61
|
+
help: string;
|
|
62
|
+
type: string;
|
|
63
|
+
values: Array<{
|
|
64
|
+
labels: Record<string, string>;
|
|
65
|
+
value: number;
|
|
66
|
+
}>;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shared/types/index.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEvC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE5B;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAEhC;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,KAAK,CAAC;QACZ,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC/B,KAAK,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;CACJ"}
|
package/package.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nestjs-redisx/metrics",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Prometheus metrics plugin for NestJS RedisX with custom metrics support",
|
|
5
|
+
"author": "NestJS RedisX Team",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"require": "./dist/index.js",
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"default": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"README.md",
|
|
20
|
+
"LICENSE"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsup",
|
|
24
|
+
"test": "SKIP_INTEGRATION=true vitest run",
|
|
25
|
+
"test:watch": "SKIP_INTEGRATION=true vitest",
|
|
26
|
+
"test:cov": "SKIP_INTEGRATION=true vitest run --coverage",
|
|
27
|
+
"lint": "eslint \"{src,test}/**/*.ts\"",
|
|
28
|
+
"format": "prettier --write \"{src,test}/**/*.ts\""
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"prom-client": "^15.1.0"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"nestjs",
|
|
35
|
+
"redis",
|
|
36
|
+
"metrics",
|
|
37
|
+
"prometheus",
|
|
38
|
+
"monitoring",
|
|
39
|
+
"observability"
|
|
40
|
+
],
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "https://github.com/nestjs-redisx/nestjs-redisx.git",
|
|
44
|
+
"directory": "packages/metrics"
|
|
45
|
+
},
|
|
46
|
+
"homepage": "https://nestjs-redisx.dev/en/reference/metrics/",
|
|
47
|
+
"bugs": {
|
|
48
|
+
"url": "https://github.com/nestjs-redisx/nestjs-redisx/issues"
|
|
49
|
+
},
|
|
50
|
+
"peerDependencies": {
|
|
51
|
+
"@nestjs-redisx/core": "^1.0.0",
|
|
52
|
+
"@nestjs/common": "^10.0.0",
|
|
53
|
+
"@nestjs/core": "^10.0.0",
|
|
54
|
+
"reflect-metadata": "^0.2.0",
|
|
55
|
+
"rxjs": "^7.8.0"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@nestjs/testing": "^10.0.0",
|
|
59
|
+
"@types/express": "^4.17.0",
|
|
60
|
+
"@types/node": "^20.0.0",
|
|
61
|
+
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
62
|
+
"@typescript-eslint/parser": "^6.0.0",
|
|
63
|
+
"eslint": "^8.0.0",
|
|
64
|
+
"prettier": "^3.0.0",
|
|
65
|
+
"tsup": "^8.0.0",
|
|
66
|
+
"typescript": "^5.3.0",
|
|
67
|
+
"vitest": "^1.6.0",
|
|
68
|
+
"@vitest/coverage-v8": "^1.6.0"
|
|
69
|
+
},
|
|
70
|
+
"publishConfig": {
|
|
71
|
+
"access": "public"
|
|
72
|
+
}
|
|
73
|
+
}
|