diff --git a/client/src/assets/player/shared/metrics/metrics-plugin.ts b/client/src/assets/player/shared/metrics/metrics-plugin.ts index 6ca368f87..20d37d636 100644 --- a/client/src/assets/player/shared/metrics/metrics-plugin.ts +++ b/client/src/assets/player/shared/metrics/metrics-plugin.ts @@ -18,6 +18,9 @@ class MetricsPlugin extends Plugin { private resolutionChanges = 0 private errors = 0 + private p2pEnabled: boolean + private totalPeers = 0 + private lastPlayerNetworkInfo: PlayerNetworkInfo private metricsInterval: any @@ -113,6 +116,9 @@ class MetricsPlugin extends Plugin { uploadedBytesP2P: this.uploadedBytesP2P, + totalPeers: this.totalPeers, + p2pEnabled: this.p2pEnabled, + videoId: this.options_.videoUUID() } @@ -139,12 +145,18 @@ class MetricsPlugin extends Plugin { this.uploadedBytesP2P += Math.round(data.p2p.uploaded - (this.lastPlayerNetworkInfo?.p2p.uploaded || 0)) + this.totalPeers = data.p2p.numPeers + this.p2pEnabled = true + this.lastPlayerNetworkInfo = data }) this.player.on('http-info', (_event, data: PlayerNetworkInfo) => { this.downloadedBytesHTTP += Math.round(data.http.downloaded - (this.lastPlayerNetworkInfo?.http.downloaded || 0)) + this.totalPeers = 0 + this.p2pEnabled = false + this.lastPlayerNetworkInfo = data }) } diff --git a/server/lib/opentelemetry/metric-helpers/playback-metrics.ts b/server/lib/opentelemetry/metric-helpers/playback-metrics.ts index 406789618..41a5dd640 100644 --- a/server/lib/opentelemetry/metric-helpers/playback-metrics.ts +++ b/server/lib/opentelemetry/metric-helpers/playback-metrics.ts @@ -1,4 +1,4 @@ -import { Counter, Meter } from '@opentelemetry/api' +import { Counter, Histogram, Meter } from '@opentelemetry/api' import { MVideoImmutable } from '@server/types/models' import { PlaybackMetricCreate } from '@shared/models' @@ -11,6 +11,8 @@ export class PlaybackMetrics { private downloadedBytesHTTPCounter: Counter + private peersP2PPeers: Histogram + constructor (private readonly meter: Meter) { } @@ -34,6 +36,10 @@ export class PlaybackMetrics { this.uploadedBytesP2PCounter = this.meter.createCounter('peertube_playback_p2p_uploaded_bytes', { description: 'Uploaded bytes with P2P by PeerTube player.' }) + + this.peersP2PPeers = this.meter.createHistogram('peertube_playback_p2p_peers', { + description: 'Total P2P peers connected to the PeerTube player.' + }) } observe (video: MVideoImmutable, metrics: PlaybackMetricCreate) { @@ -47,6 +53,8 @@ export class PlaybackMetrics { resolution: metrics.resolution + '', fps: metrics.fps + '', + p2pEnabled: metrics.p2pEnabled, + videoUUID: video.uuid } @@ -57,5 +65,7 @@ export class PlaybackMetrics { this.downloadedBytesP2PCounter.add(metrics.downloadedBytesP2P, attributes) this.uploadedBytesP2PCounter.add(metrics.uploadedBytesP2P, attributes) + + if (metrics.totalPeers) this.peersP2PPeers.record(metrics.totalPeers, attributes) } } diff --git a/server/middlewares/validators/metrics.ts b/server/middlewares/validators/metrics.ts index 8ee5ac0d0..ced9afc69 100644 --- a/server/middlewares/validators/metrics.ts +++ b/server/middlewares/validators/metrics.ts @@ -12,6 +12,15 @@ const addPlaybackMetricValidator = [ body('fps') .optional() .isInt({ min: 0 }), + + body('totalPeers') + .optional() + .isInt({ min: 0 }), + + body('p2pEnabled') + .optional() + .isBoolean(), + body('playerMode') .custom(isValidPlayerMode), diff --git a/server/tests/api/check-params/metrics.ts b/server/tests/api/check-params/metrics.ts index be8253217..25443401d 100644 --- a/server/tests/api/check-params/metrics.ts +++ b/server/tests/api/check-params/metrics.ts @@ -89,10 +89,6 @@ describe('Test metrics API validators', function () { }) }) - it('Should fail with a missing errors', async function () { - - }) - it('Should fail with an missing/invalid errors', async function () { await makePostBodyRequest({ url: server.url, @@ -149,6 +145,22 @@ describe('Test metrics API validators', function () { }) }) + it('Should fail with an invalid p2pEnabled', async function () { + await makePostBodyRequest({ + url: server.url, + path, + fields: { ...baseParams, p2pEnabled: 'toto' } + }) + }) + + it('Should fail with an invalid totalPeers', async function () { + await makePostBodyRequest({ + url: server.url, + path, + fields: { ...baseParams, totalPeers: 'toto' } + }) + }) + it('Should fail with a bad video id', async function () { await makePostBodyRequest({ url: server.url, @@ -173,6 +185,13 @@ describe('Test metrics API validators', function () { fields: baseParams, expectedStatus: HttpStatusCode.NO_CONTENT_204 }) + + await makePostBodyRequest({ + url: server.url, + path, + fields: { ...baseParams, p2pEnabled: false, totalPeers: 32 }, + expectedStatus: HttpStatusCode.NO_CONTENT_204 + }) }) }) diff --git a/server/tests/api/server/open-telemetry.ts b/server/tests/api/server/open-telemetry.ts index fd85fc514..0bd0b5e86 100644 --- a/server/tests/api/server/open-telemetry.ts +++ b/server/tests/api/server/open-telemetry.ts @@ -62,6 +62,8 @@ describe('Open Telemetry', function () { downloadedBytesP2P: 0, downloadedBytesHTTP: 0, uploadedBytesP2P: 5, + totalPeers: 1, + p2pEnabled: false, videoId: video.uuid } }) diff --git a/shared/models/metrics/playback-metric-create.model.ts b/shared/models/metrics/playback-metric-create.model.ts index 3a8f328c8..b428beeb6 100644 --- a/shared/models/metrics/playback-metric-create.model.ts +++ b/shared/models/metrics/playback-metric-create.model.ts @@ -6,6 +6,9 @@ export interface PlaybackMetricCreate { resolution?: VideoResolution fps?: number + p2pEnabled?: boolean + totalPeers?: number + resolutionChanges: number errors: number