@stacksjs/bun-router 0.0.13 → 0.0.14
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/CHANGELOG.md +770 -0
- package/README.md +584 -261
- package/package.json +43 -47
- package/bin/cli.ts +0 -9
- package/dist/auth.d.ts +0 -134
- package/dist/cache/lru-cache.d.ts +0 -139
- package/dist/cache/middleware-memoization.d.ts +0 -151
- package/dist/cache/route-cache-warmer.d.ts +0 -161
- package/dist/cache/sqlite-cache.d.ts +0 -209
- package/dist/cache/streaming-cache.d.ts +0 -132
- package/dist/chunk-1mvtv6jw.js +0 -13012
- package/dist/cli/colors.d.ts +0 -15
- package/dist/cli/index.d.ts +0 -10
- package/dist/cli/middleware.d.ts +0 -31
- package/dist/cli/openapi.d.ts +0 -17
- package/dist/cli/router.d.ts +0 -15
- package/dist/cli/routes.d.ts +0 -29
- package/dist/cli/utils.d.ts +0 -74
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +0 -3195
- package/dist/config.d.ts +0 -7
- package/dist/container/container.d.ts +0 -273
- package/dist/container/contextual-binding.d.ts +0 -240
- package/dist/container/decorators.d.ts +0 -141
- package/dist/container/service-provider.d.ts +0 -285
- package/dist/development/hot-reload.d.ts +0 -187
- package/dist/development/index.d.ts +0 -167
- package/dist/development/performance-profiler.d.ts +0 -217
- package/dist/development/route-debugger.d.ts +0 -154
- package/dist/development/route-inspector.d.ts +0 -211
- package/dist/development/typescript-utilities.d.ts +0 -209
- package/dist/docs.d.ts +0 -11
- package/dist/errors/circuit-breaker.d.ts +0 -195
- package/dist/errors/error-handler.d.ts +0 -88
- package/dist/errors/error-reporting.d.ts +0 -144
- package/dist/errors/exceptions.d.ts +0 -184
- package/dist/errors/graceful-degradation.d.ts +0 -154
- package/dist/errors/index.d.ts +0 -9
- package/dist/errors/router-errors.d.ts +0 -110
- package/dist/file-serving/static-files.d.ts +0 -143
- package/dist/index.d.ts +0 -14
- package/dist/index.js +0 -13933
- package/dist/middleware/auth.d.ts +0 -63
- package/dist/middleware/content_security_policy.d.ts +0 -53
- package/dist/middleware/cors.d.ts +0 -5
- package/dist/middleware/csrf.d.ts +0 -7
- package/dist/middleware/ddos_protection.d.ts +0 -39
- package/dist/middleware/file_security.d.ts +0 -26
- package/dist/middleware/file_upload.d.ts +0 -38
- package/dist/middleware/helmet.d.ts +0 -54
- package/dist/middleware/index.d.ts +0 -44
- package/dist/middleware/input_validation.d.ts +0 -45
- package/dist/middleware/json_body.d.ts +0 -4
- package/dist/middleware/performance_alerting.d.ts +0 -87
- package/dist/middleware/performance_dashboard.d.ts +0 -87
- package/dist/middleware/performance_monitor.d.ts +0 -209
- package/dist/middleware/pipeline.d.ts +0 -131
- package/dist/middleware/rate_limit.d.ts +0 -36
- package/dist/middleware/request_id.d.ts +0 -4
- package/dist/middleware/request_signing.d.ts +0 -153
- package/dist/middleware/request_tracer.d.ts +0 -72
- package/dist/middleware/response_cache.d.ts +0 -97
- package/dist/middleware/security.d.ts +0 -69
- package/dist/middleware/security_suite.d.ts +0 -46
- package/dist/middleware/session.d.ts +0 -23
- package/dist/model-binding/index.d.ts +0 -2
- package/dist/model-binding/model-middleware.d.ts +0 -118
- package/dist/model-binding/model-registry.d.ts +0 -164
- package/dist/model-binding.d.ts +0 -185
- package/dist/model-resolver-factory.d.ts +0 -31
- package/dist/observability/correlation.d.ts +0 -187
- package/dist/observability/health-checks.d.ts +0 -186
- package/dist/observability/index.d.ts +0 -60
- package/dist/observability/integration.d.ts +0 -147
- package/dist/observability/metrics.d.ts +0 -184
- package/dist/observability/tracing.d.ts +0 -187
- package/dist/optimization/bun-utilities.d.ts +0 -224
- package/dist/query-builder-integration.d.ts +0 -36
- package/dist/request/context.d.ts +0 -34
- package/dist/request/enhanced-request.d.ts +0 -213
- package/dist/request/macros.d.ts +0 -300
- package/dist/response/macros.d.ts +0 -245
- package/dist/response/response-factory.d.ts +0 -133
- package/dist/router/api-routes.d.ts +0 -5
- package/dist/router/file-based-routing.d.ts +0 -118
- package/dist/router/file-streaming.d.ts +0 -5
- package/dist/router/fluent-router.d.ts +0 -315
- package/dist/router/fluent-routing.d.ts +0 -271
- package/dist/router/group-organization.d.ts +0 -5
- package/dist/router/handler-resolver.d.ts +0 -24
- package/dist/router/http-methods.d.ts +0 -10
- package/dist/router/index.d.ts +0 -114
- package/dist/router/middleware-groups.d.ts +0 -94
- package/dist/router/middleware-integration.d.ts +0 -112
- package/dist/router/middleware.d.ts +0 -5
- package/dist/router/model-binding.d.ts +0 -5
- package/dist/router/optimized-route-matching.d.ts +0 -6
- package/dist/router/route-building.d.ts +0 -5
- package/dist/router/route-compiler.d.ts +0 -153
- package/dist/router/route-matching.d.ts +0 -5
- package/dist/router/route-trie.d.ts +0 -114
- package/dist/router/router.d.ts +0 -294
- package/dist/router/server.d.ts +0 -5
- package/dist/router/validation-integration.d.ts +0 -170
- package/dist/router/view-rendering.d.ts +0 -5
- package/dist/router/websocket.d.ts +0 -5
- package/dist/routing/route-caching.d.ts +0 -129
- package/dist/routing/route-throttling.d.ts +0 -150
- package/dist/routing/subdomain-routing.d.ts +0 -206
- package/dist/session/database-store.d.ts +0 -51
- package/dist/session/file-store.d.ts +0 -22
- package/dist/session/index.d.ts +0 -106
- package/dist/session/memory-store.d.ts +0 -21
- package/dist/session/redis-store.d.ts +0 -31
- package/dist/streaming/index.d.ts +0 -3
- package/dist/streaming/sse-handler.d.ts +0 -138
- package/dist/streaming/stream-handler.d.ts +0 -114
- package/dist/testing/auth-testing.d.ts +0 -156
- package/dist/testing/file-upload-testing.d.ts +0 -190
- package/dist/testing/index.d.ts +0 -10
- package/dist/testing/middleware-testing.d.ts +0 -138
- package/dist/testing/model-binding-testing.d.ts +0 -186
- package/dist/testing/performance-testing.d.ts +0 -235
- package/dist/testing/test-client.d.ts +0 -117
- package/dist/testing/test-request.d.ts +0 -85
- package/dist/testing/test-response.d.ts +0 -90
- package/dist/testing/types.d.ts +0 -207
- package/dist/testing/websocket-testing.d.ts +0 -227
- package/dist/types/controller-types.d.ts +0 -208
- package/dist/types/core.d.ts +0 -543
- package/dist/types/middleware-types.d.ts +0 -227
- package/dist/types/request-response-augmentation.d.ts +0 -261
- package/dist/types/route-inference.d.ts +0 -168
- package/dist/types.d.ts +0 -1782
- package/dist/url.d.ts +0 -56
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/query-preservation.d.ts +0 -48
- package/dist/utils.d.ts +0 -69
- package/dist/validation/validator.d.ts +0 -140
- package/dist/websocket/clustering.d.ts +0 -185
- package/src/auth.ts +0 -469
- package/src/cache/lru-cache.ts +0 -457
- package/src/cache/middleware-memoization.ts +0 -531
- package/src/cache/route-cache-warmer.ts +0 -486
- package/src/cache/sqlite-cache.ts +0 -783
- package/src/cache/streaming-cache.ts +0 -572
- package/src/cli/colors.ts +0 -29
- package/src/cli/index.ts +0 -287
- package/src/cli/middleware.ts +0 -291
- package/src/cli/openapi.ts +0 -407
- package/src/cli/router.ts +0 -188
- package/src/cli/routes.ts +0 -265
- package/src/cli/utils.ts +0 -531
- package/src/cli.ts +0 -5
- package/src/config.ts +0 -322
- package/src/container/container.ts +0 -740
- package/src/container/contextual-binding.ts +0 -603
- package/src/container/decorators.ts +0 -359
- package/src/container/service-provider.ts +0 -596
- package/src/development/hot-reload.ts +0 -673
- package/src/development/index.ts +0 -499
- package/src/development/performance-profiler.ts +0 -717
- package/src/development/route-debugger.ts +0 -527
- package/src/development/route-inspector.ts +0 -749
- package/src/development/typescript-utilities.ts +0 -682
- package/src/docs.ts +0 -397
- package/src/errors/circuit-breaker.ts +0 -732
- package/src/errors/error-handler.ts +0 -569
- package/src/errors/error-reporting.ts +0 -672
- package/src/errors/exceptions.ts +0 -536
- package/src/errors/graceful-degradation.ts +0 -621
- package/src/errors/index.ts +0 -21
- package/src/errors/router-errors.ts +0 -632
- package/src/file-serving/static-files.ts +0 -581
- package/src/index.ts +0 -14
- package/src/middleware/auth.ts +0 -219
- package/src/middleware/content_security_policy.ts +0 -215
- package/src/middleware/cors.ts +0 -74
- package/src/middleware/csrf.ts +0 -108
- package/src/middleware/ddos_protection.ts +0 -255
- package/src/middleware/file_security.ts +0 -191
- package/src/middleware/file_upload.ts +0 -264
- package/src/middleware/helmet.ts +0 -268
- package/src/middleware/index.ts +0 -117
- package/src/middleware/input_validation.ts +0 -449
- package/src/middleware/json_body.ts +0 -37
- package/src/middleware/performance_alerting.ts +0 -538
- package/src/middleware/performance_dashboard.ts +0 -661
- package/src/middleware/performance_monitor.ts +0 -943
- package/src/middleware/pipeline.ts +0 -489
- package/src/middleware/rate_limit.ts +0 -245
- package/src/middleware/request_id.ts +0 -36
- package/src/middleware/request_signing.ts +0 -636
- package/src/middleware/request_tracer.ts +0 -636
- package/src/middleware/response_cache.ts +0 -743
- package/src/middleware/security.ts +0 -482
- package/src/middleware/security_suite.ts +0 -257
- package/src/middleware/session.ts +0 -91
- package/src/model-binding/index.ts +0 -18
- package/src/model-binding/model-middleware.ts +0 -425
- package/src/model-binding/model-registry.ts +0 -550
- package/src/model-binding.ts +0 -370
- package/src/model-resolver-factory.ts +0 -106
- package/src/observability/correlation.ts +0 -691
- package/src/observability/health-checks.ts +0 -729
- package/src/observability/index.ts +0 -184
- package/src/observability/integration.ts +0 -548
- package/src/observability/metrics.ts +0 -753
- package/src/observability/tracing.ts +0 -638
- package/src/optimization/bun-utilities.ts +0 -778
- package/src/query-builder-integration.ts +0 -137
- package/src/request/context.ts +0 -62
- package/src/request/enhanced-request.ts +0 -857
- package/src/request/macros.ts +0 -688
- package/src/response/macros.ts +0 -612
- package/src/response/response-factory.ts +0 -596
- package/src/router/api-routes.ts +0 -243
- package/src/router/file-based-routing.ts +0 -670
- package/src/router/file-streaming.ts +0 -372
- package/src/router/fluent-router.ts +0 -927
- package/src/router/fluent-routing.ts +0 -797
- package/src/router/group-organization.ts +0 -213
- package/src/router/handler-resolver.ts +0 -291
- package/src/router/http-methods.ts +0 -377
- package/src/router/index.ts +0 -187
- package/src/router/middleware-groups.ts +0 -222
- package/src/router/middleware-integration.ts +0 -399
- package/src/router/middleware.ts +0 -231
- package/src/router/model-binding.ts +0 -215
- package/src/router/optimized-route-matching.ts +0 -253
- package/src/router/route-building.ts +0 -212
- package/src/router/route-compiler.ts +0 -702
- package/src/router/route-matching.ts +0 -349
- package/src/router/route-trie.ts +0 -464
- package/src/router/router.ts +0 -1581
- package/src/router/server.ts +0 -462
- package/src/router/validation-integration.ts +0 -443
- package/src/router/view-rendering.ts +0 -233
- package/src/router/websocket.ts +0 -100
- package/src/routing/route-caching.ts +0 -402
- package/src/routing/route-throttling.ts +0 -469
- package/src/routing/subdomain-routing.ts +0 -492
- package/src/session/database-store.ts +0 -109
- package/src/session/file-store.ts +0 -148
- package/src/session/index.ts +0 -244
- package/src/session/memory-store.ts +0 -88
- package/src/session/redis-store.ts +0 -93
- package/src/streaming/index.ts +0 -17
- package/src/streaming/sse-handler.ts +0 -482
- package/src/streaming/stream-handler.ts +0 -552
- package/src/testing/auth-testing.ts +0 -446
- package/src/testing/file-upload-testing.ts +0 -543
- package/src/testing/index.ts +0 -10
- package/src/testing/middleware-testing.ts +0 -322
- package/src/testing/model-binding-testing.ts +0 -645
- package/src/testing/performance-testing.ts +0 -738
- package/src/testing/test-client.ts +0 -310
- package/src/testing/test-request.ts +0 -315
- package/src/testing/test-response.ts +0 -332
- package/src/testing/types.ts +0 -224
- package/src/testing/websocket-testing.ts +0 -590
- package/src/types/controller-types.ts +0 -385
- package/src/types/core.ts +0 -683
- package/src/types/middleware-types.ts +0 -419
- package/src/types/request-response-augmentation.ts +0 -489
- package/src/types/route-inference.ts +0 -357
- package/src/types.ts +0 -2055
- package/src/url.ts +0 -126
- package/src/utils/index.ts +0 -1
- package/src/utils/query-preservation.ts +0 -201
- package/src/utils.ts +0 -327
- package/src/validation/validator.ts +0 -685
- package/src/websocket/clustering.ts +0 -762
|
@@ -1,753 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Observability & Monitoring - Custom Metrics Collection with Prometheus Format
|
|
3
|
-
*
|
|
4
|
-
* Enterprise-grade metrics collection and Prometheus-compatible exposition
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { EnhancedRequest } from '../types'
|
|
8
|
-
import process from 'node:process'
|
|
9
|
-
|
|
10
|
-
export interface MetricConfig {
|
|
11
|
-
prefix?: string
|
|
12
|
-
labels?: Record<string, string>
|
|
13
|
-
enableDefaultMetrics?: boolean
|
|
14
|
-
collectInterval?: number
|
|
15
|
-
maxHistogramBuckets?: number
|
|
16
|
-
maxSummaryAge?: number
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface MetricLabels {
|
|
20
|
-
[key: string]: string
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface HistogramBucket {
|
|
24
|
-
le: number
|
|
25
|
-
count: number
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface SummaryQuantile {
|
|
29
|
-
quantile: number
|
|
30
|
-
value: number
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Base metric interface
|
|
35
|
-
*/
|
|
36
|
-
export abstract class Metric {
|
|
37
|
-
public readonly name: string
|
|
38
|
-
public readonly help: string
|
|
39
|
-
public readonly type: string
|
|
40
|
-
public readonly labels: MetricLabels
|
|
41
|
-
|
|
42
|
-
constructor(name: string, help: string, type: string, labels: MetricLabels = {}) {
|
|
43
|
-
this.name = name
|
|
44
|
-
this.help = help
|
|
45
|
-
this.type = type
|
|
46
|
-
this.labels = labels
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
abstract getValue(): number | string
|
|
50
|
-
abstract reset(): void
|
|
51
|
-
abstract toPrometheusString(): string
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Counter metric - monotonically increasing value
|
|
56
|
-
*/
|
|
57
|
-
export class Counter extends Metric {
|
|
58
|
-
private value = 0
|
|
59
|
-
private labeledCounters = new Map<string, number>()
|
|
60
|
-
|
|
61
|
-
constructor(name: string, help: string, labels: MetricLabels = {}) {
|
|
62
|
-
super(name, help, 'counter', labels)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
inc(value = 1, labels: MetricLabels = {}): void {
|
|
66
|
-
if (Object.keys(labels).length === 0) {
|
|
67
|
-
this.value += value
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
const key = this.getLabelKey(labels)
|
|
71
|
-
this.labeledCounters.set(key, (this.labeledCounters.get(key) || 0) + value)
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
getValue(): number {
|
|
76
|
-
return this.value
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
reset(): void {
|
|
80
|
-
this.value = 0
|
|
81
|
-
this.labeledCounters.clear()
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
private getLabelKey(labels: MetricLabels): string {
|
|
85
|
-
return Object.entries({ ...this.labels, ...labels })
|
|
86
|
-
.sort(([a], [b]) => a.localeCompare(b))
|
|
87
|
-
.map(([k, v]) => `${k}="${v}"`)
|
|
88
|
-
.join(',')
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
toPrometheusString(): string {
|
|
92
|
-
let output = `# HELP ${this.name} ${this.help}\n`
|
|
93
|
-
output += `# TYPE ${this.name} counter\n`
|
|
94
|
-
|
|
95
|
-
if (this.labeledCounters.size === 0) {
|
|
96
|
-
const labelStr = Object.keys(this.labels).length > 0
|
|
97
|
-
? `{${this.getLabelKey(this.labels)}}`
|
|
98
|
-
: ''
|
|
99
|
-
output += `${this.name}${labelStr} ${this.value}\n`
|
|
100
|
-
}
|
|
101
|
-
else {
|
|
102
|
-
for (const [labelKey, value] of this.labeledCounters.entries()) {
|
|
103
|
-
output += `${this.name}{${labelKey}} ${value}\n`
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
return output
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Gauge metric - can go up and down
|
|
113
|
-
*/
|
|
114
|
-
export class Gauge extends Metric {
|
|
115
|
-
private value = 0
|
|
116
|
-
private labeledGauges = new Map<string, number>()
|
|
117
|
-
|
|
118
|
-
constructor(name: string, help: string, labels: MetricLabels = {}) {
|
|
119
|
-
super(name, help, 'gauge', labels)
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
set(value: number, labels: MetricLabels = {}): void {
|
|
123
|
-
if (Object.keys(labels).length === 0) {
|
|
124
|
-
this.value = value
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
127
|
-
const key = this.getLabelKey(labels)
|
|
128
|
-
this.labeledGauges.set(key, value)
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
inc(value = 1, labels: MetricLabels = {}): void {
|
|
133
|
-
if (Object.keys(labels).length === 0) {
|
|
134
|
-
this.value += value
|
|
135
|
-
}
|
|
136
|
-
else {
|
|
137
|
-
const key = this.getLabelKey(labels)
|
|
138
|
-
this.labeledGauges.set(key, (this.labeledGauges.get(key) || 0) + value)
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
dec(value = 1, labels: MetricLabels = {}): void {
|
|
143
|
-
this.inc(-value, labels)
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
getValue(): number {
|
|
147
|
-
return this.value
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
reset(): void {
|
|
151
|
-
this.value = 0
|
|
152
|
-
this.labeledGauges.clear()
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
private getLabelKey(labels: MetricLabels): string {
|
|
156
|
-
return Object.entries({ ...this.labels, ...labels })
|
|
157
|
-
.sort(([a], [b]) => a.localeCompare(b))
|
|
158
|
-
.map(([k, v]) => `${k}="${v}"`)
|
|
159
|
-
.join(',')
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
toPrometheusString(): string {
|
|
163
|
-
let output = `# HELP ${this.name} ${this.help}\n`
|
|
164
|
-
output += `# TYPE ${this.name} gauge\n`
|
|
165
|
-
|
|
166
|
-
if (this.labeledGauges.size === 0) {
|
|
167
|
-
const labelStr = Object.keys(this.labels).length > 0
|
|
168
|
-
? `{${this.getLabelKey(this.labels)}}`
|
|
169
|
-
: ''
|
|
170
|
-
output += `${this.name}${labelStr} ${this.value}\n`
|
|
171
|
-
}
|
|
172
|
-
else {
|
|
173
|
-
for (const [labelKey, value] of this.labeledGauges.entries()) {
|
|
174
|
-
output += `${this.name}{${labelKey}} ${value}\n`
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return output
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Histogram metric - tracks distribution of values
|
|
184
|
-
*/
|
|
185
|
-
export class Histogram extends Metric {
|
|
186
|
-
private buckets: Map<number, number> = new Map()
|
|
187
|
-
private sum = 0
|
|
188
|
-
private count = 0
|
|
189
|
-
private readonly bucketBounds: number[]
|
|
190
|
-
|
|
191
|
-
constructor(
|
|
192
|
-
name: string,
|
|
193
|
-
help: string,
|
|
194
|
-
buckets: number[] = [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10],
|
|
195
|
-
labels: MetricLabels = {},
|
|
196
|
-
) {
|
|
197
|
-
super(name, help, 'histogram', labels)
|
|
198
|
-
this.bucketBounds = [...buckets, Infinity].sort((a, b) => a - b)
|
|
199
|
-
|
|
200
|
-
// Initialize buckets
|
|
201
|
-
for (const bound of this.bucketBounds) {
|
|
202
|
-
this.buckets.set(bound, 0)
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
observe(value: number, _labels: MetricLabels = {}): void {
|
|
207
|
-
this.sum += value
|
|
208
|
-
this.count++
|
|
209
|
-
|
|
210
|
-
// Increment appropriate buckets
|
|
211
|
-
for (const bound of this.bucketBounds) {
|
|
212
|
-
if (value <= bound) {
|
|
213
|
-
this.buckets.set(bound, (this.buckets.get(bound) || 0) + 1)
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
getValue(): number {
|
|
219
|
-
return this.sum
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
getCount(): number {
|
|
223
|
-
return this.count
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
getSum(): number {
|
|
227
|
-
return this.sum
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
getBuckets(): HistogramBucket[] {
|
|
231
|
-
return Array.from(this.buckets.entries()).map(([le, count]) => ({ le, count }))
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
reset(): void {
|
|
235
|
-
this.sum = 0
|
|
236
|
-
this.count = 0
|
|
237
|
-
for (const bound of this.bucketBounds) {
|
|
238
|
-
this.buckets.set(bound, 0)
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
toPrometheusString(): string {
|
|
243
|
-
let output = `# HELP ${this.name} ${this.help}\n`
|
|
244
|
-
output += `# TYPE ${this.name} histogram\n`
|
|
245
|
-
|
|
246
|
-
const labelStr = Object.keys(this.labels).length > 0
|
|
247
|
-
? `{${Object.entries(this.labels).map(([k, v]) => `${k}="${v}"`).join(',')}}`
|
|
248
|
-
: ''
|
|
249
|
-
|
|
250
|
-
// Output buckets
|
|
251
|
-
for (const [bound, count] of this.buckets.entries()) {
|
|
252
|
-
const le = bound === Infinity ? '+Inf' : bound.toString()
|
|
253
|
-
const bucketLabels = labelStr ? `{${labelStr.slice(1, -1)},le="${le}"}` : `{le="${le}"}`
|
|
254
|
-
output += `${this.name}_bucket${bucketLabels} ${count}\n`
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// Output sum and count
|
|
258
|
-
output += `${this.name}_sum${labelStr} ${this.sum}\n`
|
|
259
|
-
output += `${this.name}_count${labelStr} ${this.count}\n`
|
|
260
|
-
|
|
261
|
-
return output
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Summary metric - tracks quantiles over sliding time window
|
|
267
|
-
*/
|
|
268
|
-
export class Summary extends Metric {
|
|
269
|
-
private observations: Array<{ value: number, timestamp: number }> = []
|
|
270
|
-
private sum = 0
|
|
271
|
-
private count = 0
|
|
272
|
-
private readonly quantiles: number[]
|
|
273
|
-
private readonly maxAge: number
|
|
274
|
-
|
|
275
|
-
constructor(
|
|
276
|
-
name: string,
|
|
277
|
-
help: string,
|
|
278
|
-
quantiles: number[] = [0.5, 0.9, 0.95, 0.99],
|
|
279
|
-
maxAge = 600000, // 10 minutes
|
|
280
|
-
labels: MetricLabels = {},
|
|
281
|
-
) {
|
|
282
|
-
super(name, help, 'summary', labels)
|
|
283
|
-
this.quantiles = quantiles.sort((a, b) => a - b)
|
|
284
|
-
this.maxAge = maxAge
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
observe(value: number, _labels: MetricLabels = {}): void {
|
|
288
|
-
const now = Date.now()
|
|
289
|
-
this.observations.push({ value, timestamp: now })
|
|
290
|
-
this.sum += value
|
|
291
|
-
this.count++
|
|
292
|
-
|
|
293
|
-
// Clean old observations
|
|
294
|
-
this.cleanOldObservations(now)
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
getValue(): number {
|
|
298
|
-
return this.sum
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
getCount(): number {
|
|
302
|
-
return this.count
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
getSum(): number {
|
|
306
|
-
return this.sum
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
getQuantiles(): SummaryQuantile[] {
|
|
310
|
-
this.cleanOldObservations(Date.now())
|
|
311
|
-
|
|
312
|
-
if (this.observations.length === 0) {
|
|
313
|
-
return this.quantiles.map(q => ({ quantile: q, value: 0 }))
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
const sortedValues = this.observations
|
|
317
|
-
.map(obs => obs.value)
|
|
318
|
-
.sort((a, b) => a - b)
|
|
319
|
-
|
|
320
|
-
return this.quantiles.map((quantile) => {
|
|
321
|
-
const index = Math.ceil(quantile * sortedValues.length) - 1
|
|
322
|
-
const value = sortedValues[Math.max(0, index)] || 0
|
|
323
|
-
return { quantile, value }
|
|
324
|
-
})
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
private cleanOldObservations(now: number): void {
|
|
328
|
-
const cutoff = now - this.maxAge
|
|
329
|
-
const oldLength = this.observations.length
|
|
330
|
-
|
|
331
|
-
this.observations = this.observations.filter(obs => obs.timestamp >= cutoff)
|
|
332
|
-
|
|
333
|
-
// Adjust sum and count for removed observations
|
|
334
|
-
const removedCount = oldLength - this.observations.length
|
|
335
|
-
if (removedCount > 0) {
|
|
336
|
-
// Recalculate sum from remaining observations
|
|
337
|
-
this.sum = this.observations.reduce((sum, obs) => sum + obs.value, 0)
|
|
338
|
-
this.count = this.observations.length
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
reset(): void {
|
|
343
|
-
this.observations = []
|
|
344
|
-
this.sum = 0
|
|
345
|
-
this.count = 0
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
toPrometheusString(): string {
|
|
349
|
-
let output = `# HELP ${this.name} ${this.help}\n`
|
|
350
|
-
output += `# TYPE ${this.name} summary\n`
|
|
351
|
-
|
|
352
|
-
const labelStr = Object.keys(this.labels).length > 0
|
|
353
|
-
? `{${Object.entries(this.labels).map(([k, v]) => `${k}="${v}"`).join(',')}}`
|
|
354
|
-
: ''
|
|
355
|
-
|
|
356
|
-
// Output quantiles
|
|
357
|
-
const quantiles = this.getQuantiles()
|
|
358
|
-
for (const { quantile, value } of quantiles) {
|
|
359
|
-
const quantileLabels = labelStr
|
|
360
|
-
? `{${labelStr.slice(1, -1)},quantile="${quantile}"}`
|
|
361
|
-
: `{quantile="${quantile}"}`
|
|
362
|
-
output += `${this.name}${quantileLabels} ${value}\n`
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
// Output sum and count
|
|
366
|
-
output += `${this.name}_sum${labelStr} ${this.sum}\n`
|
|
367
|
-
output += `${this.name}_count${labelStr} ${this.count}\n`
|
|
368
|
-
|
|
369
|
-
return output
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
/**
|
|
374
|
-
* Metrics registry
|
|
375
|
-
*/
|
|
376
|
-
export class MetricsRegistry {
|
|
377
|
-
private metrics = new Map<string, Metric>()
|
|
378
|
-
private config: MetricConfig
|
|
379
|
-
private defaultMetrics: Map<string, Metric> = new Map()
|
|
380
|
-
|
|
381
|
-
constructor(config: MetricConfig = {}) {
|
|
382
|
-
this.config = {
|
|
383
|
-
prefix: '',
|
|
384
|
-
enableDefaultMetrics: true,
|
|
385
|
-
collectInterval: 15000, // 15 seconds
|
|
386
|
-
maxHistogramBuckets: 20,
|
|
387
|
-
maxSummaryAge: 600000, // 10 minutes
|
|
388
|
-
...config,
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
if (this.config.enableDefaultMetrics) {
|
|
392
|
-
this.registerDefaultMetrics()
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
/**
|
|
397
|
-
* Register a metric
|
|
398
|
-
*/
|
|
399
|
-
register(metric: Metric): void {
|
|
400
|
-
const name = this.config.prefix ? `${this.config.prefix}_${metric.name}` : metric.name
|
|
401
|
-
this.metrics.set(name, metric)
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
/**
|
|
405
|
-
* Get a metric by name
|
|
406
|
-
*/
|
|
407
|
-
get(name: string): Metric | undefined {
|
|
408
|
-
const fullName = this.config.prefix ? `${this.config.prefix}_${name}` : name
|
|
409
|
-
return this.metrics.get(fullName)
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
/**
|
|
413
|
-
* Create and register a counter
|
|
414
|
-
*/
|
|
415
|
-
createCounter(name: string, help: string, labels: MetricLabels = {}): Counter {
|
|
416
|
-
const counter = new Counter(name, help, labels)
|
|
417
|
-
this.register(counter)
|
|
418
|
-
return counter
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
/**
|
|
422
|
-
* Create and register a gauge
|
|
423
|
-
*/
|
|
424
|
-
createGauge(name: string, help: string, labels: MetricLabels = {}): Gauge {
|
|
425
|
-
const gauge = new Gauge(name, help, labels)
|
|
426
|
-
this.register(gauge)
|
|
427
|
-
return gauge
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
/**
|
|
431
|
-
* Create and register a histogram
|
|
432
|
-
*/
|
|
433
|
-
createHistogram(
|
|
434
|
-
name: string,
|
|
435
|
-
help: string,
|
|
436
|
-
buckets?: number[],
|
|
437
|
-
labels: MetricLabels = {},
|
|
438
|
-
): Histogram {
|
|
439
|
-
const histogram = new Histogram(name, help, buckets, labels)
|
|
440
|
-
this.register(histogram)
|
|
441
|
-
return histogram
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
/**
|
|
445
|
-
* Create and register a summary
|
|
446
|
-
*/
|
|
447
|
-
createSummary(
|
|
448
|
-
name: string,
|
|
449
|
-
help: string,
|
|
450
|
-
quantiles?: number[],
|
|
451
|
-
maxAge?: number,
|
|
452
|
-
labels: MetricLabels = {},
|
|
453
|
-
): Summary {
|
|
454
|
-
const summary = new Summary(name, help, quantiles, maxAge, labels)
|
|
455
|
-
this.register(summary)
|
|
456
|
-
return summary
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
/**
|
|
460
|
-
* Register default system metrics
|
|
461
|
-
*/
|
|
462
|
-
private registerDefaultMetrics(): void {
|
|
463
|
-
// HTTP request metrics
|
|
464
|
-
const httpRequestsTotal = this.createCounter(
|
|
465
|
-
'http_requests_total',
|
|
466
|
-
'Total number of HTTP requests',
|
|
467
|
-
)
|
|
468
|
-
|
|
469
|
-
const httpRequestDuration = this.createHistogram(
|
|
470
|
-
'http_request_duration_seconds',
|
|
471
|
-
'HTTP request duration in seconds',
|
|
472
|
-
[0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10],
|
|
473
|
-
)
|
|
474
|
-
|
|
475
|
-
const httpRequestSize = this.createHistogram(
|
|
476
|
-
'http_request_size_bytes',
|
|
477
|
-
'HTTP request size in bytes',
|
|
478
|
-
[100, 1000, 10000, 100000, 1000000, 10000000],
|
|
479
|
-
)
|
|
480
|
-
|
|
481
|
-
const httpResponseSize = this.createHistogram(
|
|
482
|
-
'http_response_size_bytes',
|
|
483
|
-
'HTTP response size in bytes',
|
|
484
|
-
[100, 1000, 10000, 100000, 1000000, 10000000],
|
|
485
|
-
)
|
|
486
|
-
|
|
487
|
-
// System metrics
|
|
488
|
-
const processStartTime = this.createGauge(
|
|
489
|
-
'process_start_time_seconds',
|
|
490
|
-
'Start time of the process since unix epoch in seconds',
|
|
491
|
-
)
|
|
492
|
-
processStartTime.set(Date.now() / 1000)
|
|
493
|
-
|
|
494
|
-
const processUptime = this.createGauge(
|
|
495
|
-
'process_uptime_seconds',
|
|
496
|
-
'Process uptime in seconds',
|
|
497
|
-
)
|
|
498
|
-
|
|
499
|
-
// Memory metrics
|
|
500
|
-
const processMemoryUsage = this.createGauge(
|
|
501
|
-
'process_memory_usage_bytes',
|
|
502
|
-
'Process memory usage in bytes',
|
|
503
|
-
)
|
|
504
|
-
|
|
505
|
-
// Active connections
|
|
506
|
-
const activeConnections = this.createGauge(
|
|
507
|
-
'active_connections',
|
|
508
|
-
'Number of active connections',
|
|
509
|
-
)
|
|
510
|
-
|
|
511
|
-
this.defaultMetrics.set('http_requests_total', httpRequestsTotal)
|
|
512
|
-
this.defaultMetrics.set('http_request_duration_seconds', httpRequestDuration)
|
|
513
|
-
this.defaultMetrics.set('http_request_size_bytes', httpRequestSize)
|
|
514
|
-
this.defaultMetrics.set('http_response_size_bytes', httpResponseSize)
|
|
515
|
-
this.defaultMetrics.set('process_uptime_seconds', processUptime)
|
|
516
|
-
this.defaultMetrics.set('process_memory_usage_bytes', processMemoryUsage)
|
|
517
|
-
this.defaultMetrics.set('active_connections', activeConnections)
|
|
518
|
-
|
|
519
|
-
// Start collection interval for system metrics
|
|
520
|
-
if (this.config.collectInterval && this.config.collectInterval > 0) {
|
|
521
|
-
setInterval(() => {
|
|
522
|
-
this.collectSystemMetrics()
|
|
523
|
-
}, this.config.collectInterval)
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
/**
|
|
528
|
-
* Collect system metrics
|
|
529
|
-
*/
|
|
530
|
-
private collectSystemMetrics(): void {
|
|
531
|
-
try {
|
|
532
|
-
// Update uptime
|
|
533
|
-
const uptimeGauge = this.defaultMetrics.get('process_uptime_seconds') as Gauge
|
|
534
|
-
if (uptimeGauge) {
|
|
535
|
-
uptimeGauge.set(process.uptime())
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
// Update memory usage
|
|
539
|
-
const memoryGauge = this.defaultMetrics.get('process_memory_usage_bytes') as Gauge
|
|
540
|
-
if (memoryGauge && typeof process.memoryUsage === 'function') {
|
|
541
|
-
const memUsage = process.memoryUsage()
|
|
542
|
-
memoryGauge.set(memUsage.rss)
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
catch (error) {
|
|
546
|
-
console.error('Error collecting system metrics:', error)
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
/**
|
|
551
|
-
* Get all metrics in Prometheus format
|
|
552
|
-
*/
|
|
553
|
-
toPrometheusString(): string {
|
|
554
|
-
let output = ''
|
|
555
|
-
|
|
556
|
-
for (const metric of this.metrics.values()) {
|
|
557
|
-
output += `${metric.toPrometheusString()}\n`
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
return output.trim()
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
/**
|
|
564
|
-
* Get metrics as JSON
|
|
565
|
-
*/
|
|
566
|
-
toJSON(): Record<string, any> {
|
|
567
|
-
const result: Record<string, any> = {}
|
|
568
|
-
|
|
569
|
-
for (const [name, metric] of this.metrics.entries()) {
|
|
570
|
-
result[name] = {
|
|
571
|
-
type: metric.type,
|
|
572
|
-
help: metric.help,
|
|
573
|
-
value: metric.getValue(),
|
|
574
|
-
labels: metric.labels,
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
return result
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
/**
|
|
582
|
-
* Reset all metrics
|
|
583
|
-
*/
|
|
584
|
-
reset(): void {
|
|
585
|
-
for (const metric of this.metrics.values()) {
|
|
586
|
-
metric.reset()
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
/**
|
|
591
|
-
* Get metric names
|
|
592
|
-
*/
|
|
593
|
-
getMetricNames(): string[] {
|
|
594
|
-
return Array.from(this.metrics.keys())
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
/**
|
|
598
|
-
* Remove a metric
|
|
599
|
-
*/
|
|
600
|
-
unregister(name: string): boolean {
|
|
601
|
-
const fullName = this.config.prefix ? `${this.config.prefix}_${name}` : name
|
|
602
|
-
return this.metrics.delete(fullName)
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
/**
|
|
606
|
-
* Clear all metrics
|
|
607
|
-
*/
|
|
608
|
-
clear(): void {
|
|
609
|
-
this.metrics.clear()
|
|
610
|
-
this.defaultMetrics.clear()
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
/**
|
|
615
|
-
* Global metrics registry
|
|
616
|
-
*/
|
|
617
|
-
let globalRegistry: MetricsRegistry | null = null
|
|
618
|
-
|
|
619
|
-
/**
|
|
620
|
-
* Initialize global metrics registry
|
|
621
|
-
*/
|
|
622
|
-
export function initializeMetrics(config?: MetricConfig): MetricsRegistry {
|
|
623
|
-
globalRegistry = new MetricsRegistry(config)
|
|
624
|
-
return globalRegistry
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
/**
|
|
628
|
-
* Get global metrics registry
|
|
629
|
-
*/
|
|
630
|
-
export function getMetricsRegistry(): MetricsRegistry | null {
|
|
631
|
-
return globalRegistry
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
/**
|
|
635
|
-
* Metrics middleware factory
|
|
636
|
-
*/
|
|
637
|
-
export function createMetricsMiddleware(_config?: Partial<MetricConfig>) {
|
|
638
|
-
return async (req: EnhancedRequest, next: () => Promise<Response>): Promise<Response> => {
|
|
639
|
-
const registry = getMetricsRegistry()
|
|
640
|
-
if (!registry) {
|
|
641
|
-
return await next()
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
const startTime = Date.now()
|
|
645
|
-
const url = new URL(req.url)
|
|
646
|
-
|
|
647
|
-
// Get metrics
|
|
648
|
-
const requestsTotal = registry.get('http_requests_total') as Counter
|
|
649
|
-
const requestDuration = registry.get('http_request_duration_seconds') as Histogram
|
|
650
|
-
const requestSize = registry.get('http_request_size_bytes') as Histogram
|
|
651
|
-
const responseSize = registry.get('http_response_size_bytes') as Histogram
|
|
652
|
-
const activeConnections = registry.get('active_connections') as Gauge
|
|
653
|
-
|
|
654
|
-
// Increment active connections
|
|
655
|
-
if (activeConnections) {
|
|
656
|
-
activeConnections.inc()
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
// Record request size
|
|
660
|
-
if (requestSize) {
|
|
661
|
-
const contentLength = req.headers.get('content-length')
|
|
662
|
-
if (contentLength) {
|
|
663
|
-
requestSize.observe(Number.parseInt(contentLength, 10))
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
let response: Response
|
|
668
|
-
try {
|
|
669
|
-
response = await next()
|
|
670
|
-
|
|
671
|
-
// Record metrics
|
|
672
|
-
const duration = (Date.now() - startTime) / 1000
|
|
673
|
-
const labels = {
|
|
674
|
-
method: req.method,
|
|
675
|
-
status: response.status.toString(),
|
|
676
|
-
path: url.pathname,
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
if (requestsTotal) {
|
|
680
|
-
requestsTotal.inc(1, labels)
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
if (requestDuration) {
|
|
684
|
-
requestDuration.observe(duration, labels)
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
if (responseSize) {
|
|
688
|
-
const contentLength = response.headers.get('content-length')
|
|
689
|
-
if (contentLength) {
|
|
690
|
-
responseSize.observe(Number.parseInt(contentLength, 10), labels)
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
catch (error) {
|
|
695
|
-
// Record error metrics
|
|
696
|
-
const duration = (Date.now() - startTime) / 1000
|
|
697
|
-
const labels = {
|
|
698
|
-
method: req.method,
|
|
699
|
-
status: '500',
|
|
700
|
-
path: url.pathname,
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
if (requestsTotal) {
|
|
704
|
-
requestsTotal.inc(1, labels)
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
if (requestDuration) {
|
|
708
|
-
requestDuration.observe(duration, labels)
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
throw error
|
|
712
|
-
}
|
|
713
|
-
finally {
|
|
714
|
-
// Decrement active connections
|
|
715
|
-
if (activeConnections) {
|
|
716
|
-
activeConnections.dec()
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
return response
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
/**
|
|
725
|
-
* Metrics endpoint handler
|
|
726
|
-
*/
|
|
727
|
-
export function createMetricsHandler() {
|
|
728
|
-
return async (req: EnhancedRequest): Promise<Response> => {
|
|
729
|
-
const registry = getMetricsRegistry()
|
|
730
|
-
if (!registry) {
|
|
731
|
-
return new Response('Metrics not initialized', { status: 500 })
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
const format = new URL(req.url).searchParams.get('format') || 'prometheus'
|
|
735
|
-
|
|
736
|
-
if (format === 'json') {
|
|
737
|
-
return new Response(JSON.stringify(registry.toJSON(), null, 2), {
|
|
738
|
-
headers: {
|
|
739
|
-
'Content-Type': 'application/json',
|
|
740
|
-
'Cache-Control': 'no-cache',
|
|
741
|
-
},
|
|
742
|
-
})
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
// Default to Prometheus format
|
|
746
|
-
return new Response(registry.toPrometheusString(), {
|
|
747
|
-
headers: {
|
|
748
|
-
'Content-Type': 'text/plain; version=0.0.4; charset=utf-8',
|
|
749
|
-
'Cache-Control': 'no-cache',
|
|
750
|
-
},
|
|
751
|
-
})
|
|
752
|
-
}
|
|
753
|
-
}
|