]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/lib/opentelemetry/metrics.ts
Merge branch 'feature/improve-live' into develop
[github/Chocobozzz/PeerTube.git] / server / lib / opentelemetry / metrics.ts
CommitLineData
630d0a1b 1import { Application, Request, Response } from 'express'
31a9ed96 2import { Meter, metrics } from '@opentelemetry/api'
630d0a1b 3import { PrometheusExporter } from '@opentelemetry/exporter-prometheus'
3d2e4f03 4import { MeterProvider } from '@opentelemetry/sdk-metrics'
630d0a1b
C
5import { logger } from '@server/helpers/logger'
6import { CONFIG } from '@server/initializers/config'
fd3c2e87
C
7import { MVideoImmutable } from '@server/types/models'
8import { PlaybackMetricCreate } from '@shared/models'
adc94cf0
C
9import {
10 JobQueueObserversBuilder,
11 LivesObserversBuilder,
12 NodeJSObserversBuilder,
fd3c2e87 13 PlaybackMetrics,
adc94cf0
C
14 StatsObserversBuilder,
15 ViewersObserversBuilder
16} from './metric-helpers'
630d0a1b
C
17
18class OpenTelemetryMetrics {
19
20 private static instance: OpenTelemetryMetrics
21
22 private meter: Meter
23
24 private onRequestDuration: (req: Request, res: Response) => void
25
fd3c2e87
C
26 private playbackMetrics: PlaybackMetrics
27
630d0a1b
C
28 private constructor () {}
29
30 init (app: Application) {
31 if (CONFIG.OPEN_TELEMETRY.METRICS.ENABLED !== true) return
32
33 app.use((req, res, next) => {
34 res.once('finish', () => {
35 if (!this.onRequestDuration) return
36
37 this.onRequestDuration(req as Request, res as Response)
38 })
39
40 next()
41 })
42 }
43
44 registerMetrics () {
45 if (CONFIG.OPEN_TELEMETRY.METRICS.ENABLED !== true) return
46
47 logger.info('Registering Open Telemetry metrics')
48
fd3c2e87
C
49 const provider = new MeterProvider({
50 views: [
51 ...NodeJSObserversBuilder.getViews()
52 ]
53 })
630d0a1b 54
31a9ed96
C
55 provider.addMetricReader(new PrometheusExporter({
56 host: CONFIG.OPEN_TELEMETRY.METRICS.PROMETHEUS_EXPORTER.HOSTNAME,
57 port: CONFIG.OPEN_TELEMETRY.METRICS.PROMETHEUS_EXPORTER.PORT
58 }))
630d0a1b
C
59
60 metrics.setGlobalMeterProvider(provider)
61
62 this.meter = metrics.getMeter('default')
63
630d0a1b 64 this.buildRequestObserver()
630d0a1b 65
fd3c2e87
C
66 this.playbackMetrics = new PlaybackMetrics(this.meter)
67 this.playbackMetrics.buildCounters()
68
69 const nodeJSObserversBuilder = new NodeJSObserversBuilder(this.meter)
cd1b8e9a 70 nodeJSObserversBuilder.buildObservers()
630d0a1b 71
cd1b8e9a
C
72 const jobQueueObserversBuilder = new JobQueueObserversBuilder(this.meter)
73 jobQueueObserversBuilder.buildObservers()
630d0a1b 74
cd1b8e9a
C
75 const statsObserversBuilder = new StatsObserversBuilder(this.meter)
76 statsObserversBuilder.buildObservers()
adc94cf0
C
77
78 const livesObserversBuilder = new LivesObserversBuilder(this.meter)
79 livesObserversBuilder.buildObservers()
80
81 const viewersObserversBuilder = new ViewersObserversBuilder(this.meter)
82 viewersObserversBuilder.buildObservers()
630d0a1b
C
83 }
84
fd3c2e87
C
85 observePlaybackMetric (video: MVideoImmutable, metrics: PlaybackMetricCreate) {
86 this.playbackMetrics.observe(video, metrics)
87 }
88
630d0a1b
C
89 private buildRequestObserver () {
90 const requestDuration = this.meter.createHistogram('http_request_duration_ms', {
91 unit: 'milliseconds',
92 description: 'Duration of HTTP requests in ms'
93 })
94
95 this.onRequestDuration = (req: Request, res: Response) => {
96 const duration = Date.now() - res.locals.requestStart
97
98 requestDuration.record(duration, {
99 path: this.buildRequestPath(req.originalUrl),
100 method: req.method,
101 statusCode: res.statusCode + ''
102 })
103 }
104 }
105
106 private buildRequestPath (path: string) {
107 return path.split('?')[0]
108 }
109
110 static get Instance () {
111 return this.instance || (this.instance = new this())
112 }
113}
114
115export {
116 OpenTelemetryMetrics
117}