diff options
15 files changed, 141 insertions, 73 deletions
diff --git a/client/src/assets/player/peertube-player.ts b/client/src/assets/player/peertube-player.ts index ebb79247a..69ca1a566 100644 --- a/client/src/assets/player/peertube-player.ts +++ b/client/src/assets/player/peertube-player.ts | |||
@@ -203,7 +203,7 @@ export class PeerTubePlayer { | |||
203 | 203 | ||
204 | this.player.one('error', () => handleError()) | 204 | this.player.one('error', () => handleError()) |
205 | 205 | ||
206 | this.player.on('p2p-info', (_, data: PlayerNetworkInfo) => { | 206 | this.player.on('network-info', (_, data: PlayerNetworkInfo) => { |
207 | if (data.source !== 'p2p-media-loader' || isNaN(data.bandwidthEstimate)) return | 207 | if (data.source !== 'p2p-media-loader' || isNaN(data.bandwidthEstimate)) return |
208 | 208 | ||
209 | saveAverageBandwidth(data.bandwidthEstimate) | 209 | saveAverageBandwidth(data.bandwidthEstimate) |
diff --git a/client/src/assets/player/shared/control-bar/p2p-info-button.ts b/client/src/assets/player/shared/control-bar/p2p-info-button.ts index 4177b3280..d2d2b6c99 100644 --- a/client/src/assets/player/shared/control-bar/p2p-info-button.ts +++ b/client/src/assets/player/shared/control-bar/p2p-info-button.ts | |||
@@ -39,15 +39,14 @@ class P2PInfoButton extends Button { | |||
39 | subDivP2P.appendChild(peersText) | 39 | subDivP2P.appendChild(peersText) |
40 | 40 | ||
41 | const subDivHttp = videojs.dom.createEl('div', { className: 'vjs-peertube-hidden' }) as HTMLElement | 41 | const subDivHttp = videojs.dom.createEl('div', { className: 'vjs-peertube-hidden' }) as HTMLElement |
42 | const subDivHttpText = videojs.dom.createEl('span', { | 42 | const subDivHttpText = videojs.dom.createEl('span', { className: 'http-fallback' }) |
43 | className: 'http-fallback', | ||
44 | textContent: 'HTTP' | ||
45 | }) | ||
46 | 43 | ||
47 | subDivHttp.appendChild(subDivHttpText) | 44 | subDivHttp.appendChild(subDivHttpText) |
48 | div.appendChild(subDivHttp) | 45 | div.appendChild(subDivHttp) |
49 | 46 | ||
50 | this.player_.on('p2p-info', (_event: any, data: PlayerNetworkInfo) => { | 47 | this.player_.on('network-info', (_event: any, data: PlayerNetworkInfo) => { |
48 | if (!data.p2p) return | ||
49 | |||
51 | subDivP2P.className = 'vjs-peertube-displayed' | 50 | subDivP2P.className = 'vjs-peertube-displayed' |
52 | subDivHttp.className = 'vjs-peertube-hidden' | 51 | subDivHttp.className = 'vjs-peertube-hidden' |
53 | 52 | ||
@@ -58,7 +57,7 @@ class P2PInfoButton extends Button { | |||
58 | const uploadSpeed = bytes(p2pStats.uploadSpeed) | 57 | const uploadSpeed = bytes(p2pStats.uploadSpeed) |
59 | const totalDownloaded = bytes(p2pStats.downloaded + httpStats.downloaded) | 58 | const totalDownloaded = bytes(p2pStats.downloaded + httpStats.downloaded) |
60 | const totalUploaded = bytes(p2pStats.uploaded) | 59 | const totalUploaded = bytes(p2pStats.uploaded) |
61 | const numPeers = p2pStats.numPeers | 60 | const numPeers = p2pStats.peersWithWebSeed |
62 | 61 | ||
63 | subDivP2P.title = this.player().localize('Total downloaded: ') + totalDownloaded.join(' ') + '\n' | 62 | subDivP2P.title = this.player().localize('Total downloaded: ') + totalDownloaded.join(' ') + '\n' |
64 | 63 | ||
@@ -85,8 +84,13 @@ class P2PInfoButton extends Button { | |||
85 | subDivP2P.className = 'vjs-peertube-displayed' | 84 | subDivP2P.className = 'vjs-peertube-displayed' |
86 | }) | 85 | }) |
87 | 86 | ||
88 | this.player_.on('http-info', (_event, data: PlayerNetworkInfo) => { | 87 | this.player_.on('network-info', (_event, data: PlayerNetworkInfo) => { |
89 | // We are in HTTP fallback | 88 | if (data.p2p) return |
89 | |||
90 | if (data.source === 'web-video') subDivHttpText.textContent = 'HTTP' | ||
91 | else if (data.source === 'p2p-media-loader') subDivHttpText.textContent = 'HLS' | ||
92 | |||
93 | // We are in HTTP mode | ||
90 | subDivHttp.className = 'vjs-peertube-displayed' | 94 | subDivHttp.className = 'vjs-peertube-displayed' |
91 | subDivP2P.className = 'vjs-peertube-hidden' | 95 | subDivP2P.className = 'vjs-peertube-hidden' |
92 | 96 | ||
diff --git a/client/src/assets/player/shared/metrics/metrics-plugin.ts b/client/src/assets/player/shared/metrics/metrics-plugin.ts index 20d37d636..06ca0c2f2 100644 --- a/client/src/assets/player/shared/metrics/metrics-plugin.ts +++ b/client/src/assets/player/shared/metrics/metrics-plugin.ts | |||
@@ -19,7 +19,7 @@ class MetricsPlugin extends Plugin { | |||
19 | private errors = 0 | 19 | private errors = 0 |
20 | 20 | ||
21 | private p2pEnabled: boolean | 21 | private p2pEnabled: boolean |
22 | private totalPeers = 0 | 22 | private p2pPeers = 0 |
23 | 23 | ||
24 | private lastPlayerNetworkInfo: PlayerNetworkInfo | 24 | private lastPlayerNetworkInfo: PlayerNetworkInfo |
25 | 25 | ||
@@ -111,12 +111,12 @@ class MetricsPlugin extends Plugin { | |||
111 | 111 | ||
112 | errors: this.errors, | 112 | errors: this.errors, |
113 | 113 | ||
114 | downloadedBytesP2P: this.downloadedBytesP2P, | ||
115 | downloadedBytesHTTP: this.downloadedBytesHTTP, | 114 | downloadedBytesHTTP: this.downloadedBytesHTTP, |
116 | 115 | ||
116 | downloadedBytesP2P: this.downloadedBytesP2P, | ||
117 | uploadedBytesP2P: this.uploadedBytesP2P, | 117 | uploadedBytesP2P: this.uploadedBytesP2P, |
118 | 118 | ||
119 | totalPeers: this.totalPeers, | 119 | p2pPeers: this.p2pPeers, |
120 | p2pEnabled: this.p2pEnabled, | 120 | p2pEnabled: this.p2pEnabled, |
121 | 121 | ||
122 | videoId: this.options_.videoUUID() | 122 | videoId: this.options_.videoUUID() |
@@ -139,23 +139,14 @@ class MetricsPlugin extends Plugin { | |||
139 | } | 139 | } |
140 | 140 | ||
141 | private trackBytes () { | 141 | private trackBytes () { |
142 | this.player.on('p2p-info', (_event, data: PlayerNetworkInfo) => { | 142 | this.player.on('network-info', (_event, data: PlayerNetworkInfo) => { |
143 | this.downloadedBytesHTTP += Math.round(data.http.downloaded - (this.lastPlayerNetworkInfo?.http.downloaded || 0)) | 143 | this.downloadedBytesHTTP += Math.round(data.http.downloaded - (this.lastPlayerNetworkInfo?.http.downloaded || 0)) |
144 | this.downloadedBytesP2P += Math.round(data.p2p.downloaded - (this.lastPlayerNetworkInfo?.p2p.downloaded || 0)) | 144 | this.downloadedBytesP2P += Math.round((data.p2p?.downloaded || 0) - (this.lastPlayerNetworkInfo?.p2p?.downloaded || 0)) |
145 | |||
146 | this.uploadedBytesP2P += Math.round(data.p2p.uploaded - (this.lastPlayerNetworkInfo?.p2p.uploaded || 0)) | ||
147 | |||
148 | this.totalPeers = data.p2p.numPeers | ||
149 | this.p2pEnabled = true | ||
150 | 145 | ||
151 | this.lastPlayerNetworkInfo = data | 146 | this.uploadedBytesP2P += Math.round((data.p2p?.uploaded || 0) - (this.lastPlayerNetworkInfo?.p2p?.uploaded || 0)) |
152 | }) | ||
153 | |||
154 | this.player.on('http-info', (_event, data: PlayerNetworkInfo) => { | ||
155 | this.downloadedBytesHTTP += Math.round(data.http.downloaded - (this.lastPlayerNetworkInfo?.http.downloaded || 0)) | ||
156 | 147 | ||
157 | this.totalPeers = 0 | 148 | this.p2pPeers = data.p2p?.peersP2POnly |
158 | this.p2pEnabled = false | 149 | this.p2pEnabled = !!data.p2p |
159 | 150 | ||
160 | this.lastPlayerNetworkInfo = data | 151 | this.lastPlayerNetworkInfo = data |
161 | }) | 152 | }) |
diff --git a/client/src/assets/player/shared/p2p-media-loader/p2p-media-loader-plugin.ts b/client/src/assets/player/shared/p2p-media-loader/p2p-media-loader-plugin.ts index fe967a730..8c376cd21 100644 --- a/client/src/assets/player/shared/p2p-media-loader/p2p-media-loader-plugin.ts +++ b/client/src/assets/player/shared/p2p-media-loader/p2p-media-loader-plugin.ts | |||
@@ -16,7 +16,8 @@ class P2pMediaLoaderPlugin extends Plugin { | |||
16 | private statsP2PBytes = { | 16 | private statsP2PBytes = { |
17 | pendingDownload: [] as number[], | 17 | pendingDownload: [] as number[], |
18 | pendingUpload: [] as number[], | 18 | pendingUpload: [] as number[], |
19 | numPeers: 0, | 19 | peersWithWebSeed: 0, |
20 | peersP2POnly: 0, | ||
20 | totalDownload: 0, | 21 | totalDownload: 0, |
21 | totalUpload: 0 | 22 | totalUpload: 0 |
22 | } | 23 | } |
@@ -113,7 +114,7 @@ class P2pMediaLoaderPlugin extends Plugin { | |||
113 | this.options.redundancyUrlManager.removeBySegmentUrl(segment.requestUrl) | 114 | this.options.redundancyUrlManager.removeBySegmentUrl(segment.requestUrl) |
114 | }) | 115 | }) |
115 | 116 | ||
116 | this.statsP2PBytes.numPeers = 1 + this.options.redundancyUrlManager.countBaseUrls() | 117 | this.statsP2PBytes.peersWithWebSeed = 1 + this.options.redundancyUrlManager.countBaseUrls() |
117 | 118 | ||
118 | this.runStats() | 119 | this.runStats() |
119 | 120 | ||
@@ -138,8 +139,14 @@ class P2pMediaLoaderPlugin extends Plugin { | |||
138 | this.statsP2PBytes.totalUpload += bytes | 139 | this.statsP2PBytes.totalUpload += bytes |
139 | }) | 140 | }) |
140 | 141 | ||
141 | this.p2pEngine.on(Events.PeerConnect, () => this.statsP2PBytes.numPeers++) | 142 | this.p2pEngine.on(Events.PeerConnect, () => { |
142 | this.p2pEngine.on(Events.PeerClose, () => this.statsP2PBytes.numPeers--) | 143 | this.statsP2PBytes.peersWithWebSeed++ |
144 | this.statsP2PBytes.peersP2POnly++ | ||
145 | }) | ||
146 | this.p2pEngine.on(Events.PeerClose, () => { | ||
147 | this.statsP2PBytes.peersWithWebSeed-- | ||
148 | this.statsP2PBytes.peersP2POnly-- | ||
149 | }) | ||
143 | 150 | ||
144 | this.networkInfoInterval = setInterval(() => { | 151 | this.networkInfoInterval = setInterval(() => { |
145 | const p2pDownloadSpeed = this.arraySum(this.statsP2PBytes.pendingDownload) | 152 | const p2pDownloadSpeed = this.arraySum(this.statsP2PBytes.pendingDownload) |
@@ -151,20 +158,23 @@ class P2pMediaLoaderPlugin extends Plugin { | |||
151 | this.statsP2PBytes.pendingUpload = [] | 158 | this.statsP2PBytes.pendingUpload = [] |
152 | this.statsHTTPBytes.pendingDownload = [] | 159 | this.statsHTTPBytes.pendingDownload = [] |
153 | 160 | ||
154 | return this.player.trigger('p2p-info', { | 161 | return this.player.trigger('network-info', { |
155 | source: 'p2p-media-loader', | 162 | source: 'p2p-media-loader', |
163 | bandwidthEstimate: (this.hlsjs as any).bandwidthEstimate / 8, | ||
156 | http: { | 164 | http: { |
157 | downloadSpeed: httpDownloadSpeed, | 165 | downloadSpeed: httpDownloadSpeed, |
158 | downloaded: this.statsHTTPBytes.totalDownload | 166 | downloaded: this.statsHTTPBytes.totalDownload |
159 | }, | 167 | }, |
160 | p2p: { | 168 | p2p: this.options.p2pEnabled |
161 | downloadSpeed: p2pDownloadSpeed, | 169 | ? { |
162 | uploadSpeed: p2pUploadSpeed, | 170 | downloadSpeed: p2pDownloadSpeed, |
163 | numPeers: this.statsP2PBytes.numPeers, | 171 | uploadSpeed: p2pUploadSpeed, |
164 | downloaded: this.statsP2PBytes.totalDownload, | 172 | peersWithWebSeed: this.statsP2PBytes.peersWithWebSeed, |
165 | uploaded: this.statsP2PBytes.totalUpload | 173 | peersP2POnly: this.statsP2PBytes.peersP2POnly, |
166 | }, | 174 | downloaded: this.statsP2PBytes.totalDownload, |
167 | bandwidthEstimate: (this.hlsjs as any).bandwidthEstimate / 8 | 175 | uploaded: this.statsP2PBytes.totalUpload |
176 | } | ||
177 | : undefined | ||
168 | } as PlayerNetworkInfo) | 178 | } as PlayerNetworkInfo) |
169 | }, 1000) | 179 | }, 1000) |
170 | } | 180 | } |
diff --git a/client/src/assets/player/shared/player-options-builder/hls-options-builder.ts b/client/src/assets/player/shared/player-options-builder/hls-options-builder.ts index 1658f776c..fd632d90d 100644 --- a/client/src/assets/player/shared/player-options-builder/hls-options-builder.ts +++ b/client/src/assets/player/shared/player-options-builder/hls-options-builder.ts | |||
@@ -44,6 +44,8 @@ export class HLSOptionsBuilder { | |||
44 | requiresUserAuth: this.options.requiresUserAuth, | 44 | requiresUserAuth: this.options.requiresUserAuth, |
45 | videoFileToken: this.options.videoFileToken, | 45 | videoFileToken: this.options.videoFileToken, |
46 | 46 | ||
47 | p2pEnabled: this.options.p2pEnabled, | ||
48 | |||
47 | redundancyUrlManager, | 49 | redundancyUrlManager, |
48 | type: 'application/x-mpegURL', | 50 | type: 'application/x-mpegURL', |
49 | src: this.options.hls.playlistUrl, | 51 | src: this.options.hls.playlistUrl, |
diff --git a/client/src/assets/player/shared/stats/stats-card.ts b/client/src/assets/player/shared/stats/stats-card.ts index 077c900e5..13334d91a 100644 --- a/client/src/assets/player/shared/stats/stats-card.ts +++ b/client/src/assets/player/shared/stats/stats-card.ts | |||
@@ -63,8 +63,7 @@ class StatsCard extends Component { | |||
63 | 63 | ||
64 | private liveLatency: InfoElement | 64 | private liveLatency: InfoElement |
65 | 65 | ||
66 | private onP2PInfoHandler: (_event: any, data: EventPlayerNetworkInfo) => void | 66 | private onNetworkInfoHandler: (_event: any, data: EventPlayerNetworkInfo) => void |
67 | private onHTTPInfoHandler: (_event: any, data: EventPlayerNetworkInfo) => void | ||
68 | 67 | ||
69 | createEl () { | 68 | createEl () { |
70 | this.containerEl = videojs.dom.createEl('div', { | 69 | this.containerEl = videojs.dom.createEl('div', { |
@@ -89,33 +88,26 @@ class StatsCard extends Component { | |||
89 | 88 | ||
90 | this.populateInfoBlocks() | 89 | this.populateInfoBlocks() |
91 | 90 | ||
92 | this.onP2PInfoHandler = (_event, data) => { | 91 | this.onNetworkInfoHandler = (_event, data) => { |
93 | this.mode = data.source | 92 | this.mode = data.source |
94 | 93 | ||
95 | const p2pStats = data.p2p | 94 | const p2pStats = data.p2p |
96 | const httpStats = data.http | 95 | const httpStats = data.http |
97 | 96 | ||
98 | this.playerNetworkInfo.downloadSpeed = bytes(p2pStats.downloadSpeed + httpStats.downloadSpeed).join(' ') | 97 | this.playerNetworkInfo.downloadSpeed = bytes((p2pStats?.downloadSpeed || 0) + (httpStats.downloadSpeed || 0)).join(' ') |
99 | this.playerNetworkInfo.uploadSpeed = bytes(p2pStats.uploadSpeed).join(' ') | 98 | this.playerNetworkInfo.uploadSpeed = bytes(p2pStats?.uploadSpeed || 0).join(' ') |
100 | this.playerNetworkInfo.totalDownloaded = bytes(p2pStats.downloaded + httpStats.downloaded).join(' ') | 99 | this.playerNetworkInfo.totalDownloaded = bytes((p2pStats?.downloaded || 0) + httpStats.downloaded).join(' ') |
101 | this.playerNetworkInfo.totalUploaded = bytes(p2pStats.uploaded).join(' ') | 100 | this.playerNetworkInfo.totalUploaded = bytes(p2pStats?.uploaded || 0).join(' ') |
102 | this.playerNetworkInfo.numPeers = p2pStats.numPeers | 101 | this.playerNetworkInfo.numPeers = p2pStats?.peersWithWebSeed |
103 | this.playerNetworkInfo.averageBandwidth = bytes(data.bandwidthEstimate).join(' ') + '/s' | ||
104 | 102 | ||
105 | if (data.source === 'p2p-media-loader') { | 103 | if (data.source === 'p2p-media-loader') { |
104 | this.playerNetworkInfo.averageBandwidth = bytes(data.bandwidthEstimate).join(' ') + '/s' | ||
106 | this.playerNetworkInfo.downloadedFromServer = bytes(httpStats.downloaded).join(' ') | 105 | this.playerNetworkInfo.downloadedFromServer = bytes(httpStats.downloaded).join(' ') |
107 | this.playerNetworkInfo.downloadedFromPeers = bytes(p2pStats.downloaded).join(' ') | 106 | this.playerNetworkInfo.downloadedFromPeers = bytes(p2pStats?.downloaded || 0).join(' ') |
108 | } | 107 | } |
109 | } | 108 | } |
110 | 109 | ||
111 | this.onHTTPInfoHandler = (_event, data) => { | 110 | this.player().on('network-info', this.onNetworkInfoHandler) |
112 | this.mode = data.source | ||
113 | |||
114 | this.playerNetworkInfo.totalDownloaded = bytes(data.http.downloaded).join(' ') | ||
115 | } | ||
116 | |||
117 | this.player().on('p2p-info', this.onP2PInfoHandler) | ||
118 | this.player().on('http-info', this.onHTTPInfoHandler) | ||
119 | 111 | ||
120 | return this.containerEl | 112 | return this.containerEl |
121 | } | 113 | } |
@@ -123,8 +115,7 @@ class StatsCard extends Component { | |||
123 | dispose () { | 115 | dispose () { |
124 | if (this.updateInterval) clearInterval(this.updateInterval) | 116 | if (this.updateInterval) clearInterval(this.updateInterval) |
125 | 117 | ||
126 | this.player().off('p2p-info', this.onP2PInfoHandler) | 118 | this.player().off('network-info', this.onNetworkInfoHandler) |
127 | this.player().off('http-info', this.onHTTPInfoHandler) | ||
128 | 119 | ||
129 | super.dispose() | 120 | super.dispose() |
130 | } | 121 | } |
diff --git a/client/src/assets/player/shared/web-video/web-video-plugin.ts b/client/src/assets/player/shared/web-video/web-video-plugin.ts index 930b5045a..d09b5a724 100644 --- a/client/src/assets/player/shared/web-video/web-video-plugin.ts +++ b/client/src/assets/player/shared/web-video/web-video-plugin.ts | |||
@@ -175,7 +175,7 @@ class WebVideoPlugin extends Plugin { | |||
175 | 175 | ||
176 | private setupNetworkInfoInterval () { | 176 | private setupNetworkInfoInterval () { |
177 | this.networkInfoInterval = setInterval(() => { | 177 | this.networkInfoInterval = setInterval(() => { |
178 | return this.player.trigger('http-info', { | 178 | return this.player.trigger('network-info', { |
179 | source: 'web-video', | 179 | source: 'web-video', |
180 | http: { | 180 | http: { |
181 | downloaded: this.player.bufferedPercent() * this.currentVideoFile.size | 181 | downloaded: this.player.bufferedPercent() * this.currentVideoFile.size |
diff --git a/client/src/assets/player/types/peertube-videojs-typings.ts b/client/src/assets/player/types/peertube-videojs-typings.ts index adaa43d77..73b38d0d3 100644 --- a/client/src/assets/player/types/peertube-videojs-typings.ts +++ b/client/src/assets/player/types/peertube-videojs-typings.ts | |||
@@ -184,6 +184,8 @@ type P2PMediaLoaderPluginOptions = { | |||
184 | type: string | 184 | type: string |
185 | src: string | 185 | src: string |
186 | 186 | ||
187 | p2pEnabled: boolean | ||
188 | |||
187 | loader: P2PMediaLoader | 189 | loader: P2PMediaLoader |
188 | segmentValidator: SegmentValidator | 190 | segmentValidator: SegmentValidator |
189 | 191 | ||
@@ -240,9 +242,12 @@ type PlayerNetworkInfo = { | |||
240 | p2p?: { | 242 | p2p?: { |
241 | downloadSpeed: number | 243 | downloadSpeed: number |
242 | uploadSpeed: number | 244 | uploadSpeed: number |
245 | |||
243 | downloaded: number | 246 | downloaded: number |
244 | uploaded: number | 247 | uploaded: number |
245 | numPeers: number | 248 | |
249 | peersWithWebSeed: number | ||
250 | peersP2POnly: number | ||
246 | } | 251 | } |
247 | 252 | ||
248 | // In bytes | 253 | // In bytes |
diff --git a/config/dev.yaml b/config/dev.yaml index f570ede1e..60179533d 100644 --- a/config/dev.yaml +++ b/config/dev.yaml | |||
@@ -35,6 +35,10 @@ smtp: | |||
35 | log: | 35 | log: |
36 | level: 'debug' | 36 | level: 'debug' |
37 | 37 | ||
38 | open_telemetry: | ||
39 | metrics: | ||
40 | enabled: true | ||
41 | |||
38 | contact_form: | 42 | contact_form: |
39 | enabled: true | 43 | enabled: true |
40 | 44 | ||
diff --git a/server/lib/opentelemetry/metric-helpers/playback-metrics.ts b/server/lib/opentelemetry/metric-helpers/playback-metrics.ts index 41a5dd640..1eb08b5a6 100644 --- a/server/lib/opentelemetry/metric-helpers/playback-metrics.ts +++ b/server/lib/opentelemetry/metric-helpers/playback-metrics.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { Counter, Histogram, Meter } from '@opentelemetry/api' | 1 | import { Counter, Meter } from '@opentelemetry/api' |
2 | import { MVideoImmutable } from '@server/types/models' | 2 | import { MVideoImmutable } from '@server/types/models' |
3 | import { PlaybackMetricCreate } from '@shared/models' | 3 | import { PlaybackMetricCreate } from '@shared/models' |
4 | 4 | ||
@@ -11,7 +11,10 @@ export class PlaybackMetrics { | |||
11 | 11 | ||
12 | private downloadedBytesHTTPCounter: Counter | 12 | private downloadedBytesHTTPCounter: Counter |
13 | 13 | ||
14 | private peersP2PPeers: Histogram | 14 | private peersP2PPeersGaugeBuffer: { |
15 | value: number | ||
16 | attributes: any | ||
17 | }[] = [] | ||
15 | 18 | ||
16 | constructor (private readonly meter: Meter) { | 19 | constructor (private readonly meter: Meter) { |
17 | 20 | ||
@@ -37,8 +40,14 @@ export class PlaybackMetrics { | |||
37 | description: 'Uploaded bytes with P2P by PeerTube player.' | 40 | description: 'Uploaded bytes with P2P by PeerTube player.' |
38 | }) | 41 | }) |
39 | 42 | ||
40 | this.peersP2PPeers = this.meter.createHistogram('peertube_playback_p2p_peers', { | 43 | this.meter.createObservableGauge('peertube_playback_p2p_peers', { |
41 | description: 'Total P2P peers connected to the PeerTube player.' | 44 | description: 'Total P2P peers connected to the PeerTube player.' |
45 | }).addCallback(observableResult => { | ||
46 | for (const gauge of this.peersP2PPeersGaugeBuffer) { | ||
47 | observableResult.observe(gauge.value, gauge.attributes) | ||
48 | } | ||
49 | |||
50 | this.peersP2PPeersGaugeBuffer = [] | ||
42 | }) | 51 | }) |
43 | } | 52 | } |
44 | 53 | ||
@@ -66,6 +75,11 @@ export class PlaybackMetrics { | |||
66 | 75 | ||
67 | this.uploadedBytesP2PCounter.add(metrics.uploadedBytesP2P, attributes) | 76 | this.uploadedBytesP2PCounter.add(metrics.uploadedBytesP2P, attributes) |
68 | 77 | ||
69 | if (metrics.totalPeers) this.peersP2PPeers.record(metrics.totalPeers, attributes) | 78 | if (metrics.p2pPeers) { |
79 | this.peersP2PPeersGaugeBuffer.push({ | ||
80 | value: metrics.p2pPeers, | ||
81 | attributes | ||
82 | }) | ||
83 | } | ||
70 | } | 84 | } |
71 | } | 85 | } |
diff --git a/server/middlewares/validators/metrics.ts b/server/middlewares/validators/metrics.ts index ced9afc69..986b30a19 100644 --- a/server/middlewares/validators/metrics.ts +++ b/server/middlewares/validators/metrics.ts | |||
@@ -13,12 +13,11 @@ const addPlaybackMetricValidator = [ | |||
13 | .optional() | 13 | .optional() |
14 | .isInt({ min: 0 }), | 14 | .isInt({ min: 0 }), |
15 | 15 | ||
16 | body('totalPeers') | 16 | body('p2pPeers') |
17 | .optional() | 17 | .optional() |
18 | .isInt({ min: 0 }), | 18 | .isInt({ min: 0 }), |
19 | 19 | ||
20 | body('p2pEnabled') | 20 | body('p2pEnabled') |
21 | .optional() | ||
22 | .isBoolean(), | 21 | .isBoolean(), |
23 | 22 | ||
24 | body('playerMode') | 23 | body('playerMode') |
diff --git a/server/tests/api/check-params/metrics.ts b/server/tests/api/check-params/metrics.ts index 25443401d..302bef4f5 100644 --- a/server/tests/api/check-params/metrics.ts +++ b/server/tests/api/check-params/metrics.ts | |||
@@ -38,6 +38,7 @@ describe('Test metrics API validators', function () { | |||
38 | fps: 30, | 38 | fps: 30, |
39 | resolutionChanges: 1, | 39 | resolutionChanges: 1, |
40 | errors: 2, | 40 | errors: 2, |
41 | p2pEnabled: true, | ||
41 | downloadedBytesP2P: 0, | 42 | downloadedBytesP2P: 0, |
42 | downloadedBytesHTTP: 0, | 43 | downloadedBytesHTTP: 0, |
43 | uploadedBytesP2P: 0, | 44 | uploadedBytesP2P: 0, |
@@ -145,7 +146,13 @@ describe('Test metrics API validators', function () { | |||
145 | }) | 146 | }) |
146 | }) | 147 | }) |
147 | 148 | ||
148 | it('Should fail with an invalid p2pEnabled', async function () { | 149 | it('Should fail with a missing/invalid p2pEnabled', async function () { |
150 | await makePostBodyRequest({ | ||
151 | url: server.url, | ||
152 | path, | ||
153 | fields: omit(baseParams, [ 'p2pEnabled' ]) | ||
154 | }) | ||
155 | |||
149 | await makePostBodyRequest({ | 156 | await makePostBodyRequest({ |
150 | url: server.url, | 157 | url: server.url, |
151 | path, | 158 | path, |
@@ -157,7 +164,7 @@ describe('Test metrics API validators', function () { | |||
157 | await makePostBodyRequest({ | 164 | await makePostBodyRequest({ |
158 | url: server.url, | 165 | url: server.url, |
159 | path, | 166 | path, |
160 | fields: { ...baseParams, totalPeers: 'toto' } | 167 | fields: { ...baseParams, p2pPeers: 'toto' } |
161 | }) | 168 | }) |
162 | }) | 169 | }) |
163 | 170 | ||
diff --git a/server/tests/api/server/open-telemetry.ts b/server/tests/api/server/open-telemetry.ts index 0bd0b5e86..508e9d649 100644 --- a/server/tests/api/server/open-telemetry.ts +++ b/server/tests/api/server/open-telemetry.ts | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | import { expect } from 'chai' | 3 | import { expect } from 'chai' |
4 | import { expectLogContain, expectLogDoesNotContain, MockHTTP } from '@server/tests/shared' | 4 | import { expectLogContain, expectLogDoesNotContain, MockHTTP } from '@server/tests/shared' |
5 | import { HttpStatusCode, VideoPrivacy, VideoResolution } from '@shared/models' | 5 | import { HttpStatusCode, PlaybackMetricCreate, VideoPrivacy, VideoResolution } from '@shared/models' |
6 | import { cleanupTests, createSingleServer, makeRawRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' | 6 | import { cleanupTests, createSingleServer, makeRawRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' |
7 | 7 | ||
8 | describe('Open Telemetry', function () { | 8 | describe('Open Telemetry', function () { |
@@ -62,14 +62,49 @@ describe('Open Telemetry', function () { | |||
62 | downloadedBytesP2P: 0, | 62 | downloadedBytesP2P: 0, |
63 | downloadedBytesHTTP: 0, | 63 | downloadedBytesHTTP: 0, |
64 | uploadedBytesP2P: 5, | 64 | uploadedBytesP2P: 5, |
65 | totalPeers: 1, | 65 | p2pPeers: 1, |
66 | p2pEnabled: false, | 66 | p2pEnabled: false, |
67 | videoId: video.uuid | 67 | videoId: video.uuid |
68 | } | 68 | } |
69 | }) | 69 | }) |
70 | 70 | ||
71 | const res = await makeRawRequest({ url: metricsUrl, expectedStatus: HttpStatusCode.OK_200 }) | 71 | const res = await makeRawRequest({ url: metricsUrl, expectedStatus: HttpStatusCode.OK_200 }) |
72 | |||
72 | expect(res.text).to.contain('peertube_playback_http_downloaded_bytes_total{') | 73 | expect(res.text).to.contain('peertube_playback_http_downloaded_bytes_total{') |
74 | expect(res.text).to.contain('peertube_playback_p2p_peers{') | ||
75 | expect(res.text).to.contain('p2pEnabled="false"') | ||
76 | }) | ||
77 | |||
78 | it('Should take the last playback metric', async function () { | ||
79 | await setAccessTokensToServers([ server ]) | ||
80 | |||
81 | const video = await server.videos.quickUpload({ name: 'video' }) | ||
82 | |||
83 | const metrics = { | ||
84 | playerMode: 'p2p-media-loader', | ||
85 | resolution: VideoResolution.H_1080P, | ||
86 | fps: 30, | ||
87 | resolutionChanges: 1, | ||
88 | errors: 2, | ||
89 | downloadedBytesP2P: 0, | ||
90 | downloadedBytesHTTP: 0, | ||
91 | uploadedBytesP2P: 5, | ||
92 | p2pPeers: 7, | ||
93 | p2pEnabled: false, | ||
94 | videoId: video.uuid | ||
95 | } as PlaybackMetricCreate | ||
96 | |||
97 | await server.metrics.addPlaybackMetric({ metrics }) | ||
98 | |||
99 | metrics.p2pPeers = 42 | ||
100 | await server.metrics.addPlaybackMetric({ metrics }) | ||
101 | |||
102 | const res = await makeRawRequest({ url: metricsUrl, expectedStatus: HttpStatusCode.OK_200 }) | ||
103 | |||
104 | // eslint-disable-next-line max-len | ||
105 | const label = `{videoOrigin="local",playerMode="p2p-media-loader",resolution="1080",fps="30",p2pEnabled="false",videoUUID="${video.uuid}"}` | ||
106 | expect(res.text).to.contain(`peertube_playback_p2p_peers${label} 42`) | ||
107 | expect(res.text).to.not.contain(`peertube_playback_p2p_peers${label} 7`) | ||
73 | }) | 108 | }) |
74 | 109 | ||
75 | it('Should disable http request duration metrics', async function () { | 110 | it('Should disable http request duration metrics', async function () { |
diff --git a/shared/models/metrics/playback-metric-create.model.ts b/shared/models/metrics/playback-metric-create.model.ts index b428beeb6..1d47421c3 100644 --- a/shared/models/metrics/playback-metric-create.model.ts +++ b/shared/models/metrics/playback-metric-create.model.ts | |||
@@ -6,8 +6,8 @@ export interface PlaybackMetricCreate { | |||
6 | resolution?: VideoResolution | 6 | resolution?: VideoResolution |
7 | fps?: number | 7 | fps?: number |
8 | 8 | ||
9 | p2pEnabled?: boolean | 9 | p2pEnabled: boolean |
10 | totalPeers?: number | 10 | p2pPeers?: number |
11 | 11 | ||
12 | resolutionChanges: number | 12 | resolutionChanges: number |
13 | 13 | ||
diff --git a/support/doc/api/openapi.yaml b/support/doc/api/openapi.yaml index 2dfad9987..90aaebd26 100644 --- a/support/doc/api/openapi.yaml +++ b/support/doc/api/openapi.yaml | |||
@@ -9528,6 +9528,11 @@ components: | |||
9528 | fps: | 9528 | fps: |
9529 | type: number | 9529 | type: number |
9530 | description: Current player video fps | 9530 | description: Current player video fps |
9531 | p2pEnabled: | ||
9532 | type: boolean | ||
9533 | p2pPeers: | ||
9534 | type: number | ||
9535 | description: P2P peers connected (doesn't include WebSeed peers) | ||
9531 | resolutionChanges: | 9536 | resolutionChanges: |
9532 | type: number | 9537 | type: number |
9533 | description: How many resolution changes occured since the last metric creation | 9538 | description: How many resolution changes occured since the last metric creation |
@@ -9555,6 +9560,7 @@ components: | |||
9555 | - downloadedBytesP2P | 9560 | - downloadedBytesP2P |
9556 | - downloadedBytesHTTP | 9561 | - downloadedBytesHTTP |
9557 | - uploadedBytesP2P | 9562 | - uploadedBytesP2P |
9563 | - p2pEnabled | ||
9558 | - videoId | 9564 | - videoId |
9559 | 9565 | ||
9560 | RunnerRegistrationToken: | 9566 | RunnerRegistrationToken: |