diff options
author | Chocobozzz <me@florianbigard.com> | 2022-08-12 16:41:29 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2022-08-16 10:33:27 +0200 |
commit | fd3c2e87051f5029cdec39d877b576a62f48e219 (patch) | |
tree | a3c657f178702a3363af680ed8ffb7cd038243b8 /server | |
parent | 0e6cd1c00f71554fe7375a96db693a6983951ba6 (diff) | |
download | PeerTube-fd3c2e87051f5029cdec39d877b576a62f48e219.tar.gz PeerTube-fd3c2e87051f5029cdec39d877b576a62f48e219.tar.zst PeerTube-fd3c2e87051f5029cdec39d877b576a62f48e219.zip |
Add playback metric endpoint sent to OTEL
Diffstat (limited to 'server')
-rw-r--r-- | server/controllers/api/index.ts | 4 | ||||
-rw-r--r-- | server/controllers/api/metrics.ts | 27 | ||||
-rw-r--r-- | server/helpers/custom-validators/metrics.ts | 9 | ||||
-rw-r--r-- | server/lib/opentelemetry/metric-helpers/index.ts | 1 | ||||
-rw-r--r-- | server/lib/opentelemetry/metric-helpers/nodejs-observers-builder.ts | 18 | ||||
-rw-r--r-- | server/lib/opentelemetry/metric-helpers/playback-metrics.ts | 59 | ||||
-rw-r--r-- | server/lib/opentelemetry/metrics.ts | 20 | ||||
-rw-r--r-- | server/middlewares/validators/index.ts | 1 | ||||
-rw-r--r-- | server/middlewares/validators/metrics.ts | 56 | ||||
-rw-r--r-- | server/tests/api/check-params/index.ts | 1 | ||||
-rw-r--r-- | server/tests/api/check-params/metrics.ts | 183 | ||||
-rw-r--r-- | server/tests/api/server/open-telemetry.ts | 31 |
12 files changed, 397 insertions, 13 deletions
diff --git a/server/controllers/api/index.ts b/server/controllers/api/index.ts index 8c8ebd061..e1d197c8a 100644 --- a/server/controllers/api/index.ts +++ b/server/controllers/api/index.ts | |||
@@ -11,6 +11,7 @@ import { bulkRouter } from './bulk' | |||
11 | import { configRouter } from './config' | 11 | import { configRouter } from './config' |
12 | import { customPageRouter } from './custom-page' | 12 | import { customPageRouter } from './custom-page' |
13 | import { jobsRouter } from './jobs' | 13 | import { jobsRouter } from './jobs' |
14 | import { metricsRouter } from './metrics' | ||
14 | import { oauthClientsRouter } from './oauth-clients' | 15 | import { oauthClientsRouter } from './oauth-clients' |
15 | import { overviewsRouter } from './overviews' | 16 | import { overviewsRouter } from './overviews' |
16 | import { pluginRouter } from './plugins' | 17 | import { pluginRouter } from './plugins' |
@@ -18,9 +19,9 @@ import { searchRouter } from './search' | |||
18 | import { serverRouter } from './server' | 19 | import { serverRouter } from './server' |
19 | import { usersRouter } from './users' | 20 | import { usersRouter } from './users' |
20 | import { videoChannelRouter } from './video-channel' | 21 | import { videoChannelRouter } from './video-channel' |
22 | import { videoChannelSyncRouter } from './video-channel-sync' | ||
21 | import { videoPlaylistRouter } from './video-playlist' | 23 | import { videoPlaylistRouter } from './video-playlist' |
22 | import { videosRouter } from './videos' | 24 | import { videosRouter } from './videos' |
23 | import { videoChannelSyncRouter } from './video-channel-sync' | ||
24 | 25 | ||
25 | const apiRouter = express.Router() | 26 | const apiRouter = express.Router() |
26 | 27 | ||
@@ -48,6 +49,7 @@ apiRouter.use('/video-channel-syncs', videoChannelSyncRouter) | |||
48 | apiRouter.use('/video-playlists', videoPlaylistRouter) | 49 | apiRouter.use('/video-playlists', videoPlaylistRouter) |
49 | apiRouter.use('/videos', videosRouter) | 50 | apiRouter.use('/videos', videosRouter) |
50 | apiRouter.use('/jobs', jobsRouter) | 51 | apiRouter.use('/jobs', jobsRouter) |
52 | apiRouter.use('/metrics', metricsRouter) | ||
51 | apiRouter.use('/search', searchRouter) | 53 | apiRouter.use('/search', searchRouter) |
52 | apiRouter.use('/overviews', overviewsRouter) | 54 | apiRouter.use('/overviews', overviewsRouter) |
53 | apiRouter.use('/plugins', pluginRouter) | 55 | apiRouter.use('/plugins', pluginRouter) |
diff --git a/server/controllers/api/metrics.ts b/server/controllers/api/metrics.ts new file mode 100644 index 000000000..578b023a1 --- /dev/null +++ b/server/controllers/api/metrics.ts | |||
@@ -0,0 +1,27 @@ | |||
1 | import express from 'express' | ||
2 | import { OpenTelemetryMetrics } from '@server/lib/opentelemetry/metrics' | ||
3 | import { HttpStatusCode, PlaybackMetricCreate } from '@shared/models' | ||
4 | import { addPlaybackMetricValidator, asyncMiddleware } from '../../middlewares' | ||
5 | |||
6 | const metricsRouter = express.Router() | ||
7 | |||
8 | metricsRouter.post('/playback', | ||
9 | asyncMiddleware(addPlaybackMetricValidator), | ||
10 | addPlaybackMetric | ||
11 | ) | ||
12 | |||
13 | // --------------------------------------------------------------------------- | ||
14 | |||
15 | export { | ||
16 | metricsRouter | ||
17 | } | ||
18 | |||
19 | // --------------------------------------------------------------------------- | ||
20 | |||
21 | function addPlaybackMetric (req: express.Request, res: express.Response) { | ||
22 | const body: PlaybackMetricCreate = req.body | ||
23 | |||
24 | OpenTelemetryMetrics.Instance.observePlaybackMetric(res.locals.onlyImmutableVideo, body) | ||
25 | |||
26 | return res.sendStatus(HttpStatusCode.NO_CONTENT_204) | ||
27 | } | ||
diff --git a/server/helpers/custom-validators/metrics.ts b/server/helpers/custom-validators/metrics.ts new file mode 100644 index 000000000..533f8988d --- /dev/null +++ b/server/helpers/custom-validators/metrics.ts | |||
@@ -0,0 +1,9 @@ | |||
1 | function isValidPlayerMode (value: any) { | ||
2 | return value === 'webtorrent' || value === 'p2p-media-loader' | ||
3 | } | ||
4 | |||
5 | // --------------------------------------------------------------------------- | ||
6 | |||
7 | export { | ||
8 | isValidPlayerMode | ||
9 | } | ||
diff --git a/server/lib/opentelemetry/metric-helpers/index.ts b/server/lib/opentelemetry/metric-helpers/index.ts index 1b3813743..775d954ba 100644 --- a/server/lib/opentelemetry/metric-helpers/index.ts +++ b/server/lib/opentelemetry/metric-helpers/index.ts | |||
@@ -1,5 +1,6 @@ | |||
1 | export * from './lives-observers-builder' | 1 | export * from './lives-observers-builder' |
2 | export * from './job-queue-observers-builder' | 2 | export * from './job-queue-observers-builder' |
3 | export * from './nodejs-observers-builder' | 3 | export * from './nodejs-observers-builder' |
4 | export * from './playback-metrics' | ||
4 | export * from './stats-observers-builder' | 5 | export * from './stats-observers-builder' |
5 | export * from './viewers-observers-builder' | 6 | export * from './viewers-observers-builder' |
diff --git a/server/lib/opentelemetry/metric-helpers/nodejs-observers-builder.ts b/server/lib/opentelemetry/metric-helpers/nodejs-observers-builder.ts index 766cbe03b..473015e91 100644 --- a/server/lib/opentelemetry/metric-helpers/nodejs-observers-builder.ts +++ b/server/lib/opentelemetry/metric-helpers/nodejs-observers-builder.ts | |||
@@ -2,7 +2,7 @@ import { readdir } from 'fs-extra' | |||
2 | import { constants, PerformanceObserver } from 'perf_hooks' | 2 | import { constants, PerformanceObserver } from 'perf_hooks' |
3 | import * as process from 'process' | 3 | import * as process from 'process' |
4 | import { Meter, ObservableResult } from '@opentelemetry/api-metrics' | 4 | import { Meter, ObservableResult } from '@opentelemetry/api-metrics' |
5 | import { ExplicitBucketHistogramAggregation, MeterProvider } from '@opentelemetry/sdk-metrics-base' | 5 | import { ExplicitBucketHistogramAggregation } from '@opentelemetry/sdk-metrics-base' |
6 | import { View } from '@opentelemetry/sdk-metrics-base/build/src/view/View' | 6 | import { View } from '@opentelemetry/sdk-metrics-base/build/src/view/View' |
7 | import { logger } from '@server/helpers/logger' | 7 | import { logger } from '@server/helpers/logger' |
8 | 8 | ||
@@ -12,7 +12,16 @@ import { logger } from '@server/helpers/logger' | |||
12 | 12 | ||
13 | export class NodeJSObserversBuilder { | 13 | export class NodeJSObserversBuilder { |
14 | 14 | ||
15 | constructor (private readonly meter: Meter, private readonly meterProvider: MeterProvider) { | 15 | constructor (private readonly meter: Meter) { |
16 | } | ||
17 | |||
18 | static getViews () { | ||
19 | return [ | ||
20 | new View({ | ||
21 | aggregation: new ExplicitBucketHistogramAggregation([ 0.001, 0.01, 0.1, 1, 2, 5 ]), | ||
22 | instrumentName: 'nodejs_gc_duration_seconds' | ||
23 | }) | ||
24 | ] | ||
16 | } | 25 | } |
17 | 26 | ||
18 | buildObservers () { | 27 | buildObservers () { |
@@ -91,11 +100,6 @@ export class NodeJSObserversBuilder { | |||
91 | [constants.NODE_PERFORMANCE_GC_WEAKCB]: 'weakcb' | 100 | [constants.NODE_PERFORMANCE_GC_WEAKCB]: 'weakcb' |
92 | } | 101 | } |
93 | 102 | ||
94 | this.meterProvider.addView( | ||
95 | new View({ aggregation: new ExplicitBucketHistogramAggregation([ 0.001, 0.01, 0.1, 1, 2, 5 ]) }), | ||
96 | { instrument: { name: 'nodejs_gc_duration_seconds' } } | ||
97 | ) | ||
98 | |||
99 | const histogram = this.meter.createHistogram('nodejs_gc_duration_seconds', { | 103 | const histogram = this.meter.createHistogram('nodejs_gc_duration_seconds', { |
100 | description: 'Garbage collection duration by kind, one of major, minor, incremental or weakcb' | 104 | description: 'Garbage collection duration by kind, one of major, minor, incremental or weakcb' |
101 | }) | 105 | }) |
diff --git a/server/lib/opentelemetry/metric-helpers/playback-metrics.ts b/server/lib/opentelemetry/metric-helpers/playback-metrics.ts new file mode 100644 index 000000000..d2abdee62 --- /dev/null +++ b/server/lib/opentelemetry/metric-helpers/playback-metrics.ts | |||
@@ -0,0 +1,59 @@ | |||
1 | import { Counter, Meter } from '@opentelemetry/api-metrics' | ||
2 | import { MVideoImmutable } from '@server/types/models' | ||
3 | import { PlaybackMetricCreate } from '@shared/models' | ||
4 | |||
5 | export class PlaybackMetrics { | ||
6 | private errorsCounter: Counter | ||
7 | private resolutionChangesCounter: Counter | ||
8 | |||
9 | private downloadedBytesP2PCounter: Counter | ||
10 | private uploadedBytesP2PCounter: Counter | ||
11 | |||
12 | private downloadedBytesHTTPCounter: Counter | ||
13 | |||
14 | constructor (private readonly meter: Meter) { | ||
15 | |||
16 | } | ||
17 | |||
18 | buildCounters () { | ||
19 | this.errorsCounter = this.meter.createCounter('peertube_playback_errors_count', { | ||
20 | description: 'Errors collected from PeerTube player.' | ||
21 | }) | ||
22 | |||
23 | this.resolutionChangesCounter = this.meter.createCounter('peertube_playback_resolution_changes_count', { | ||
24 | description: 'Resolution changes collected from PeerTube player.' | ||
25 | }) | ||
26 | |||
27 | this.downloadedBytesHTTPCounter = this.meter.createCounter('peertube_playback_http_downloaded_bytes', { | ||
28 | description: 'Downloaded bytes with HTTP by PeerTube player.' | ||
29 | }) | ||
30 | this.downloadedBytesP2PCounter = this.meter.createCounter('peertube_playback_p2p_downloaded_bytes', { | ||
31 | description: 'Downloaded bytes with P2P by PeerTube player.' | ||
32 | }) | ||
33 | |||
34 | this.uploadedBytesP2PCounter = this.meter.createCounter('peertube_playback_p2p_uploaded_bytes', { | ||
35 | description: 'Uploaded bytes with P2P by PeerTube player.' | ||
36 | }) | ||
37 | } | ||
38 | |||
39 | observe (video: MVideoImmutable, metrics: PlaybackMetricCreate) { | ||
40 | const attributes = { | ||
41 | videoOrigin: video.remote | ||
42 | ? 'remote' | ||
43 | : 'local', | ||
44 | |||
45 | playerMode: metrics.playerMode, | ||
46 | |||
47 | resolution: metrics.resolution + '', | ||
48 | fps: metrics.fps + '' | ||
49 | } | ||
50 | |||
51 | this.errorsCounter.add(metrics.errors, attributes) | ||
52 | this.resolutionChangesCounter.add(metrics.resolutionChanges, attributes) | ||
53 | |||
54 | this.downloadedBytesHTTPCounter.add(metrics.downloadedBytesHTTP, attributes) | ||
55 | this.downloadedBytesP2PCounter.add(metrics.downloadedBytesP2P, attributes) | ||
56 | |||
57 | this.uploadedBytesP2PCounter.add(metrics.uploadedBytesP2P, attributes) | ||
58 | } | ||
59 | } | ||
diff --git a/server/lib/opentelemetry/metrics.ts b/server/lib/opentelemetry/metrics.ts index ffe493670..ba33c9505 100644 --- a/server/lib/opentelemetry/metrics.ts +++ b/server/lib/opentelemetry/metrics.ts | |||
@@ -4,10 +4,13 @@ import { PrometheusExporter } from '@opentelemetry/exporter-prometheus' | |||
4 | import { MeterProvider } from '@opentelemetry/sdk-metrics-base' | 4 | import { MeterProvider } from '@opentelemetry/sdk-metrics-base' |
5 | import { logger } from '@server/helpers/logger' | 5 | import { logger } from '@server/helpers/logger' |
6 | import { CONFIG } from '@server/initializers/config' | 6 | import { CONFIG } from '@server/initializers/config' |
7 | import { MVideoImmutable } from '@server/types/models' | ||
8 | import { PlaybackMetricCreate } from '@shared/models' | ||
7 | import { | 9 | import { |
8 | JobQueueObserversBuilder, | 10 | JobQueueObserversBuilder, |
9 | LivesObserversBuilder, | 11 | LivesObserversBuilder, |
10 | NodeJSObserversBuilder, | 12 | NodeJSObserversBuilder, |
13 | PlaybackMetrics, | ||
11 | StatsObserversBuilder, | 14 | StatsObserversBuilder, |
12 | ViewersObserversBuilder | 15 | ViewersObserversBuilder |
13 | } from './metric-helpers' | 16 | } from './metric-helpers' |
@@ -20,6 +23,8 @@ class OpenTelemetryMetrics { | |||
20 | 23 | ||
21 | private onRequestDuration: (req: Request, res: Response) => void | 24 | private onRequestDuration: (req: Request, res: Response) => void |
22 | 25 | ||
26 | private playbackMetrics: PlaybackMetrics | ||
27 | |||
23 | private constructor () {} | 28 | private constructor () {} |
24 | 29 | ||
25 | init (app: Application) { | 30 | init (app: Application) { |
@@ -41,7 +46,11 @@ class OpenTelemetryMetrics { | |||
41 | 46 | ||
42 | logger.info('Registering Open Telemetry metrics') | 47 | logger.info('Registering Open Telemetry metrics') |
43 | 48 | ||
44 | const provider = new MeterProvider() | 49 | const provider = new MeterProvider({ |
50 | views: [ | ||
51 | ...NodeJSObserversBuilder.getViews() | ||
52 | ] | ||
53 | }) | ||
45 | 54 | ||
46 | provider.addMetricReader(new PrometheusExporter({ port: CONFIG.OPEN_TELEMETRY.METRICS.PROMETHEUS_EXPORTER.PORT })) | 55 | provider.addMetricReader(new PrometheusExporter({ port: CONFIG.OPEN_TELEMETRY.METRICS.PROMETHEUS_EXPORTER.PORT })) |
47 | 56 | ||
@@ -51,7 +60,10 @@ class OpenTelemetryMetrics { | |||
51 | 60 | ||
52 | this.buildRequestObserver() | 61 | this.buildRequestObserver() |
53 | 62 | ||
54 | const nodeJSObserversBuilder = new NodeJSObserversBuilder(this.meter, provider) | 63 | this.playbackMetrics = new PlaybackMetrics(this.meter) |
64 | this.playbackMetrics.buildCounters() | ||
65 | |||
66 | const nodeJSObserversBuilder = new NodeJSObserversBuilder(this.meter) | ||
55 | nodeJSObserversBuilder.buildObservers() | 67 | nodeJSObserversBuilder.buildObservers() |
56 | 68 | ||
57 | const jobQueueObserversBuilder = new JobQueueObserversBuilder(this.meter) | 69 | const jobQueueObserversBuilder = new JobQueueObserversBuilder(this.meter) |
@@ -67,6 +79,10 @@ class OpenTelemetryMetrics { | |||
67 | viewersObserversBuilder.buildObservers() | 79 | viewersObserversBuilder.buildObservers() |
68 | } | 80 | } |
69 | 81 | ||
82 | observePlaybackMetric (video: MVideoImmutable, metrics: PlaybackMetricCreate) { | ||
83 | this.playbackMetrics.observe(video, metrics) | ||
84 | } | ||
85 | |||
70 | private buildRequestObserver () { | 86 | private buildRequestObserver () { |
71 | const requestDuration = this.meter.createHistogram('http_request_duration_ms', { | 87 | const requestDuration = this.meter.createHistogram('http_request_duration_ms', { |
72 | unit: 'milliseconds', | 88 | unit: 'milliseconds', |
diff --git a/server/middlewares/validators/index.ts b/server/middlewares/validators/index.ts index b0ad04819..ffadb3b49 100644 --- a/server/middlewares/validators/index.ts +++ b/server/middlewares/validators/index.ts | |||
@@ -10,6 +10,7 @@ export * from './express' | |||
10 | export * from './feeds' | 10 | export * from './feeds' |
11 | export * from './follows' | 11 | export * from './follows' |
12 | export * from './jobs' | 12 | export * from './jobs' |
13 | export * from './metrics' | ||
13 | export * from './logs' | 14 | export * from './logs' |
14 | export * from './oembed' | 15 | export * from './oembed' |
15 | export * from './pagination' | 16 | export * from './pagination' |
diff --git a/server/middlewares/validators/metrics.ts b/server/middlewares/validators/metrics.ts new file mode 100644 index 000000000..b1dbec603 --- /dev/null +++ b/server/middlewares/validators/metrics.ts | |||
@@ -0,0 +1,56 @@ | |||
1 | import express from 'express' | ||
2 | import { body } from 'express-validator' | ||
3 | import { isValidPlayerMode } from '@server/helpers/custom-validators/metrics' | ||
4 | import { isIdOrUUIDValid, toCompleteUUID } from '@server/helpers/custom-validators/misc' | ||
5 | import { CONFIG } from '@server/initializers/config' | ||
6 | import { HttpStatusCode, PlaybackMetricCreate } from '@shared/models' | ||
7 | import { logger } from '../../helpers/logger' | ||
8 | import { areValidationErrors, doesVideoExist } from './shared' | ||
9 | |||
10 | const addPlaybackMetricValidator = [ | ||
11 | body('resolution') | ||
12 | .isInt({ min: 0 }).withMessage('Invalid resolution'), | ||
13 | body('fps') | ||
14 | .optional() | ||
15 | .isInt({ min: 0 }).withMessage('Invalid fps'), | ||
16 | body('playerMode') | ||
17 | .custom(isValidPlayerMode).withMessage('Invalid playerMode'), | ||
18 | |||
19 | body('resolutionChanges') | ||
20 | .isInt({ min: 0 }).withMessage('Invalid resolutionChanges'), | ||
21 | |||
22 | body('errors') | ||
23 | .isInt({ min: 0 }).withMessage('Invalid errors'), | ||
24 | |||
25 | body('downloadedBytesP2P') | ||
26 | .isInt({ min: 0 }).withMessage('Invalid downloadedBytesP2P'), | ||
27 | body('downloadedBytesHTTP') | ||
28 | .isInt({ min: 0 }).withMessage('Invalid downloadedBytesHTTP'), | ||
29 | |||
30 | body('uploadedBytesP2P') | ||
31 | .isInt({ min: 0 }).withMessage('Invalid uploadedBytesP2P'), | ||
32 | |||
33 | body('videoId') | ||
34 | .customSanitizer(toCompleteUUID) | ||
35 | .optional() | ||
36 | .custom(isIdOrUUIDValid), | ||
37 | |||
38 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
39 | logger.debug('Checking addPlaybackMetricValidator parameters.', { parameters: req.query }) | ||
40 | |||
41 | if (!CONFIG.OPEN_TELEMETRY.METRICS.ENABLED) return res.sendStatus(HttpStatusCode.NO_CONTENT_204) | ||
42 | |||
43 | const body: PlaybackMetricCreate = req.body | ||
44 | |||
45 | if (areValidationErrors(req, res)) return | ||
46 | if (!await doesVideoExist(body.videoId, res, 'only-immutable-attributes')) return | ||
47 | |||
48 | return next() | ||
49 | } | ||
50 | ] | ||
51 | |||
52 | // --------------------------------------------------------------------------- | ||
53 | |||
54 | export { | ||
55 | addPlaybackMetricValidator | ||
56 | } | ||
diff --git a/server/tests/api/check-params/index.ts b/server/tests/api/check-params/index.ts index 149305f49..cd7a38459 100644 --- a/server/tests/api/check-params/index.ts +++ b/server/tests/api/check-params/index.ts | |||
@@ -10,6 +10,7 @@ import './follows' | |||
10 | import './jobs' | 10 | import './jobs' |
11 | import './live' | 11 | import './live' |
12 | import './logs' | 12 | import './logs' |
13 | import './metrics' | ||
13 | import './my-user' | 14 | import './my-user' |
14 | import './plugins' | 15 | import './plugins' |
15 | import './redundancy' | 16 | import './redundancy' |
diff --git a/server/tests/api/check-params/metrics.ts b/server/tests/api/check-params/metrics.ts new file mode 100644 index 000000000..2d4509406 --- /dev/null +++ b/server/tests/api/check-params/metrics.ts | |||
@@ -0,0 +1,183 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import 'mocha' | ||
4 | import { omit } from 'lodash' | ||
5 | import { HttpStatusCode, PlaybackMetricCreate, VideoResolution } from '@shared/models' | ||
6 | import { cleanupTests, createSingleServer, makePostBodyRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' | ||
7 | |||
8 | describe('Test metrics API validators', function () { | ||
9 | let server: PeerTubeServer | ||
10 | let videoUUID: string | ||
11 | |||
12 | // --------------------------------------------------------------- | ||
13 | |||
14 | before(async function () { | ||
15 | this.timeout(120000) | ||
16 | |||
17 | server = await createSingleServer(1, { | ||
18 | open_telemetry: { | ||
19 | metrics: { | ||
20 | enabled: true | ||
21 | } | ||
22 | } | ||
23 | }) | ||
24 | |||
25 | await setAccessTokensToServers([ server ]) | ||
26 | |||
27 | const { uuid } = await server.videos.quickUpload({ name: 'video' }) | ||
28 | videoUUID = uuid | ||
29 | }) | ||
30 | |||
31 | describe('When adding playback metrics', function () { | ||
32 | const path = '/api/v1/metrics/playback' | ||
33 | let baseParams: PlaybackMetricCreate | ||
34 | |||
35 | before(function () { | ||
36 | baseParams = { | ||
37 | playerMode: 'p2p-media-loader', | ||
38 | resolution: VideoResolution.H_1080P, | ||
39 | fps: 30, | ||
40 | resolutionChanges: 1, | ||
41 | errors: 2, | ||
42 | downloadedBytesP2P: 0, | ||
43 | downloadedBytesHTTP: 0, | ||
44 | uploadedBytesP2P: 0, | ||
45 | videoId: videoUUID | ||
46 | } | ||
47 | }) | ||
48 | |||
49 | it('Should fail with an invalid resolution', async function () { | ||
50 | await makePostBodyRequest({ | ||
51 | url: server.url, | ||
52 | path, | ||
53 | fields: { ...baseParams, resolution: 'toto' } | ||
54 | }) | ||
55 | }) | ||
56 | |||
57 | it('Should fail with an invalid fps', async function () { | ||
58 | await makePostBodyRequest({ | ||
59 | url: server.url, | ||
60 | path, | ||
61 | fields: { ...baseParams, fps: 'toto' } | ||
62 | }) | ||
63 | }) | ||
64 | |||
65 | it('Should fail with a missing/invalid player mode', async function () { | ||
66 | await makePostBodyRequest({ | ||
67 | url: server.url, | ||
68 | path, | ||
69 | fields: omit(baseParams, 'playerMode') | ||
70 | }) | ||
71 | |||
72 | await makePostBodyRequest({ | ||
73 | url: server.url, | ||
74 | path, | ||
75 | fields: { ...baseParams, playerMode: 'toto' } | ||
76 | }) | ||
77 | }) | ||
78 | |||
79 | it('Should fail with an missing/invalid resolution changes', async function () { | ||
80 | await makePostBodyRequest({ | ||
81 | url: server.url, | ||
82 | path, | ||
83 | fields: omit(baseParams, 'resolutionChanges') | ||
84 | }) | ||
85 | |||
86 | await makePostBodyRequest({ | ||
87 | url: server.url, | ||
88 | path, | ||
89 | fields: { ...baseParams, resolutionChanges: 'toto' } | ||
90 | }) | ||
91 | }) | ||
92 | |||
93 | it('Should fail with a missing errors', async function () { | ||
94 | |||
95 | }) | ||
96 | |||
97 | it('Should fail with an missing/invalid errors', async function () { | ||
98 | await makePostBodyRequest({ | ||
99 | url: server.url, | ||
100 | path, | ||
101 | fields: omit(baseParams, 'errors') | ||
102 | }) | ||
103 | |||
104 | await makePostBodyRequest({ | ||
105 | url: server.url, | ||
106 | path, | ||
107 | fields: { ...baseParams, errors: 'toto' } | ||
108 | }) | ||
109 | }) | ||
110 | |||
111 | it('Should fail with an missing/invalid downloadedBytesP2P', async function () { | ||
112 | await makePostBodyRequest({ | ||
113 | url: server.url, | ||
114 | path, | ||
115 | fields: omit(baseParams, 'downloadedBytesP2P') | ||
116 | }) | ||
117 | |||
118 | await makePostBodyRequest({ | ||
119 | url: server.url, | ||
120 | path, | ||
121 | fields: { ...baseParams, downloadedBytesP2P: 'toto' } | ||
122 | }) | ||
123 | }) | ||
124 | |||
125 | it('Should fail with an missing/invalid downloadedBytesHTTP', async function () { | ||
126 | await makePostBodyRequest({ | ||
127 | url: server.url, | ||
128 | path, | ||
129 | fields: omit(baseParams, 'downloadedBytesHTTP') | ||
130 | }) | ||
131 | |||
132 | await makePostBodyRequest({ | ||
133 | url: server.url, | ||
134 | path, | ||
135 | fields: { ...baseParams, downloadedBytesHTTP: 'toto' } | ||
136 | }) | ||
137 | }) | ||
138 | |||
139 | it('Should fail with an missing/invalid uploadedBytesP2P', async function () { | ||
140 | await makePostBodyRequest({ | ||
141 | url: server.url, | ||
142 | path, | ||
143 | fields: omit(baseParams, 'uploadedBytesP2P') | ||
144 | }) | ||
145 | |||
146 | await makePostBodyRequest({ | ||
147 | url: server.url, | ||
148 | path, | ||
149 | fields: { ...baseParams, uploadedBytesP2P: 'toto' } | ||
150 | }) | ||
151 | }) | ||
152 | |||
153 | it('Should fail with a bad video id', async function () { | ||
154 | await makePostBodyRequest({ | ||
155 | url: server.url, | ||
156 | path, | ||
157 | fields: { ...baseParams, videoId: 'toto' } | ||
158 | }) | ||
159 | }) | ||
160 | |||
161 | it('Should fail with an unknown video', async function () { | ||
162 | await makePostBodyRequest({ | ||
163 | url: server.url, | ||
164 | path, | ||
165 | fields: { ...baseParams, videoId: 42 }, | ||
166 | expectedStatus: HttpStatusCode.NOT_FOUND_404 | ||
167 | }) | ||
168 | }) | ||
169 | |||
170 | it('Should succeed with the correct params', async function () { | ||
171 | await makePostBodyRequest({ | ||
172 | url: server.url, | ||
173 | path, | ||
174 | fields: baseParams, | ||
175 | expectedStatus: HttpStatusCode.NO_CONTENT_204 | ||
176 | }) | ||
177 | }) | ||
178 | }) | ||
179 | |||
180 | after(async function () { | ||
181 | await cleanupTests([ server ]) | ||
182 | }) | ||
183 | }) | ||
diff --git a/server/tests/api/server/open-telemetry.ts b/server/tests/api/server/open-telemetry.ts index 20909429f..3137a9eb6 100644 --- a/server/tests/api/server/open-telemetry.ts +++ b/server/tests/api/server/open-telemetry.ts | |||
@@ -2,14 +2,14 @@ | |||
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 } from '@shared/models' | 5 | import { HttpStatusCode, 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 () { |
9 | let server: PeerTubeServer | 9 | let server: PeerTubeServer |
10 | 10 | ||
11 | describe('Metrics', function () { | 11 | describe('Metrics', function () { |
12 | const metricsUrl = 'http://localhost:9091/metrics' | 12 | const metricsUrl = 'http://localhost:9092/metrics' |
13 | 13 | ||
14 | it('Should not enable open telemetry metrics', async function () { | 14 | it('Should not enable open telemetry metrics', async function () { |
15 | server = await createSingleServer(1) | 15 | server = await createSingleServer(1) |
@@ -36,8 +36,33 @@ describe('Open Telemetry', function () { | |||
36 | }) | 36 | }) |
37 | 37 | ||
38 | const res = await makeRawRequest(metricsUrl, HttpStatusCode.OK_200) | 38 | const res = await makeRawRequest(metricsUrl, HttpStatusCode.OK_200) |
39 | expect(res.text).to.contain('peertube_job_queue_total') | 39 | expect(res.text).to.contain('peertube_job_queue_total{') |
40 | }) | ||
41 | |||
42 | it('Should have playback metrics', async function () { | ||
43 | await setAccessTokensToServers([ server ]) | ||
44 | |||
45 | const video = await server.videos.quickUpload({ name: 'video' }) | ||
46 | |||
47 | await server.metrics.addPlaybackMetric({ | ||
48 | metrics: { | ||
49 | playerMode: 'p2p-media-loader', | ||
50 | resolution: VideoResolution.H_1080P, | ||
51 | fps: 30, | ||
52 | resolutionChanges: 1, | ||
53 | errors: 2, | ||
54 | downloadedBytesP2P: 0, | ||
55 | downloadedBytesHTTP: 0, | ||
56 | uploadedBytesP2P: 5, | ||
57 | videoId: video.uuid | ||
58 | } | ||
59 | }) | ||
40 | 60 | ||
61 | const res = await makeRawRequest(metricsUrl, HttpStatusCode.OK_200) | ||
62 | expect(res.text).to.contain('peertube_playback_http_uploaded_bytes_total{') | ||
63 | }) | ||
64 | |||
65 | after(async function () { | ||
41 | await server.kill() | 66 | await server.kill() |
42 | }) | 67 | }) |
43 | }) | 68 | }) |