]>
Commit | Line | Data |
---|---|---|
630d0a1b C |
1 | import { Application, Request, Response } from 'express' |
2 | import { Meter, metrics } from '@opentelemetry/api-metrics' | |
3 | import { PrometheusExporter } from '@opentelemetry/exporter-prometheus' | |
4 | import { MeterProvider } from '@opentelemetry/sdk-metrics-base' | |
5 | import { logger } from '@server/helpers/logger' | |
6 | import { CONFIG } from '@server/initializers/config' | |
adc94cf0 C |
7 | import { |
8 | JobQueueObserversBuilder, | |
9 | LivesObserversBuilder, | |
10 | NodeJSObserversBuilder, | |
11 | StatsObserversBuilder, | |
12 | ViewersObserversBuilder | |
13 | } from './metric-helpers' | |
630d0a1b C |
14 | |
15 | class OpenTelemetryMetrics { | |
16 | ||
17 | private static instance: OpenTelemetryMetrics | |
18 | ||
19 | private meter: Meter | |
20 | ||
21 | private onRequestDuration: (req: Request, res: Response) => void | |
22 | ||
23 | private constructor () {} | |
24 | ||
25 | init (app: Application) { | |
26 | if (CONFIG.OPEN_TELEMETRY.METRICS.ENABLED !== true) return | |
27 | ||
28 | app.use((req, res, next) => { | |
29 | res.once('finish', () => { | |
30 | if (!this.onRequestDuration) return | |
31 | ||
32 | this.onRequestDuration(req as Request, res as Response) | |
33 | }) | |
34 | ||
35 | next() | |
36 | }) | |
37 | } | |
38 | ||
39 | registerMetrics () { | |
40 | if (CONFIG.OPEN_TELEMETRY.METRICS.ENABLED !== true) return | |
41 | ||
42 | logger.info('Registering Open Telemetry metrics') | |
43 | ||
44 | const provider = new MeterProvider() | |
45 | ||
46 | provider.addMetricReader(new PrometheusExporter({ port: CONFIG.OPEN_TELEMETRY.METRICS.PROMETHEUS_EXPORTER.PORT })) | |
47 | ||
48 | metrics.setGlobalMeterProvider(provider) | |
49 | ||
50 | this.meter = metrics.getMeter('default') | |
51 | ||
630d0a1b | 52 | this.buildRequestObserver() |
630d0a1b | 53 | |
cd1b8e9a C |
54 | const nodeJSObserversBuilder = new NodeJSObserversBuilder(this.meter, provider) |
55 | nodeJSObserversBuilder.buildObservers() | |
630d0a1b | 56 | |
cd1b8e9a C |
57 | const jobQueueObserversBuilder = new JobQueueObserversBuilder(this.meter) |
58 | jobQueueObserversBuilder.buildObservers() | |
630d0a1b | 59 | |
cd1b8e9a C |
60 | const statsObserversBuilder = new StatsObserversBuilder(this.meter) |
61 | statsObserversBuilder.buildObservers() | |
adc94cf0 C |
62 | |
63 | const livesObserversBuilder = new LivesObserversBuilder(this.meter) | |
64 | livesObserversBuilder.buildObservers() | |
65 | ||
66 | const viewersObserversBuilder = new ViewersObserversBuilder(this.meter) | |
67 | viewersObserversBuilder.buildObservers() | |
630d0a1b C |
68 | } |
69 | ||
70 | private buildRequestObserver () { | |
71 | const requestDuration = this.meter.createHistogram('http_request_duration_ms', { | |
72 | unit: 'milliseconds', | |
73 | description: 'Duration of HTTP requests in ms' | |
74 | }) | |
75 | ||
76 | this.onRequestDuration = (req: Request, res: Response) => { | |
77 | const duration = Date.now() - res.locals.requestStart | |
78 | ||
79 | requestDuration.record(duration, { | |
80 | path: this.buildRequestPath(req.originalUrl), | |
81 | method: req.method, | |
82 | statusCode: res.statusCode + '' | |
83 | }) | |
84 | } | |
85 | } | |
86 | ||
87 | private buildRequestPath (path: string) { | |
88 | return path.split('?')[0] | |
89 | } | |
90 | ||
91 | static get Instance () { | |
92 | return this.instance || (this.instance = new this()) | |
93 | } | |
94 | } | |
95 | ||
96 | export { | |
97 | OpenTelemetryMetrics | |
98 | } |