diff options
author | Chocobozzz <me@florianbigard.com> | 2022-07-05 15:43:21 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2022-07-06 15:13:55 +0200 |
commit | 630d0a1bf5897fff203cb07e426223f55dcc882d (patch) | |
tree | 5e6fa9d26f3f21178a538bd1ac38fa0a3f4f228c | |
parent | 15b43b214eb37b05aa65aa8ef61fd0e6aa0b62d2 (diff) | |
download | PeerTube-630d0a1bf5897fff203cb07e426223f55dcc882d.tar.gz PeerTube-630d0a1bf5897fff203cb07e426223f55dcc882d.tar.zst PeerTube-630d0a1bf5897fff203cb07e426223f55dcc882d.zip |
Introduce experimental telemetry
23 files changed, 1002 insertions, 90 deletions
diff --git a/config/default.yaml b/config/default.yaml index 8e5d13355..8458ee016 100644 --- a/config/default.yaml +++ b/config/default.yaml | |||
@@ -177,6 +177,22 @@ log: | |||
177 | log_tracker_unknown_infohash: true | 177 | log_tracker_unknown_infohash: true |
178 | prettify_sql: false | 178 | prettify_sql: false |
179 | 179 | ||
180 | # Highly experimental support of Open Telemetry | ||
181 | open_telemetry: | ||
182 | metrics: | ||
183 | enabled: false | ||
184 | |||
185 | # Create a prometheus exporter server on this port so prometheus server can scrape PeerTube metrics | ||
186 | prometheus_exporter: | ||
187 | port: 9091 | ||
188 | |||
189 | tracing: | ||
190 | enabled: false | ||
191 | |||
192 | # Send traces to a Jaeger compatible endpoint | ||
193 | jaeger_exporter: | ||
194 | endpoint: '' | ||
195 | |||
180 | trending: | 196 | trending: |
181 | videos: | 197 | videos: |
182 | interval_days: 7 # Compute trending videos for the last x days | 198 | interval_days: 7 # Compute trending videos for the last x days |
diff --git a/config/production.yaml.example b/config/production.yaml.example index ef0358221..3da2421fe 100644 --- a/config/production.yaml.example +++ b/config/production.yaml.example | |||
@@ -175,6 +175,22 @@ log: | |||
175 | log_tracker_unknown_infohash: true | 175 | log_tracker_unknown_infohash: true |
176 | prettify_sql: false | 176 | prettify_sql: false |
177 | 177 | ||
178 | # Highly experimental support of Open Telemetry | ||
179 | open_telemetry: | ||
180 | metrics: | ||
181 | enabled: false | ||
182 | |||
183 | # Create a prometheus exporter server on this port so prometheus server can scrape PeerTube metrics | ||
184 | prometheus_exporter: | ||
185 | port: 9091 | ||
186 | |||
187 | tracing: | ||
188 | enabled: false | ||
189 | |||
190 | # Send traces to a Jaeger compatible endpoint | ||
191 | jaeger_exporter: | ||
192 | endpoint: '' | ||
193 | |||
178 | trending: | 194 | trending: |
179 | videos: | 195 | videos: |
180 | interval_days: 7 # Compute trending videos for the last x days | 196 | interval_days: 7 # Compute trending videos for the last x days |
diff --git a/package.json b/package.json index 6a5bcf75c..79bc7cf1f 100644 --- a/package.json +++ b/package.json | |||
@@ -85,6 +85,22 @@ | |||
85 | "@aws-sdk/node-http-handler": "^3.82.0", | 85 | "@aws-sdk/node-http-handler": "^3.82.0", |
86 | "@babel/parser": "7.17.8", | 86 | "@babel/parser": "7.17.8", |
87 | "@node-oauth/oauth2-server": "^4.2.0", | 87 | "@node-oauth/oauth2-server": "^4.2.0", |
88 | "@opentelemetry/api": "^1.1.0", | ||
89 | "@opentelemetry/api-metrics": "^0.29.2", | ||
90 | "@opentelemetry/exporter-jaeger": "^1.3.1", | ||
91 | "@opentelemetry/exporter-prometheus": "~0.29.2", | ||
92 | "@opentelemetry/instrumentation": "^0.29.2", | ||
93 | "@opentelemetry/instrumentation-dns": "^0.29.0", | ||
94 | "@opentelemetry/instrumentation-express": "^0.30.0", | ||
95 | "@opentelemetry/instrumentation-fs": "^0.4.0", | ||
96 | "@opentelemetry/instrumentation-http": "^0.29.2", | ||
97 | "@opentelemetry/instrumentation-pg": "^0.30.0", | ||
98 | "@opentelemetry/instrumentation-redis-4": "^0.31.0", | ||
99 | "@opentelemetry/resources": "^1.3.1", | ||
100 | "@opentelemetry/sdk-metrics-base": "~0.29.2", | ||
101 | "@opentelemetry/sdk-trace-base": "^1.3.1", | ||
102 | "@opentelemetry/sdk-trace-node": "^1.3.1", | ||
103 | "@opentelemetry/semantic-conventions": "^1.3.1", | ||
88 | "@peertube/feed": "^5.0.1", | 104 | "@peertube/feed": "^5.0.1", |
89 | "@peertube/http-signature": "^1.6.0", | 105 | "@peertube/http-signature": "^1.6.0", |
90 | "@uploadx/core": "^5.1.2", | 106 | "@uploadx/core": "^5.1.2", |
@@ -1,4 +1,7 @@ | |||
1 | // ----------- Node modules ----------- | 1 | // ----------- Node modules ----------- |
2 | import { registerOpentelemetryTracing } from './server/lib/opentelemetry/tracing' | ||
3 | registerOpentelemetryTracing() | ||
4 | |||
2 | import express from 'express' | 5 | import express from 'express' |
3 | import morgan, { token } from 'morgan' | 6 | import morgan, { token } from 'morgan' |
4 | import cors from 'cors' | 7 | import cors from 'cors' |
@@ -47,6 +50,12 @@ checkConfig() | |||
47 | // Trust our proxy (IP forwarding...) | 50 | // Trust our proxy (IP forwarding...) |
48 | app.set('trust proxy', CONFIG.TRUST_PROXY) | 51 | app.set('trust proxy', CONFIG.TRUST_PROXY) |
49 | 52 | ||
53 | app.use((_req, res, next) => { | ||
54 | res.locals.requestStart = Date.now() | ||
55 | |||
56 | return next() | ||
57 | }) | ||
58 | |||
50 | // Security middleware | 59 | // Security middleware |
51 | import { baseCSP } from './server/middlewares/csp' | 60 | import { baseCSP } from './server/middlewares/csp' |
52 | 61 | ||
@@ -126,6 +135,7 @@ import { VideosTorrentCache } from '@server/lib/files-cache/videos-torrent-cache | |||
126 | import { ServerConfigManager } from '@server/lib/server-config-manager' | 135 | import { ServerConfigManager } from '@server/lib/server-config-manager' |
127 | import { VideoViewsManager } from '@server/lib/views/video-views-manager' | 136 | import { VideoViewsManager } from '@server/lib/views/video-views-manager' |
128 | import { isTestInstance } from './server/helpers/core-utils' | 137 | import { isTestInstance } from './server/helpers/core-utils' |
138 | import { OpenTelemetryMetrics } from '@server/lib/opentelemetry/metrics' | ||
129 | 139 | ||
130 | // ----------- Command line ----------- | 140 | // ----------- Command line ----------- |
131 | 141 | ||
@@ -194,6 +204,10 @@ app.use(cookieParser()) | |||
194 | // W3C DNT Tracking Status | 204 | // W3C DNT Tracking Status |
195 | app.use(advertiseDoNotTrack) | 205 | app.use(advertiseDoNotTrack) |
196 | 206 | ||
207 | // ----------- Open Telemetry ----------- | ||
208 | |||
209 | OpenTelemetryMetrics.Instance.init(app) | ||
210 | |||
197 | // ----------- Views, routes and static files ----------- | 211 | // ----------- Views, routes and static files ----------- |
198 | 212 | ||
199 | // API | 213 | // API |
@@ -297,6 +311,7 @@ async function startApplication () { | |||
297 | RemoveDanglingResumableUploadsScheduler.Instance.enable() | 311 | RemoveDanglingResumableUploadsScheduler.Instance.enable() |
298 | VideoViewsBufferScheduler.Instance.enable() | 312 | VideoViewsBufferScheduler.Instance.enable() |
299 | GeoIPUpdateScheduler.Instance.enable() | 313 | GeoIPUpdateScheduler.Instance.enable() |
314 | OpenTelemetryMetrics.Instance.registerMetrics() | ||
300 | 315 | ||
301 | Redis.Instance.init() | 316 | Redis.Instance.init() |
302 | PeerTubeSocket.Instance.init(server) | 317 | PeerTubeSocket.Instance.init(server) |
diff --git a/server/helpers/logger.ts b/server/helpers/logger.ts index 4fbaf8a73..9625c1b33 100644 --- a/server/helpers/logger.ts +++ b/server/helpers/logger.ts | |||
@@ -1,54 +1,18 @@ | |||
1 | // Thanks http://tostring.it/2014/06/23/advanced-logging-with-nodejs/ | ||
2 | import { stat } from 'fs-extra' | 1 | import { stat } from 'fs-extra' |
3 | import { omit } from 'lodash' | 2 | import { omit } from 'lodash' |
4 | import { join } from 'path' | 3 | import { join } from 'path' |
5 | import { format as sqlFormat } from 'sql-formatter' | 4 | import { format as sqlFormat } from 'sql-formatter' |
6 | import { createLogger, format, transports } from 'winston' | 5 | import { createLogger, format, transports } from 'winston' |
7 | import { FileTransportOptions } from 'winston/lib/winston/transports' | 6 | import { FileTransportOptions } from 'winston/lib/winston/transports' |
7 | import { context } from '@opentelemetry/api' | ||
8 | import { getSpanContext } from '@opentelemetry/api/build/src/trace/context-utils' | ||
8 | import { CONFIG } from '../initializers/config' | 9 | import { CONFIG } from '../initializers/config' |
9 | import { LOG_FILENAME } from '../initializers/constants' | 10 | import { LOG_FILENAME } from '../initializers/constants' |
10 | 11 | ||
11 | const label = CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT | 12 | const label = CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT |
12 | 13 | ||
13 | function getLoggerReplacer () { | ||
14 | const seen = new WeakSet() | ||
15 | |||
16 | // Thanks: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value#Examples | ||
17 | return (key: string, value: any) => { | ||
18 | if (key === 'cert') return 'Replaced by the logger to avoid large log message' | ||
19 | |||
20 | if (typeof value === 'object' && value !== null) { | ||
21 | if (seen.has(value)) return | ||
22 | |||
23 | seen.add(value) | ||
24 | } | ||
25 | |||
26 | if (value instanceof Set) { | ||
27 | return Array.from(value) | ||
28 | } | ||
29 | |||
30 | if (value instanceof Map) { | ||
31 | return Array.from(value.entries()) | ||
32 | } | ||
33 | |||
34 | if (value instanceof Error) { | ||
35 | const error = {} | ||
36 | |||
37 | Object.getOwnPropertyNames(value).forEach(key => { error[key] = value[key] }) | ||
38 | |||
39 | return error | ||
40 | } | ||
41 | |||
42 | return value | ||
43 | } | ||
44 | } | ||
45 | |||
46 | const consoleLoggerFormat = format.printf(info => { | 14 | const consoleLoggerFormat = format.printf(info => { |
47 | const toOmit = [ 'label', 'timestamp', 'level', 'message', 'sql', 'tags' ] | 15 | let additionalInfos = JSON.stringify(getAdditionalInfo(info), removeCyclicValues(), 2) |
48 | |||
49 | const obj = omit(info, ...toOmit) | ||
50 | |||
51 | let additionalInfos = JSON.stringify(obj, getLoggerReplacer(), 2) | ||
52 | 16 | ||
53 | if (additionalInfos === undefined || additionalInfos === '{}') additionalInfos = '' | 17 | if (additionalInfos === undefined || additionalInfos === '{}') additionalInfos = '' |
54 | else additionalInfos = ' ' + additionalInfos | 18 | else additionalInfos = ' ' + additionalInfos |
@@ -68,7 +32,7 @@ const consoleLoggerFormat = format.printf(info => { | |||
68 | }) | 32 | }) |
69 | 33 | ||
70 | const jsonLoggerFormat = format.printf(info => { | 34 | const jsonLoggerFormat = format.printf(info => { |
71 | return JSON.stringify(info, getLoggerReplacer()) | 35 | return JSON.stringify(info, removeCyclicValues()) |
72 | }) | 36 | }) |
73 | 37 | ||
74 | const timestampFormatter = format.timestamp({ | 38 | const timestampFormatter = format.timestamp({ |
@@ -94,11 +58,14 @@ if (CONFIG.LOG.ROTATION.ENABLED) { | |||
94 | fileLoggerOptions.maxFiles = CONFIG.LOG.ROTATION.MAX_FILES | 58 | fileLoggerOptions.maxFiles = CONFIG.LOG.ROTATION.MAX_FILES |
95 | } | 59 | } |
96 | 60 | ||
97 | const logger = buildLogger() | ||
98 | |||
99 | function buildLogger (labelSuffix?: string) { | 61 | function buildLogger (labelSuffix?: string) { |
100 | return createLogger({ | 62 | return createLogger({ |
101 | level: CONFIG.LOG.LEVEL, | 63 | level: CONFIG.LOG.LEVEL, |
64 | defaultMeta: { | ||
65 | get traceId () { return getSpanContext(context.active())?.traceId }, | ||
66 | get spanId () { return getSpanContext(context.active())?.spanId }, | ||
67 | get traceFlags () { return getSpanContext(context.active())?.traceFlags } | ||
68 | }, | ||
102 | format: format.combine( | 69 | format: format.combine( |
103 | labelFormatter(labelSuffix), | 70 | labelFormatter(labelSuffix), |
104 | format.splat() | 71 | format.splat() |
@@ -118,6 +85,10 @@ function buildLogger (labelSuffix?: string) { | |||
118 | }) | 85 | }) |
119 | } | 86 | } |
120 | 87 | ||
88 | const logger = buildLogger() | ||
89 | |||
90 | // --------------------------------------------------------------------------- | ||
91 | |||
121 | function bunyanLogFactory (level: string) { | 92 | function bunyanLogFactory (level: string) { |
122 | return function (...params: any[]) { | 93 | return function (...params: any[]) { |
123 | let meta = null | 94 | let meta = null |
@@ -141,12 +112,15 @@ const bunyanLogger = { | |||
141 | level: () => { }, | 112 | level: () => { }, |
142 | trace: bunyanLogFactory('debug'), | 113 | trace: bunyanLogFactory('debug'), |
143 | debug: bunyanLogFactory('debug'), | 114 | debug: bunyanLogFactory('debug'), |
115 | verbose: bunyanLogFactory('debug'), | ||
144 | info: bunyanLogFactory('info'), | 116 | info: bunyanLogFactory('info'), |
145 | warn: bunyanLogFactory('warn'), | 117 | warn: bunyanLogFactory('warn'), |
146 | error: bunyanLogFactory('error'), | 118 | error: bunyanLogFactory('error'), |
147 | fatal: bunyanLogFactory('error') | 119 | fatal: bunyanLogFactory('error') |
148 | } | 120 | } |
149 | 121 | ||
122 | // --------------------------------------------------------------------------- | ||
123 | |||
150 | type LoggerTagsFn = (...tags: string[]) => { tags: string[] } | 124 | type LoggerTagsFn = (...tags: string[]) => { tags: string[] } |
151 | function loggerTagsFactory (...defaultTags: string[]): LoggerTagsFn { | 125 | function loggerTagsFactory (...defaultTags: string[]): LoggerTagsFn { |
152 | return (...tags: string[]) => { | 126 | return (...tags: string[]) => { |
@@ -154,6 +128,8 @@ function loggerTagsFactory (...defaultTags: string[]): LoggerTagsFn { | |||
154 | } | 128 | } |
155 | } | 129 | } |
156 | 130 | ||
131 | // --------------------------------------------------------------------------- | ||
132 | |||
157 | async function mtimeSortFilesDesc (files: string[], basePath: string) { | 133 | async function mtimeSortFilesDesc (files: string[], basePath: string) { |
158 | const promises = [] | 134 | const promises = [] |
159 | const out: { file: string, mtime: number }[] = [] | 135 | const out: { file: string, mtime: number }[] = [] |
@@ -189,3 +165,44 @@ export { | |||
189 | loggerTagsFactory, | 165 | loggerTagsFactory, |
190 | bunyanLogger | 166 | bunyanLogger |
191 | } | 167 | } |
168 | |||
169 | // --------------------------------------------------------------------------- | ||
170 | |||
171 | function removeCyclicValues () { | ||
172 | const seen = new WeakSet() | ||
173 | |||
174 | // Thanks: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value#Examples | ||
175 | return (key: string, value: any) => { | ||
176 | if (key === 'cert') return 'Replaced by the logger to avoid large log message' | ||
177 | |||
178 | if (typeof value === 'object' && value !== null) { | ||
179 | if (seen.has(value)) return | ||
180 | |||
181 | seen.add(value) | ||
182 | } | ||
183 | |||
184 | if (value instanceof Set) { | ||
185 | return Array.from(value) | ||
186 | } | ||
187 | |||
188 | if (value instanceof Map) { | ||
189 | return Array.from(value.entries()) | ||
190 | } | ||
191 | |||
192 | if (value instanceof Error) { | ||
193 | const error = {} | ||
194 | |||
195 | Object.getOwnPropertyNames(value).forEach(key => { error[key] = value[key] }) | ||
196 | |||
197 | return error | ||
198 | } | ||
199 | |||
200 | return value | ||
201 | } | ||
202 | } | ||
203 | |||
204 | function getAdditionalInfo (info: any) { | ||
205 | const toOmit = [ 'label', 'timestamp', 'level', 'message', 'sql', 'tags' ] | ||
206 | |||
207 | return omit(info, ...toOmit) | ||
208 | } | ||
diff --git a/server/initializers/config.ts b/server/initializers/config.ts index 754585981..0943ffe2d 100644 --- a/server/initializers/config.ts +++ b/server/initializers/config.ts | |||
@@ -167,6 +167,22 @@ const CONFIG = { | |||
167 | LOG_TRACKER_UNKNOWN_INFOHASH: config.get<boolean>('log.log_tracker_unknown_infohash'), | 167 | LOG_TRACKER_UNKNOWN_INFOHASH: config.get<boolean>('log.log_tracker_unknown_infohash'), |
168 | PRETTIFY_SQL: config.get<boolean>('log.prettify_sql') | 168 | PRETTIFY_SQL: config.get<boolean>('log.prettify_sql') |
169 | }, | 169 | }, |
170 | OPEN_TELEMETRY: { | ||
171 | METRICS: { | ||
172 | ENABLED: config.get<boolean>('open_telemetry.metrics.enabled'), | ||
173 | |||
174 | PROMETHEUS_EXPORTER: { | ||
175 | PORT: config.get<number>('open_telemetry.metrics.prometheus_exporter.port') | ||
176 | } | ||
177 | }, | ||
178 | TRACING: { | ||
179 | ENABLED: config.get<boolean>('open_telemetry.tracing.enabled'), | ||
180 | |||
181 | JAEGER_EXPORTER: { | ||
182 | ENDPOINT: config.get<string>('open_telemetry.tracing.jaeger_exporter.endpoint') | ||
183 | } | ||
184 | } | ||
185 | }, | ||
170 | TRENDING: { | 186 | TRENDING: { |
171 | VIDEOS: { | 187 | VIDEOS: { |
172 | INTERVAL_DAYS: config.get<number>('trending.videos.interval_days'), | 188 | INTERVAL_DAYS: config.get<number>('trending.videos.interval_days'), |
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index c6989c38b..e3683269c 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts | |||
@@ -736,7 +736,8 @@ const MEMOIZE_TTL = { | |||
736 | INFO_HASH_EXISTS: 1000 * 3600 * 12, // 12 hours | 736 | INFO_HASH_EXISTS: 1000 * 3600 * 12, // 12 hours |
737 | VIDEO_DURATION: 1000 * 10, // 10 seconds | 737 | VIDEO_DURATION: 1000 * 10, // 10 seconds |
738 | LIVE_ABLE_TO_UPLOAD: 1000 * 60, // 1 minute | 738 | LIVE_ABLE_TO_UPLOAD: 1000 * 60, // 1 minute |
739 | LIVE_CHECK_SOCKET_HEALTH: 1000 * 60 // 1 minute | 739 | LIVE_CHECK_SOCKET_HEALTH: 1000 * 60, // 1 minute |
740 | GET_STATS_FOR_OPEN_TELEMETRY_METRICS: 1000 * 60 // 1 minute | ||
740 | } | 741 | } |
741 | 742 | ||
742 | const MEMOIZE_LENGTH = { | 743 | const MEMOIZE_LENGTH = { |
diff --git a/server/lib/activitypub/activity.ts b/server/lib/activitypub/activity.ts index e6cec1ba7..ba2967ce9 100644 --- a/server/lib/activitypub/activity.ts +++ b/server/lib/activitypub/activity.ts | |||
@@ -1,3 +1,5 @@ | |||
1 | import { ActivityType } from "@shared/models" | ||
2 | |||
1 | function getAPId (object: string | { id: string }) { | 3 | function getAPId (object: string | { id: string }) { |
2 | if (typeof object === 'string') return object | 4 | if (typeof object === 'string') return object |
3 | 5 | ||
@@ -13,8 +15,26 @@ function getDurationFromActivityStream (duration: string) { | |||
13 | return parseInt(duration.replace(/[^\d]+/, '')) | 15 | return parseInt(duration.replace(/[^\d]+/, '')) |
14 | } | 16 | } |
15 | 17 | ||
18 | function buildAvailableActivities (): ActivityType[] { | ||
19 | return [ | ||
20 | 'Create', | ||
21 | 'Update', | ||
22 | 'Delete', | ||
23 | 'Follow', | ||
24 | 'Accept', | ||
25 | 'Announce', | ||
26 | 'Undo', | ||
27 | 'Like', | ||
28 | 'Reject', | ||
29 | 'View', | ||
30 | 'Dislike', | ||
31 | 'Flag' | ||
32 | ] | ||
33 | } | ||
34 | |||
16 | export { | 35 | export { |
17 | getAPId, | 36 | getAPId, |
18 | getActivityStreamDuration, | 37 | getActivityStreamDuration, |
38 | buildAvailableActivities, | ||
19 | getDurationFromActivityStream | 39 | getDurationFromActivityStream |
20 | } | 40 | } |
diff --git a/server/lib/job-queue/job-queue.ts b/server/lib/job-queue/job-queue.ts index ce24763f1..e55d2e7c2 100644 --- a/server/lib/job-queue/job-queue.ts +++ b/server/lib/job-queue/job-queue.ts | |||
@@ -285,6 +285,12 @@ class JobQueue { | |||
285 | return total | 285 | return total |
286 | } | 286 | } |
287 | 287 | ||
288 | async getStats () { | ||
289 | const promises = jobTypes.map(async t => ({ jobType: t, counts: await this.queues[t].getJobCounts() })) | ||
290 | |||
291 | return Promise.all(promises) | ||
292 | } | ||
293 | |||
288 | async removeOldJobs () { | 294 | async removeOldJobs () { |
289 | for (const key of Object.keys(this.queues)) { | 295 | for (const key of Object.keys(this.queues)) { |
290 | const queue = this.queues[key] | 296 | const queue = this.queues[key] |
diff --git a/server/lib/opentelemetry/metric-helpers/index.ts b/server/lib/opentelemetry/metric-helpers/index.ts new file mode 100644 index 000000000..cabb27326 --- /dev/null +++ b/server/lib/opentelemetry/metric-helpers/index.ts | |||
@@ -0,0 +1 @@ | |||
export * from './stats-observers-builder' | |||
diff --git a/server/lib/opentelemetry/metric-helpers/stats-observers-builder.ts b/server/lib/opentelemetry/metric-helpers/stats-observers-builder.ts new file mode 100644 index 000000000..90b58f33d --- /dev/null +++ b/server/lib/opentelemetry/metric-helpers/stats-observers-builder.ts | |||
@@ -0,0 +1,186 @@ | |||
1 | import memoizee from 'memoizee' | ||
2 | import { Meter } from '@opentelemetry/api-metrics' | ||
3 | import { MEMOIZE_TTL } from '@server/initializers/constants' | ||
4 | import { buildAvailableActivities } from '@server/lib/activitypub/activity' | ||
5 | import { StatsManager } from '@server/lib/stat-manager' | ||
6 | |||
7 | export class StatsObserverBuilder { | ||
8 | |||
9 | private readonly getInstanceStats = memoizee(() => { | ||
10 | return StatsManager.Instance.getStats() | ||
11 | }, { maxAge: MEMOIZE_TTL.GET_STATS_FOR_OPEN_TELEMETRY_METRICS }) | ||
12 | |||
13 | constructor (private readonly meter: Meter) { | ||
14 | |||
15 | } | ||
16 | |||
17 | buildObservers () { | ||
18 | this.buildUserStatsObserver() | ||
19 | this.buildVideoStatsObserver() | ||
20 | this.buildCommentStatsObserver() | ||
21 | this.buildPlaylistStatsObserver() | ||
22 | this.buildChannelStatsObserver() | ||
23 | this.buildInstanceFollowsStatsObserver() | ||
24 | this.buildRedundancyStatsObserver() | ||
25 | this.buildActivityPubStatsObserver() | ||
26 | } | ||
27 | |||
28 | private buildUserStatsObserver () { | ||
29 | this.meter.createObservableGauge('peertube_users_total', { | ||
30 | description: 'Total users on the instance' | ||
31 | }).addCallback(async observableResult => { | ||
32 | const stats = await this.getInstanceStats() | ||
33 | |||
34 | observableResult.observe(stats.totalUsers) | ||
35 | }) | ||
36 | |||
37 | this.meter.createObservableGauge('peertube_active_users_total', { | ||
38 | description: 'Total active users on the instance' | ||
39 | }).addCallback(async observableResult => { | ||
40 | const stats = await this.getInstanceStats() | ||
41 | |||
42 | observableResult.observe(stats.totalDailyActiveUsers, { activeInterval: 'daily' }) | ||
43 | observableResult.observe(stats.totalWeeklyActiveUsers, { activeInterval: 'weekly' }) | ||
44 | observableResult.observe(stats.totalMonthlyActiveUsers, { activeInterval: 'monthly' }) | ||
45 | }) | ||
46 | } | ||
47 | |||
48 | private buildChannelStatsObserver () { | ||
49 | this.meter.createObservableGauge('peertube_channels_total', { | ||
50 | description: 'Total channels on the instance' | ||
51 | }).addCallback(async observableResult => { | ||
52 | const stats = await this.getInstanceStats() | ||
53 | |||
54 | observableResult.observe(stats.totalLocalVideoChannels, { channelOrigin: 'local' }) | ||
55 | }) | ||
56 | |||
57 | this.meter.createObservableGauge('peertube_active_channels_total', { | ||
58 | description: 'Total active channels on the instance' | ||
59 | }).addCallback(async observableResult => { | ||
60 | const stats = await this.getInstanceStats() | ||
61 | |||
62 | observableResult.observe(stats.totalLocalDailyActiveVideoChannels, { channelOrigin: 'local', activeInterval: 'daily' }) | ||
63 | observableResult.observe(stats.totalLocalWeeklyActiveVideoChannels, { channelOrigin: 'local', activeInterval: 'weekly' }) | ||
64 | observableResult.observe(stats.totalLocalMonthlyActiveVideoChannels, { channelOrigin: 'local', activeInterval: 'monthly' }) | ||
65 | }) | ||
66 | } | ||
67 | |||
68 | private buildVideoStatsObserver () { | ||
69 | this.meter.createObservableGauge('peertube_videos_total', { | ||
70 | description: 'Total videos on the instance' | ||
71 | }).addCallback(async observableResult => { | ||
72 | const stats = await this.getInstanceStats() | ||
73 | |||
74 | observableResult.observe(stats.totalLocalVideos, { videoOrigin: 'local' }) | ||
75 | observableResult.observe(stats.totalVideos - stats.totalLocalVideos, { videoOrigin: 'remote' }) | ||
76 | }) | ||
77 | |||
78 | this.meter.createObservableGauge('peertube_video_views_total', { | ||
79 | description: 'Total video views made on the instance' | ||
80 | }).addCallback(async observableResult => { | ||
81 | const stats = await this.getInstanceStats() | ||
82 | |||
83 | observableResult.observe(stats.totalLocalVideoViews, { viewOrigin: 'local' }) | ||
84 | }) | ||
85 | |||
86 | this.meter.createObservableGauge('peertube_video_bytes_total', { | ||
87 | description: 'Total bytes of videos' | ||
88 | }).addCallback(async observableResult => { | ||
89 | const stats = await this.getInstanceStats() | ||
90 | |||
91 | observableResult.observe(stats.totalLocalVideoFilesSize, { videoOrigin: 'local' }) | ||
92 | }) | ||
93 | } | ||
94 | |||
95 | private buildCommentStatsObserver () { | ||
96 | this.meter.createObservableGauge('peertube_comments_total', { | ||
97 | description: 'Total comments on the instance' | ||
98 | }).addCallback(async observableResult => { | ||
99 | const stats = await this.getInstanceStats() | ||
100 | |||
101 | observableResult.observe(stats.totalLocalVideoComments, { accountOrigin: 'local' }) | ||
102 | }) | ||
103 | } | ||
104 | |||
105 | private buildPlaylistStatsObserver () { | ||
106 | this.meter.createObservableGauge('peertube_playlists_total', { | ||
107 | description: 'Total playlists on the instance' | ||
108 | }).addCallback(async observableResult => { | ||
109 | const stats = await this.getInstanceStats() | ||
110 | |||
111 | observableResult.observe(stats.totalLocalPlaylists, { playlistOrigin: 'local' }) | ||
112 | }) | ||
113 | } | ||
114 | |||
115 | private buildInstanceFollowsStatsObserver () { | ||
116 | this.meter.createObservableGauge('peertube_instance_followers_total', { | ||
117 | description: 'Total followers of the instance' | ||
118 | }).addCallback(async observableResult => { | ||
119 | const stats = await this.getInstanceStats() | ||
120 | |||
121 | observableResult.observe(stats.totalInstanceFollowers) | ||
122 | }) | ||
123 | |||
124 | this.meter.createObservableGauge('peertube_instance_following_total', { | ||
125 | description: 'Total following of the instance' | ||
126 | }).addCallback(async observableResult => { | ||
127 | const stats = await this.getInstanceStats() | ||
128 | |||
129 | observableResult.observe(stats.totalInstanceFollowing) | ||
130 | }) | ||
131 | } | ||
132 | |||
133 | private buildRedundancyStatsObserver () { | ||
134 | this.meter.createObservableGauge('peertube_redundancy_used_bytes_total', { | ||
135 | description: 'Total redundancy used of the instance' | ||
136 | }).addCallback(async observableResult => { | ||
137 | const stats = await this.getInstanceStats() | ||
138 | |||
139 | for (const r of stats.videosRedundancy) { | ||
140 | observableResult.observe(r.totalUsed, { strategy: r.strategy }) | ||
141 | } | ||
142 | }) | ||
143 | |||
144 | this.meter.createObservableGauge('peertube_redundancy_available_bytes_total', { | ||
145 | description: 'Total redundancy available of the instance' | ||
146 | }).addCallback(async observableResult => { | ||
147 | const stats = await this.getInstanceStats() | ||
148 | |||
149 | for (const r of stats.videosRedundancy) { | ||
150 | observableResult.observe(r.totalSize, { strategy: r.strategy }) | ||
151 | } | ||
152 | }) | ||
153 | } | ||
154 | |||
155 | private buildActivityPubStatsObserver () { | ||
156 | const availableActivities = buildAvailableActivities() | ||
157 | |||
158 | this.meter.createObservableGauge('peertube_ap_inbox_success_total', { | ||
159 | description: 'Total inbox messages processed with success' | ||
160 | }).addCallback(async observableResult => { | ||
161 | const stats = await this.getInstanceStats() | ||
162 | |||
163 | for (const type of availableActivities) { | ||
164 | observableResult.observe(stats[`totalActivityPub${type}MessagesSuccesses`], { activityType: type }) | ||
165 | } | ||
166 | }) | ||
167 | |||
168 | this.meter.createObservableGauge('peertube_ap_inbox_error_total', { | ||
169 | description: 'Total inbox messages processed with error' | ||
170 | }).addCallback(async observableResult => { | ||
171 | const stats = await this.getInstanceStats() | ||
172 | |||
173 | for (const type of availableActivities) { | ||
174 | observableResult.observe(stats[`totalActivityPub${type}MessagesErrors`], { activityType: type }) | ||
175 | } | ||
176 | }) | ||
177 | |||
178 | this.meter.createObservableGauge('peertube_ap_inbox_waiting_total', { | ||
179 | description: 'Total inbox messages waiting for being processed' | ||
180 | }).addCallback(async observableResult => { | ||
181 | const stats = await this.getInstanceStats() | ||
182 | |||
183 | observableResult.observe(stats.totalActivityPubMessagesWaiting) | ||
184 | }) | ||
185 | } | ||
186 | } | ||
diff --git a/server/lib/opentelemetry/metrics.ts b/server/lib/opentelemetry/metrics.ts new file mode 100644 index 000000000..ca0aae8e7 --- /dev/null +++ b/server/lib/opentelemetry/metrics.ts | |||
@@ -0,0 +1,111 @@ | |||
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' | ||
7 | import { JobQueue } from '../job-queue' | ||
8 | import { StatsObserverBuilder } from './metric-helpers' | ||
9 | |||
10 | class OpenTelemetryMetrics { | ||
11 | |||
12 | private static instance: OpenTelemetryMetrics | ||
13 | |||
14 | private meter: Meter | ||
15 | |||
16 | private onRequestDuration: (req: Request, res: Response) => void | ||
17 | |||
18 | private constructor () {} | ||
19 | |||
20 | init (app: Application) { | ||
21 | if (CONFIG.OPEN_TELEMETRY.METRICS.ENABLED !== true) return | ||
22 | |||
23 | app.use((req, res, next) => { | ||
24 | res.once('finish', () => { | ||
25 | if (!this.onRequestDuration) return | ||
26 | |||
27 | this.onRequestDuration(req as Request, res as Response) | ||
28 | }) | ||
29 | |||
30 | next() | ||
31 | }) | ||
32 | } | ||
33 | |||
34 | registerMetrics () { | ||
35 | if (CONFIG.OPEN_TELEMETRY.METRICS.ENABLED !== true) return | ||
36 | |||
37 | logger.info('Registering Open Telemetry metrics') | ||
38 | |||
39 | const provider = new MeterProvider() | ||
40 | |||
41 | provider.addMetricReader(new PrometheusExporter({ port: CONFIG.OPEN_TELEMETRY.METRICS.PROMETHEUS_EXPORTER.PORT })) | ||
42 | |||
43 | metrics.setGlobalMeterProvider(provider) | ||
44 | |||
45 | this.meter = metrics.getMeter('default') | ||
46 | |||
47 | this.buildMemoryObserver() | ||
48 | this.buildRequestObserver() | ||
49 | this.buildJobQueueObserver() | ||
50 | |||
51 | const statsObserverBuilder = new StatsObserverBuilder(this.meter) | ||
52 | statsObserverBuilder.buildObservers() | ||
53 | } | ||
54 | |||
55 | private buildMemoryObserver () { | ||
56 | this.meter.createObservableGauge('nodejs_memory_usage_bytes', { | ||
57 | description: 'Memory' | ||
58 | }).addCallback(observableResult => { | ||
59 | const current = process.memoryUsage() | ||
60 | |||
61 | observableResult.observe(current.heapTotal, { memoryType: 'heapTotal' }) | ||
62 | observableResult.observe(current.heapUsed, { memoryType: 'heapUsed' }) | ||
63 | observableResult.observe(current.arrayBuffers, { memoryType: 'arrayBuffers' }) | ||
64 | observableResult.observe(current.external, { memoryType: 'external' }) | ||
65 | observableResult.observe(current.rss, { memoryType: 'rss' }) | ||
66 | }) | ||
67 | } | ||
68 | |||
69 | private buildJobQueueObserver () { | ||
70 | this.meter.createObservableGauge('peertube_job_queue_total', { | ||
71 | description: 'Total jobs in the PeerTube job queue' | ||
72 | }).addCallback(async observableResult => { | ||
73 | const stats = await JobQueue.Instance.getStats() | ||
74 | |||
75 | for (const { jobType, counts } of stats) { | ||
76 | for (const state of Object.keys(counts)) { | ||
77 | observableResult.observe(counts[state], { jobType, state }) | ||
78 | } | ||
79 | } | ||
80 | }) | ||
81 | } | ||
82 | |||
83 | private buildRequestObserver () { | ||
84 | const requestDuration = this.meter.createHistogram('http_request_duration_ms', { | ||
85 | unit: 'milliseconds', | ||
86 | description: 'Duration of HTTP requests in ms' | ||
87 | }) | ||
88 | |||
89 | this.onRequestDuration = (req: Request, res: Response) => { | ||
90 | const duration = Date.now() - res.locals.requestStart | ||
91 | |||
92 | requestDuration.record(duration, { | ||
93 | path: this.buildRequestPath(req.originalUrl), | ||
94 | method: req.method, | ||
95 | statusCode: res.statusCode + '' | ||
96 | }) | ||
97 | } | ||
98 | } | ||
99 | |||
100 | private buildRequestPath (path: string) { | ||
101 | return path.split('?')[0] | ||
102 | } | ||
103 | |||
104 | static get Instance () { | ||
105 | return this.instance || (this.instance = new this()) | ||
106 | } | ||
107 | } | ||
108 | |||
109 | export { | ||
110 | OpenTelemetryMetrics | ||
111 | } | ||
diff --git a/server/lib/opentelemetry/tracing.ts b/server/lib/opentelemetry/tracing.ts new file mode 100644 index 000000000..5358d04de --- /dev/null +++ b/server/lib/opentelemetry/tracing.ts | |||
@@ -0,0 +1,81 @@ | |||
1 | import { diag, DiagLogLevel, trace } from '@opentelemetry/api' | ||
2 | import { JaegerExporter } from '@opentelemetry/exporter-jaeger' | ||
3 | import { registerInstrumentations } from '@opentelemetry/instrumentation' | ||
4 | import { DnsInstrumentation } from '@opentelemetry/instrumentation-dns' | ||
5 | import { ExpressInstrumentation } from '@opentelemetry/instrumentation-express' | ||
6 | import FsInstrumentation from '@opentelemetry/instrumentation-fs' | ||
7 | import { HttpInstrumentation } from '@opentelemetry/instrumentation-http' | ||
8 | import { PgInstrumentation } from '@opentelemetry/instrumentation-pg' | ||
9 | import { RedisInstrumentation } from '@opentelemetry/instrumentation-redis-4' | ||
10 | import { Resource } from '@opentelemetry/resources' | ||
11 | import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base' | ||
12 | import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node' | ||
13 | import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions' | ||
14 | import { logger } from '@server/helpers/logger' | ||
15 | import { CONFIG } from '@server/initializers/config' | ||
16 | |||
17 | function registerOpentelemetryTracing () { | ||
18 | if (CONFIG.OPEN_TELEMETRY.TRACING.ENABLED !== true) return | ||
19 | |||
20 | logger.info('Registering Open Telemetry tracing') | ||
21 | |||
22 | const customLogger = (level: string) => { | ||
23 | return (message: string, ...args: unknown[]) => { | ||
24 | let fullMessage = message | ||
25 | |||
26 | for (const arg of args) { | ||
27 | if (typeof arg === 'string') fullMessage += arg | ||
28 | else break | ||
29 | } | ||
30 | |||
31 | logger[level](fullMessage) | ||
32 | } | ||
33 | } | ||
34 | |||
35 | diag.setLogger({ | ||
36 | error: customLogger('error'), | ||
37 | warn: customLogger('warn'), | ||
38 | info: customLogger('info'), | ||
39 | debug: customLogger('debug'), | ||
40 | verbose: customLogger('verbose') | ||
41 | }, DiagLogLevel.INFO) | ||
42 | |||
43 | const tracerProvider = new NodeTracerProvider({ | ||
44 | resource: new Resource({ | ||
45 | [SemanticResourceAttributes.SERVICE_NAME]: 'peertube' | ||
46 | }) | ||
47 | }) | ||
48 | |||
49 | registerInstrumentations({ | ||
50 | tracerProvider: tracerProvider, | ||
51 | instrumentations: [ | ||
52 | new PgInstrumentation({ | ||
53 | enhancedDatabaseReporting: true | ||
54 | }), | ||
55 | new DnsInstrumentation(), | ||
56 | new HttpInstrumentation(), | ||
57 | new ExpressInstrumentation(), | ||
58 | new RedisInstrumentation({ | ||
59 | dbStatementSerializer: function (cmdName, cmdArgs) { | ||
60 | return [ cmdName, ...cmdArgs ].join(' ') | ||
61 | } | ||
62 | }), | ||
63 | new FsInstrumentation() | ||
64 | ] | ||
65 | }) | ||
66 | |||
67 | tracerProvider.addSpanProcessor( | ||
68 | new BatchSpanProcessor( | ||
69 | new JaegerExporter({ endpoint: CONFIG.OPEN_TELEMETRY.TRACING.JAEGER_EXPORTER.ENDPOINT }) | ||
70 | ) | ||
71 | ) | ||
72 | |||
73 | tracerProvider.register() | ||
74 | } | ||
75 | |||
76 | const tracer = trace.getTracer('peertube') | ||
77 | |||
78 | export { | ||
79 | registerOpentelemetryTracing, | ||
80 | tracer | ||
81 | } | ||
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index e5f8b5fa2..4f711b2fa 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -24,7 +24,6 @@ import { | |||
24 | Table, | 24 | Table, |
25 | UpdatedAt | 25 | UpdatedAt |
26 | } from 'sequelize-typescript' | 26 | } from 'sequelize-typescript' |
27 | import { buildNSFWFilter } from '@server/helpers/express-utils' | ||
28 | import { getPrivaciesForFederation, isPrivacyForFederation, isStateForFederation } from '@server/helpers/video' | 27 | import { getPrivaciesForFederation, isPrivacyForFederation, isStateForFederation } from '@server/helpers/video' |
29 | import { LiveManager } from '@server/lib/live/live-manager' | 28 | import { LiveManager } from '@server/lib/live/live-manager' |
30 | import { removeHLSObjectStorage, removeWebTorrentObjectStorage } from '@server/lib/object-storage' | 29 | import { removeHLSObjectStorage, removeWebTorrentObjectStorage } from '@server/lib/object-storage' |
@@ -134,9 +133,9 @@ import { VideoJobInfoModel } from './video-job-info' | |||
134 | import { VideoLiveModel } from './video-live' | 133 | import { VideoLiveModel } from './video-live' |
135 | import { VideoPlaylistElementModel } from './video-playlist-element' | 134 | import { VideoPlaylistElementModel } from './video-playlist-element' |
136 | import { VideoShareModel } from './video-share' | 135 | import { VideoShareModel } from './video-share' |
136 | import { VideoSourceModel } from './video-source' | ||
137 | import { VideoStreamingPlaylistModel } from './video-streaming-playlist' | 137 | import { VideoStreamingPlaylistModel } from './video-streaming-playlist' |
138 | import { VideoTagModel } from './video-tag' | 138 | import { VideoTagModel } from './video-tag' |
139 | import { VideoSourceModel } from './video-source' | ||
140 | 139 | ||
141 | export enum ScopeNames { | 140 | export enum ScopeNames { |
142 | FOR_API = 'FOR_API', | 141 | FOR_API = 'FOR_API', |
@@ -1370,11 +1369,7 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> { | |||
1370 | } | 1369 | } |
1371 | 1370 | ||
1372 | static async getStats () { | 1371 | static async getStats () { |
1373 | const totalLocalVideos = await VideoModel.count({ | 1372 | const serverActor = await getServerActor() |
1374 | where: { | ||
1375 | remote: false | ||
1376 | } | ||
1377 | }) | ||
1378 | 1373 | ||
1379 | let totalLocalVideoViews = await VideoModel.sum('views', { | 1374 | let totalLocalVideoViews = await VideoModel.sum('views', { |
1380 | where: { | 1375 | where: { |
@@ -1385,19 +1380,26 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> { | |||
1385 | // Sequelize could return null... | 1380 | // Sequelize could return null... |
1386 | if (!totalLocalVideoViews) totalLocalVideoViews = 0 | 1381 | if (!totalLocalVideoViews) totalLocalVideoViews = 0 |
1387 | 1382 | ||
1388 | const serverActor = await getServerActor() | 1383 | const baseOptions = { |
1389 | |||
1390 | const { total: totalVideos } = await VideoModel.listForApi({ | ||
1391 | start: 0, | 1384 | start: 0, |
1392 | count: 0, | 1385 | count: 0, |
1393 | sort: '-publishedAt', | 1386 | sort: '-publishedAt', |
1394 | nsfw: buildNSFWFilter(), | 1387 | nsfw: null, |
1388 | isLocal: true, | ||
1395 | displayOnlyForFollower: { | 1389 | displayOnlyForFollower: { |
1396 | actorId: serverActor.id, | 1390 | actorId: serverActor.id, |
1397 | orLocalVideos: true | 1391 | orLocalVideos: true |
1398 | } | 1392 | } |
1393 | } | ||
1394 | |||
1395 | const { total: totalLocalVideos } = await VideoModel.listForApi({ | ||
1396 | ...baseOptions, | ||
1397 | |||
1398 | isLocal: true | ||
1399 | }) | 1399 | }) |
1400 | 1400 | ||
1401 | const { total: totalVideos } = await VideoModel.listForApi(baseOptions) | ||
1402 | |||
1401 | return { | 1403 | return { |
1402 | totalLocalVideos, | 1404 | totalLocalVideos, |
1403 | totalLocalVideoViews, | 1405 | totalLocalVideoViews, |
diff --git a/server/tests/api/server/index.ts b/server/tests/api/server/index.ts index 45be107ce..78522c246 100644 --- a/server/tests/api/server/index.ts +++ b/server/tests/api/server/index.ts | |||
@@ -17,5 +17,6 @@ import './slow-follows' | |||
17 | import './stats' | 17 | import './stats' |
18 | import './tracker' | 18 | import './tracker' |
19 | import './no-client' | 19 | import './no-client' |
20 | import './open-telemetry' | ||
20 | import './plugins' | 21 | import './plugins' |
21 | import './proxy' | 22 | import './proxy' |
diff --git a/server/tests/api/server/no-client.ts b/server/tests/api/server/no-client.ts index 913907788..193f6c987 100644 --- a/server/tests/api/server/no-client.ts +++ b/server/tests/api/server/no-client.ts | |||
@@ -1,7 +1,6 @@ | |||
1 | import 'mocha' | ||
2 | import request from 'supertest' | 1 | import request from 'supertest' |
3 | import { cleanupTests, createSingleServer, PeerTubeServer } from '@shared/server-commands' | ||
4 | import { HttpStatusCode } from '@shared/models' | 2 | import { HttpStatusCode } from '@shared/models' |
3 | import { cleanupTests, createSingleServer, PeerTubeServer } from '@shared/server-commands' | ||
5 | 4 | ||
6 | describe('Start and stop server without web client routes', function () { | 5 | describe('Start and stop server without web client routes', function () { |
7 | let server: PeerTubeServer | 6 | let server: PeerTubeServer |
diff --git a/server/tests/api/server/open-telemetry.ts b/server/tests/api/server/open-telemetry.ts new file mode 100644 index 000000000..20909429f --- /dev/null +++ b/server/tests/api/server/open-telemetry.ts | |||
@@ -0,0 +1,95 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import { expect } from 'chai' | ||
4 | import { expectLogContain, expectLogDoesNotContain, MockHTTP } from '@server/tests/shared' | ||
5 | import { HttpStatusCode, VideoPrivacy } from '@shared/models' | ||
6 | import { cleanupTests, createSingleServer, makeRawRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' | ||
7 | |||
8 | describe('Open Telemetry', function () { | ||
9 | let server: PeerTubeServer | ||
10 | |||
11 | describe('Metrics', function () { | ||
12 | const metricsUrl = 'http://localhost:9091/metrics' | ||
13 | |||
14 | it('Should not enable open telemetry metrics', async function () { | ||
15 | server = await createSingleServer(1) | ||
16 | |||
17 | let hasError = false | ||
18 | try { | ||
19 | await makeRawRequest(metricsUrl, HttpStatusCode.NOT_FOUND_404) | ||
20 | } catch (err) { | ||
21 | hasError = err.message.includes('ECONNREFUSED') | ||
22 | } | ||
23 | |||
24 | expect(hasError).to.be.true | ||
25 | |||
26 | await server.kill() | ||
27 | }) | ||
28 | |||
29 | it('Should enable open telemetry metrics', async function () { | ||
30 | server = await createSingleServer(1, { | ||
31 | open_telemetry: { | ||
32 | metrics: { | ||
33 | enabled: true | ||
34 | } | ||
35 | } | ||
36 | }) | ||
37 | |||
38 | const res = await makeRawRequest(metricsUrl, HttpStatusCode.OK_200) | ||
39 | expect(res.text).to.contain('peertube_job_queue_total') | ||
40 | |||
41 | await server.kill() | ||
42 | }) | ||
43 | }) | ||
44 | |||
45 | describe('Tracing', function () { | ||
46 | let mockHTTP: MockHTTP | ||
47 | let mockPort: number | ||
48 | |||
49 | before(async function () { | ||
50 | mockHTTP = new MockHTTP() | ||
51 | mockPort = await mockHTTP.initialize() | ||
52 | }) | ||
53 | |||
54 | it('Should enable open telemetry tracing', async function () { | ||
55 | server = await createSingleServer(1) | ||
56 | |||
57 | await expectLogDoesNotContain(server, 'Registering Open Telemetry tracing') | ||
58 | |||
59 | await server.kill() | ||
60 | }) | ||
61 | |||
62 | it('Should enable open telemetry metrics', async function () { | ||
63 | server = await createSingleServer(1, { | ||
64 | open_telemetry: { | ||
65 | tracing: { | ||
66 | enabled: true, | ||
67 | jaeger_exporter: { | ||
68 | endpoint: 'http://localhost:' + mockPort | ||
69 | } | ||
70 | } | ||
71 | } | ||
72 | }) | ||
73 | |||
74 | await expectLogContain(server, 'Registering Open Telemetry tracing') | ||
75 | }) | ||
76 | |||
77 | it('Should upload a video and correctly works', async function () { | ||
78 | await setAccessTokensToServers([ server ]) | ||
79 | |||
80 | const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PUBLIC }) | ||
81 | |||
82 | const video = await server.videos.get({ id: uuid }) | ||
83 | |||
84 | expect(video.name).to.equal('video') | ||
85 | }) | ||
86 | |||
87 | after(async function () { | ||
88 | await mockHTTP.terminate() | ||
89 | }) | ||
90 | }) | ||
91 | |||
92 | after(async function () { | ||
93 | await cleanupTests([ server ]) | ||
94 | }) | ||
95 | }) | ||
diff --git a/server/tests/shared/checks.ts b/server/tests/shared/checks.ts index 33b917f31..55ebc6c3e 100644 --- a/server/tests/shared/checks.ts +++ b/server/tests/shared/checks.ts | |||
@@ -29,6 +29,12 @@ async function expectLogDoesNotContain (server: PeerTubeServer, str: string) { | |||
29 | expect(content.toString()).to.not.contain(str) | 29 | expect(content.toString()).to.not.contain(str) |
30 | } | 30 | } |
31 | 31 | ||
32 | async function expectLogContain (server: PeerTubeServer, str: string) { | ||
33 | const content = await server.servers.getLogContent() | ||
34 | |||
35 | expect(content.toString()).to.contain(str) | ||
36 | } | ||
37 | |||
32 | async function testImage (url: string, imageName: string, imageHTTPPath: string, extension = '.jpg') { | 38 | async function testImage (url: string, imageName: string, imageHTTPPath: string, extension = '.jpg') { |
33 | const res = await makeGetRequest({ | 39 | const res = await makeGetRequest({ |
34 | url, | 40 | url, |
@@ -99,5 +105,6 @@ export { | |||
99 | expectNotStartWith, | 105 | expectNotStartWith, |
100 | checkBadStartPagination, | 106 | checkBadStartPagination, |
101 | checkBadCountPagination, | 107 | checkBadCountPagination, |
102 | checkBadSortPagination | 108 | checkBadSortPagination, |
109 | expectLogContain | ||
103 | } | 110 | } |
diff --git a/server/tests/shared/mock-servers/index.ts b/server/tests/shared/mock-servers/index.ts index abf4a8203..1fa983116 100644 --- a/server/tests/shared/mock-servers/index.ts +++ b/server/tests/shared/mock-servers/index.ts | |||
@@ -1,5 +1,6 @@ | |||
1 | export * from './mock-429' | 1 | export * from './mock-429' |
2 | export * from './mock-email' | 2 | export * from './mock-email' |
3 | export * from './mock-http' | ||
3 | export * from './mock-instances-index' | 4 | export * from './mock-instances-index' |
4 | export * from './mock-joinpeertube-versions' | 5 | export * from './mock-joinpeertube-versions' |
5 | export * from './mock-object-storage' | 6 | export * from './mock-object-storage' |
diff --git a/server/tests/shared/mock-servers/mock-http.ts b/server/tests/shared/mock-servers/mock-http.ts new file mode 100644 index 000000000..b7a019e07 --- /dev/null +++ b/server/tests/shared/mock-servers/mock-http.ts | |||
@@ -0,0 +1,23 @@ | |||
1 | import express from 'express' | ||
2 | import { Server } from 'http' | ||
3 | import { getPort, randomListen, terminateServer } from './shared' | ||
4 | |||
5 | export class MockHTTP { | ||
6 | private server: Server | ||
7 | |||
8 | async initialize () { | ||
9 | const app = express() | ||
10 | |||
11 | app.get('/*', (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
12 | return res.sendStatus(200) | ||
13 | }) | ||
14 | |||
15 | this.server = await randomListen(app) | ||
16 | |||
17 | return getPort(this.server) | ||
18 | } | ||
19 | |||
20 | terminate () { | ||
21 | return terminateServer(this.server) | ||
22 | } | ||
23 | } | ||
diff --git a/server/types/express.d.ts b/server/types/express.d.ts index 27e532c31..8f8c65102 100644 --- a/server/types/express.d.ts +++ b/server/types/express.d.ts | |||
@@ -103,6 +103,8 @@ declare module 'express' { | |||
103 | }) => void | 103 | }) => void |
104 | 104 | ||
105 | locals: { | 105 | locals: { |
106 | requestStart: number | ||
107 | |||
106 | apicache: { | 108 | apicache: { |
107 | content: string | Buffer | 109 | content: string | Buffer |
108 | write: Writable['write'] | 110 | write: Writable['write'] |
diff --git a/shared/models/server/server-stats.model.ts b/shared/models/server/server-stats.model.ts index b1dcf2065..82f5a737f 100644 --- a/shared/models/server/server-stats.model.ts +++ b/shared/models/server/server-stats.model.ts | |||
@@ -1,5 +1,10 @@ | |||
1 | import { ActivityType } from '../activitypub' | ||
1 | import { VideoRedundancyStrategyWithManual } from '../redundancy' | 2 | import { VideoRedundancyStrategyWithManual } from '../redundancy' |
2 | export interface ServerStats { | 3 | |
4 | type ActivityPubMessagesSuccess = Record<`totalActivityPub${ActivityType}MessagesSuccesses`, number> | ||
5 | type ActivityPubMessagesErrors = Record<`totalActivityPub${ActivityType}MessagesErrors`, number> | ||
6 | |||
7 | export interface ServerStats extends ActivityPubMessagesSuccess, ActivityPubMessagesErrors { | ||
3 | totalUsers: number | 8 | totalUsers: number |
4 | totalDailyActiveUsers: number | 9 | totalDailyActiveUsers: number |
5 | totalWeeklyActiveUsers: number | 10 | totalWeeklyActiveUsers: number |
@@ -29,32 +34,6 @@ export interface ServerStats { | |||
29 | totalActivityPubMessagesSuccesses: number | 34 | totalActivityPubMessagesSuccesses: number |
30 | totalActivityPubMessagesErrors: number | 35 | totalActivityPubMessagesErrors: number |
31 | 36 | ||
32 | totalActivityPubCreateMessagesSuccesses: number | ||
33 | totalActivityPubUpdateMessagesSuccesses: number | ||
34 | totalActivityPubDeleteMessagesSuccesses: number | ||
35 | totalActivityPubFollowMessagesSuccesses: number | ||
36 | totalActivityPubAcceptMessagesSuccesses: number | ||
37 | totalActivityPubRejectMessagesSuccesses: number | ||
38 | totalActivityPubAnnounceMessagesSuccesses: number | ||
39 | totalActivityPubUndoMessagesSuccesses: number | ||
40 | totalActivityPubLikeMessagesSuccesses: number | ||
41 | totalActivityPubDislikeMessagesSuccesses: number | ||
42 | totalActivityPubFlagMessagesSuccesses: number | ||
43 | totalActivityPubViewMessagesSuccesses: number | ||
44 | |||
45 | totalActivityPubCreateMessagesErrors: number | ||
46 | totalActivityPubUpdateMessagesErrors: number | ||
47 | totalActivityPubDeleteMessagesErrors: number | ||
48 | totalActivityPubFollowMessagesErrors: number | ||
49 | totalActivityPubAcceptMessagesErrors: number | ||
50 | totalActivityPubRejectMessagesErrors: number | ||
51 | totalActivityPubAnnounceMessagesErrors: number | ||
52 | totalActivityPubUndoMessagesErrors: number | ||
53 | totalActivityPubLikeMessagesErrors: number | ||
54 | totalActivityPubDislikeMessagesErrors: number | ||
55 | totalActivityPubFlagMessagesErrors: number | ||
56 | totalActivityPubViewMessagesErrors: number | ||
57 | |||
58 | activityPubMessagesProcessedPerSecond: number | 37 | activityPubMessagesProcessedPerSecond: number |
59 | totalActivityPubMessagesWaiting: number | 38 | totalActivityPubMessagesWaiting: number |
60 | } | 39 | } |
@@ -1606,6 +1606,173 @@ | |||
1606 | "@nodelib/fs.scandir" "2.1.5" | 1606 | "@nodelib/fs.scandir" "2.1.5" |
1607 | fastq "^1.6.0" | 1607 | fastq "^1.6.0" |
1608 | 1608 | ||
1609 | "@opentelemetry/api-metrics@0.29.2", "@opentelemetry/api-metrics@^0.29.2": | ||
1610 | version "0.29.2" | ||
1611 | resolved "https://registry.yarnpkg.com/@opentelemetry/api-metrics/-/api-metrics-0.29.2.tgz#daa823e0965754222b49a6ae6133df8b39ff8fd2" | ||
1612 | integrity sha512-yRdF5beqKuEdsPNoO7ijWCQ9HcyN0Tlgicf8RS6gzGOI54d6Hj7yKquJ6+X9XV+CSRbRWJYb+lOsXyso7uyX2g== | ||
1613 | dependencies: | ||
1614 | "@opentelemetry/api" "^1.0.0" | ||
1615 | |||
1616 | "@opentelemetry/api@^1.0.0", "@opentelemetry/api@^1.1.0": | ||
1617 | version "1.1.0" | ||
1618 | resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.1.0.tgz#563539048255bbe1a5f4f586a4a10a1bb737f44a" | ||
1619 | integrity sha512-hf+3bwuBwtXsugA2ULBc95qxrOqP2pOekLz34BJhcAKawt94vfeNyUKpYc0lZQ/3sCP6LqRa7UAdHA7i5UODzQ== | ||
1620 | |||
1621 | "@opentelemetry/context-async-hooks@1.3.1": | ||
1622 | version "1.3.1" | ||
1623 | resolved "https://registry.yarnpkg.com/@opentelemetry/context-async-hooks/-/context-async-hooks-1.3.1.tgz#6b5288b535178fb8e3053c00c30eb38d3fdff60b" | ||
1624 | integrity sha512-NKUY3SGiEEIOD3EpB8erpEF4K1iyXkWald1vJMaa973+EPTASNSXvzf8hZa7nhnUVxYbxtTJqbSRsZFfbZpw4g== | ||
1625 | |||
1626 | "@opentelemetry/core@1.3.1", "@opentelemetry/core@^1.0.0": | ||
1627 | version "1.3.1" | ||
1628 | resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-1.3.1.tgz#6eef5c5efca9a4cd7daa0cd4c7ff28ca2317c8d7" | ||
1629 | integrity sha512-k7lOC86N7WIyUZsUuSKZfFIrUtINtlauMGQsC1r7jNmcr0vVJGqK1ROBvt7WWMxLbpMnt1q2pXJO8tKu0b9auA== | ||
1630 | dependencies: | ||
1631 | "@opentelemetry/semantic-conventions" "1.3.1" | ||
1632 | |||
1633 | "@opentelemetry/exporter-jaeger@^1.3.1": | ||
1634 | version "1.3.1" | ||
1635 | resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-jaeger/-/exporter-jaeger-1.3.1.tgz#00070e54abea51d5001acfaeb9fcfd537bf0d1d5" | ||
1636 | integrity sha512-uJ9811zn5TTdazyTNc4xmcDnKC8H63VRGp23ujGTxBOCFUnFzfI/kUGUJ8/O7Xok9Ulop7wuuBW3onL1WedfjA== | ||
1637 | dependencies: | ||
1638 | "@opentelemetry/core" "1.3.1" | ||
1639 | "@opentelemetry/sdk-trace-base" "1.3.1" | ||
1640 | "@opentelemetry/semantic-conventions" "1.3.1" | ||
1641 | jaeger-client "^3.15.0" | ||
1642 | |||
1643 | "@opentelemetry/exporter-prometheus@~0.29.2": | ||
1644 | version "0.29.2" | ||
1645 | resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-prometheus/-/exporter-prometheus-0.29.2.tgz#70ca7fb37655ca57a580387607d5465b47e27ac3" | ||
1646 | integrity sha512-E5sRfUM4rzbvjxdpL1H6YRtjr8wY8+/2R4NjfxPEwrENLeeQk87V1E+YFLqAS7TfFLW7Zr4lmmamunwn5THvQA== | ||
1647 | dependencies: | ||
1648 | "@opentelemetry/api-metrics" "0.29.2" | ||
1649 | "@opentelemetry/core" "1.3.1" | ||
1650 | "@opentelemetry/sdk-metrics-base" "0.29.2" | ||
1651 | |||
1652 | "@opentelemetry/instrumentation-dns@^0.29.0": | ||
1653 | version "0.29.0" | ||
1654 | resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-dns/-/instrumentation-dns-0.29.0.tgz#efd21eb9d8938de97e225b52f8a432d6072b4096" | ||
1655 | integrity sha512-3WTC4m6JKviaABiR3a+56WUMvrUp9WW9EYC0+LRpqm7RK/1a5bYq2Cozc2SlFYX9ZfWKMqGS39/fU24mKQ5toA== | ||
1656 | dependencies: | ||
1657 | "@opentelemetry/instrumentation" "^0.29.2" | ||
1658 | "@opentelemetry/semantic-conventions" "^1.0.0" | ||
1659 | semver "^7.3.2" | ||
1660 | |||
1661 | "@opentelemetry/instrumentation-express@^0.30.0": | ||
1662 | version "0.30.0" | ||
1663 | resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-express/-/instrumentation-express-0.30.0.tgz#4f5f45ce47c8f1ac75741284d3e59c861ced4269" | ||
1664 | integrity sha512-OsCfM+ThAXh3wzsyHgXyA5HUoLMdLd6Asix2Jx8yxniruU/Gq8y4Cz7aLy/vXNckXHWO3fwwL5gb7K3dykTnAQ== | ||
1665 | dependencies: | ||
1666 | "@opentelemetry/core" "^1.0.0" | ||
1667 | "@opentelemetry/instrumentation" "^0.29.2" | ||
1668 | "@opentelemetry/semantic-conventions" "^1.0.0" | ||
1669 | "@types/express" "4.17.13" | ||
1670 | |||
1671 | "@opentelemetry/instrumentation-fs@^0.4.0": | ||
1672 | version "0.4.0" | ||
1673 | resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-fs/-/instrumentation-fs-0.4.0.tgz#8d689f741c8cb706fd28306f5f70dab756d2f02c" | ||
1674 | integrity sha512-AINjLsYifpBC5R0YrkS0aaWBcql5WYr+UGste6HLJlHiselA22hBE3zP2WX4y+24eIlvDFKybwlodiNrITV16Q== | ||
1675 | dependencies: | ||
1676 | "@opentelemetry/core" "^1.0.0" | ||
1677 | "@opentelemetry/instrumentation" "^0.29.2" | ||
1678 | "@opentelemetry/semantic-conventions" "^1.0.0" | ||
1679 | |||
1680 | "@opentelemetry/instrumentation-http@^0.29.2": | ||
1681 | version "0.29.2" | ||
1682 | resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-http/-/instrumentation-http-0.29.2.tgz#c4750c33929d476c2a656f457c83d2144c5dd844" | ||
1683 | integrity sha512-XIF9WCH03rp3vQjwXXVdTxlsXT2AG6LYfFKO8r2QC+w4F4KFuZa4J3VPYJ0L/a/6dWt34DA67eBh3l6Z1rMZrg== | ||
1684 | dependencies: | ||
1685 | "@opentelemetry/core" "1.3.1" | ||
1686 | "@opentelemetry/instrumentation" "0.29.2" | ||
1687 | "@opentelemetry/semantic-conventions" "1.3.1" | ||
1688 | semver "^7.3.5" | ||
1689 | |||
1690 | "@opentelemetry/instrumentation-pg@^0.30.0": | ||
1691 | version "0.30.0" | ||
1692 | resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-pg/-/instrumentation-pg-0.30.0.tgz#5941dd2817a846e7b5bc283112a9cf46728d1f44" | ||
1693 | integrity sha512-RQ3cTTJnCBE/9GagjSpaM+yzxN25MvEwOxDFes3y8c1cqrMgqxukQLm3MbcqCQ8e1g/8d18+oyiEeBUjZJ5jnw== | ||
1694 | dependencies: | ||
1695 | "@opentelemetry/instrumentation" "^0.29.2" | ||
1696 | "@opentelemetry/semantic-conventions" "^1.0.0" | ||
1697 | "@types/pg" "8.6.1" | ||
1698 | "@types/pg-pool" "2.0.3" | ||
1699 | |||
1700 | "@opentelemetry/instrumentation-redis-4@^0.31.0": | ||
1701 | version "0.31.0" | ||
1702 | resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-redis-4/-/instrumentation-redis-4-0.31.0.tgz#3db1cfc177857fc208b73565df2d54065c69a67e" | ||
1703 | integrity sha512-3DY6bkqKnVlPc2WWHelb6DnU78ryYLQFqv0lqnVsoSkr7b6hnmw1Bzuwo/5YmS4C3XuTAD4/6dZVrQJ23g8HNA== | ||
1704 | dependencies: | ||
1705 | "@opentelemetry/instrumentation" "^0.29.2" | ||
1706 | "@opentelemetry/semantic-conventions" "^1.0.0" | ||
1707 | |||
1708 | "@opentelemetry/instrumentation@0.29.2", "@opentelemetry/instrumentation@^0.29.2": | ||
1709 | version "0.29.2" | ||
1710 | resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation/-/instrumentation-0.29.2.tgz#70e6d4e1a84508f5e9d8c7c426adcd7b0dba6c95" | ||
1711 | integrity sha512-LXx5V0ONNATQFCE8C5uqnxWSm4rcXLssdLHdXjtGdxRmURqj/JO8jYefqXCD0LzsqEQ6yxOx2GZ0dgXvhBVdTw== | ||
1712 | dependencies: | ||
1713 | "@opentelemetry/api-metrics" "0.29.2" | ||
1714 | require-in-the-middle "^5.0.3" | ||
1715 | semver "^7.3.2" | ||
1716 | shimmer "^1.2.1" | ||
1717 | |||
1718 | "@opentelemetry/propagator-b3@1.3.1": | ||
1719 | version "1.3.1" | ||
1720 | resolved "https://registry.yarnpkg.com/@opentelemetry/propagator-b3/-/propagator-b3-1.3.1.tgz#39208de42afef5635e74f4bedca5961d6ce25004" | ||
1721 | integrity sha512-tEAtHsRr6l3glsmKaJiJ/7HDw/isPv+f8OBsWJqkSlfLicKes8T/1D7nEDC6jPACiEbD3f6oK1KQSpMijC9/UQ== | ||
1722 | dependencies: | ||
1723 | "@opentelemetry/core" "1.3.1" | ||
1724 | |||
1725 | "@opentelemetry/propagator-jaeger@1.3.1": | ||
1726 | version "1.3.1" | ||
1727 | resolved "https://registry.yarnpkg.com/@opentelemetry/propagator-jaeger/-/propagator-jaeger-1.3.1.tgz#ad02cf5e63f7adb6986418dac916e7b89c34df5b" | ||
1728 | integrity sha512-H6swQcjZ8aMCS5caZaEBaadfn205IqLlB3ZyY+tCWDf5YPwJgPpjw3qgYgWulHVSEzK7VQTle/mZG7u9MAe6Pw== | ||
1729 | dependencies: | ||
1730 | "@opentelemetry/core" "1.3.1" | ||
1731 | |||
1732 | "@opentelemetry/resources@1.3.1", "@opentelemetry/resources@^1.3.1": | ||
1733 | version "1.3.1" | ||
1734 | resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-1.3.1.tgz#9fd85ac4ffeefc35441404b384d5c1db8b243121" | ||
1735 | integrity sha512-X8bl3X0YjlsHWy0Iv0KUETtZuRUznX4yr1iScKCtfy8AoRfZFc2xxWKMDJ0TrqYwSapgeg4YwpmRzUKmmnrbeA== | ||
1736 | dependencies: | ||
1737 | "@opentelemetry/core" "1.3.1" | ||
1738 | "@opentelemetry/semantic-conventions" "1.3.1" | ||
1739 | |||
1740 | "@opentelemetry/sdk-metrics-base@0.29.2", "@opentelemetry/sdk-metrics-base@~0.29.2": | ||
1741 | version "0.29.2" | ||
1742 | resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-metrics-base/-/sdk-metrics-base-0.29.2.tgz#bd515455f1d90e211458dcf957f0ae937772b155" | ||
1743 | integrity sha512-7hhhZ/6YRRgAXOUTeCsbe6SIk3wZAdAHnEwGGp7aiVH5AOyioHyHInw4EHtowlD6dbLxUWURjh6k+Geht2zbxg== | ||
1744 | dependencies: | ||
1745 | "@opentelemetry/api-metrics" "0.29.2" | ||
1746 | "@opentelemetry/core" "1.3.1" | ||
1747 | "@opentelemetry/resources" "1.3.1" | ||
1748 | lodash.merge "4.6.2" | ||
1749 | |||
1750 | "@opentelemetry/sdk-trace-base@1.3.1", "@opentelemetry/sdk-trace-base@^1.3.1": | ||
1751 | version "1.3.1" | ||
1752 | resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.3.1.tgz#958083dbab928eefd17848959ac8810c787bec7f" | ||
1753 | integrity sha512-Or95QZ+9QyvAiwqj+K68z8bDDuyWF50c37w17D10GV1dWzg4Ezcectsu/GB61QcBxm3Y4br0EN5F5TpIFfFliQ== | ||
1754 | dependencies: | ||
1755 | "@opentelemetry/core" "1.3.1" | ||
1756 | "@opentelemetry/resources" "1.3.1" | ||
1757 | "@opentelemetry/semantic-conventions" "1.3.1" | ||
1758 | |||
1759 | "@opentelemetry/sdk-trace-node@^1.3.1": | ||
1760 | version "1.3.1" | ||
1761 | resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-node/-/sdk-trace-node-1.3.1.tgz#ef6598aef93b24bfaae1ddc0321d3cf00d44c304" | ||
1762 | integrity sha512-4sn/pYhaVaEI8WY0arivM77858IM5BjUKvymjJ+HmRNWBocCJKCCCY4P9cL8w8iCGGmst5yxecMyvM7OOFBnmg== | ||
1763 | dependencies: | ||
1764 | "@opentelemetry/context-async-hooks" "1.3.1" | ||
1765 | "@opentelemetry/core" "1.3.1" | ||
1766 | "@opentelemetry/propagator-b3" "1.3.1" | ||
1767 | "@opentelemetry/propagator-jaeger" "1.3.1" | ||
1768 | "@opentelemetry/sdk-trace-base" "1.3.1" | ||
1769 | semver "^7.3.5" | ||
1770 | |||
1771 | "@opentelemetry/semantic-conventions@1.3.1", "@opentelemetry/semantic-conventions@^1.0.0", "@opentelemetry/semantic-conventions@^1.3.1": | ||
1772 | version "1.3.1" | ||
1773 | resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.3.1.tgz#ba07b864a3c955f061aa30ea3ef7f4ae4449794a" | ||
1774 | integrity sha512-wU5J8rUoo32oSef/rFpOT1HIjLjAv3qIDHkw1QIhODV3OpAVHi5oVzlouozg9obUmZKtbZ0qUe/m7FP0y0yBzA== | ||
1775 | |||
1609 | "@peertube/feed@^5.0.1": | 1776 | "@peertube/feed@^5.0.1": |
1610 | version "5.0.2" | 1777 | version "5.0.2" |
1611 | resolved "https://registry.yarnpkg.com/@peertube/feed/-/feed-5.0.2.tgz#d9ae7f38f1ccc75d353a5e24ad335a982bc4df74" | 1778 | resolved "https://registry.yarnpkg.com/@peertube/feed/-/feed-5.0.2.tgz#d9ae7f38f1ccc75d353a5e24ad335a982bc4df74" |
@@ -1859,7 +2026,7 @@ | |||
1859 | "@types/qs" "*" | 2026 | "@types/qs" "*" |
1860 | "@types/range-parser" "*" | 2027 | "@types/range-parser" "*" |
1861 | 2028 | ||
1862 | "@types/express@*": | 2029 | "@types/express@*", "@types/express@4.17.13": |
1863 | version "4.17.13" | 2030 | version "4.17.13" |
1864 | resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.13.tgz#a76e2995728999bab51a33fabce1d705a3709034" | 2031 | resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.13.tgz#a76e2995728999bab51a33fabce1d705a3709034" |
1865 | integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA== | 2032 | integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA== |
@@ -2061,6 +2228,31 @@ | |||
2061 | dependencies: | 2228 | dependencies: |
2062 | "@types/node" "*" | 2229 | "@types/node" "*" |
2063 | 2230 | ||
2231 | "@types/pg-pool@2.0.3": | ||
2232 | version "2.0.3" | ||
2233 | resolved "https://registry.yarnpkg.com/@types/pg-pool/-/pg-pool-2.0.3.tgz#3eb8df2933f617f219a53091ad4080c94ba1c959" | ||
2234 | integrity sha512-fwK5WtG42Yb5RxAwxm3Cc2dJ39FlgcaNiXKvtTLAwtCn642X7dgel+w1+cLWwpSOFImR3YjsZtbkfjxbHtFAeg== | ||
2235 | dependencies: | ||
2236 | "@types/pg" "*" | ||
2237 | |||
2238 | "@types/pg@*": | ||
2239 | version "8.6.5" | ||
2240 | resolved "https://registry.yarnpkg.com/@types/pg/-/pg-8.6.5.tgz#2dce9cb468a6a5e0f1296a59aea3ac75dd27b702" | ||
2241 | integrity sha512-tOkGtAqRVkHa/PVZicq67zuujI4Oorfglsr2IbKofDwBSysnaqSx7W1mDqFqdkGE6Fbgh+PZAl0r/BWON/mozw== | ||
2242 | dependencies: | ||
2243 | "@types/node" "*" | ||
2244 | pg-protocol "*" | ||
2245 | pg-types "^2.2.0" | ||
2246 | |||
2247 | "@types/pg@8.6.1": | ||
2248 | version "8.6.1" | ||
2249 | resolved "https://registry.yarnpkg.com/@types/pg/-/pg-8.6.1.tgz#099450b8dc977e8197a44f5229cedef95c8747f9" | ||
2250 | integrity sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w== | ||
2251 | dependencies: | ||
2252 | "@types/node" "*" | ||
2253 | pg-protocol "*" | ||
2254 | pg-types "^2.2.0" | ||
2255 | |||
2064 | "@types/qs@*": | 2256 | "@types/qs@*": |
2065 | version "6.9.7" | 2257 | version "6.9.7" |
2066 | resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" | 2258 | resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" |
@@ -2441,6 +2633,11 @@ ajv@^8.6.3: | |||
2441 | require-from-string "^2.0.2" | 2633 | require-from-string "^2.0.2" |
2442 | uri-js "^4.2.2" | 2634 | uri-js "^4.2.2" |
2443 | 2635 | ||
2636 | ansi-color@^0.2.1: | ||
2637 | version "0.2.1" | ||
2638 | resolved "https://registry.yarnpkg.com/ansi-color/-/ansi-color-0.2.1.tgz#3e75c037475217544ed763a8db5709fa9ae5bf9a" | ||
2639 | integrity sha512-bF6xLaZBLpOQzgYUtYEhJx090nPSZk1BQ/q2oyBK9aMMcJHzx9uXGCjI2Y+LebsN4Jwoykr0V9whbPiogdyHoQ== | ||
2640 | |||
2444 | ansi-colors@4.1.1: | 2641 | ansi-colors@4.1.1: |
2445 | version "4.1.1" | 2642 | version "4.1.1" |
2446 | resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" | 2643 | resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" |
@@ -2977,6 +3174,16 @@ bufferutil@^4.0.3: | |||
2977 | dependencies: | 3174 | dependencies: |
2978 | node-gyp-build "^4.3.0" | 3175 | node-gyp-build "^4.3.0" |
2979 | 3176 | ||
3177 | bufrw@^1.3.0: | ||
3178 | version "1.3.0" | ||
3179 | resolved "https://registry.yarnpkg.com/bufrw/-/bufrw-1.3.0.tgz#28d6cfdaf34300376836310f5c31d57eeb40c8fa" | ||
3180 | integrity sha512-jzQnSbdJqhIltU9O5KUiTtljP9ccw2u5ix59McQy4pV2xGhVLhRZIndY8GIrgh5HjXa6+QJ9AQhOd2QWQizJFQ== | ||
3181 | dependencies: | ||
3182 | ansi-color "^0.2.1" | ||
3183 | error "^7.0.0" | ||
3184 | hexer "^1.5.0" | ||
3185 | xtend "^4.0.0" | ||
3186 | |||
2980 | bull@^4.1.0: | 3187 | bull@^4.1.0: |
2981 | version "4.8.4" | 3188 | version "4.8.4" |
2982 | resolved "https://registry.yarnpkg.com/bull/-/bull-4.8.4.tgz#c538610492050d5160dbd9180704145f135a0aa9" | 3189 | resolved "https://registry.yarnpkg.com/bull/-/bull-4.8.4.tgz#c538610492050d5160dbd9180704145f135a0aa9" |
@@ -4029,6 +4236,21 @@ error-ex@^1.3.1: | |||
4029 | dependencies: | 4236 | dependencies: |
4030 | is-arrayish "^0.2.1" | 4237 | is-arrayish "^0.2.1" |
4031 | 4238 | ||
4239 | error@7.0.2: | ||
4240 | version "7.0.2" | ||
4241 | resolved "https://registry.yarnpkg.com/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" | ||
4242 | integrity sha512-UtVv4l5MhijsYUxPJo4390gzfZvAnTHreNnDjnTZaKIiZ/SemXxAhBkYSKtWa5RtBXbLP8tMgn/n0RUa/H7jXw== | ||
4243 | dependencies: | ||
4244 | string-template "~0.2.1" | ||
4245 | xtend "~4.0.0" | ||
4246 | |||
4247 | error@^7.0.0: | ||
4248 | version "7.2.1" | ||
4249 | resolved "https://registry.yarnpkg.com/error/-/error-7.2.1.tgz#eab21a4689b5f684fc83da84a0e390de82d94894" | ||
4250 | integrity sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA== | ||
4251 | dependencies: | ||
4252 | string-template "~0.2.1" | ||
4253 | |||
4032 | es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19.2, es-abstract@^1.19.5: | 4254 | es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19.2, es-abstract@^1.19.5: |
4033 | version "1.20.1" | 4255 | version "1.20.1" |
4034 | resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.1.tgz#027292cd6ef44bd12b1913b828116f54787d1814" | 4256 | resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.1.tgz#027292cd6ef44bd12b1913b828116f54787d1814" |
@@ -5044,6 +5266,16 @@ helmet@^5.0.1: | |||
5044 | resolved "https://registry.yarnpkg.com/helmet/-/helmet-5.1.0.tgz#e98a5d4bf89ab8119c856018a3bcc82addadcd47" | 5266 | resolved "https://registry.yarnpkg.com/helmet/-/helmet-5.1.0.tgz#e98a5d4bf89ab8119c856018a3bcc82addadcd47" |
5045 | integrity sha512-klsunXs8rgNSZoaUrNeuCiWUxyc+wzucnEnFejUg3/A+CaF589k9qepLZZ1Jehnzig7YbD4hEuscGXuBY3fq+g== | 5267 | integrity sha512-klsunXs8rgNSZoaUrNeuCiWUxyc+wzucnEnFejUg3/A+CaF589k9qepLZZ1Jehnzig7YbD4hEuscGXuBY3fq+g== |
5046 | 5268 | ||
5269 | hexer@^1.5.0: | ||
5270 | version "1.5.0" | ||
5271 | resolved "https://registry.yarnpkg.com/hexer/-/hexer-1.5.0.tgz#b86ce808598e8a9d1892c571f3cedd86fc9f0653" | ||
5272 | integrity sha512-dyrPC8KzBzUJ19QTIo1gXNqIISRXQ0NwteW6OeQHRN4ZuZeHkdODfj0zHBdOlHbRY8GqbqK57C9oWSvQZizFsg== | ||
5273 | dependencies: | ||
5274 | ansi-color "^0.2.1" | ||
5275 | minimist "^1.1.0" | ||
5276 | process "^0.10.0" | ||
5277 | xtend "^4.0.0" | ||
5278 | |||
5047 | hexoid@1.0.0: | 5279 | hexoid@1.0.0: |
5048 | version "1.0.0" | 5280 | version "1.0.0" |
5049 | resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-1.0.0.tgz#ad10c6573fb907de23d9ec63a711267d9dc9bc18" | 5281 | resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-1.0.0.tgz#ad10c6573fb907de23d9ec63a711267d9dc9bc18" |
@@ -5563,6 +5795,17 @@ isstream@0.1.x: | |||
5563 | resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" | 5795 | resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" |
5564 | integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== | 5796 | integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== |
5565 | 5797 | ||
5798 | jaeger-client@^3.15.0: | ||
5799 | version "3.19.0" | ||
5800 | resolved "https://registry.yarnpkg.com/jaeger-client/-/jaeger-client-3.19.0.tgz#9b5bd818ebd24e818616ee0f5cffe1722a53ae6e" | ||
5801 | integrity sha512-M0c7cKHmdyEUtjemnJyx/y9uX16XHocL46yQvyqDlPdvAcwPDbHrIbKjQdBqtiE4apQ/9dmr+ZLJYYPGnurgpw== | ||
5802 | dependencies: | ||
5803 | node-int64 "^0.4.0" | ||
5804 | opentracing "^0.14.4" | ||
5805 | thriftrw "^3.5.0" | ||
5806 | uuid "^8.3.2" | ||
5807 | xorshift "^1.1.1" | ||
5808 | |||
5566 | jimp@^0.16.0: | 5809 | jimp@^0.16.0: |
5567 | version "0.16.1" | 5810 | version "0.16.1" |
5568 | resolved "https://registry.yarnpkg.com/jimp/-/jimp-0.16.1.tgz#192f851a30e5ca11112a3d0aa53137659a78ca7a" | 5811 | resolved "https://registry.yarnpkg.com/jimp/-/jimp-0.16.1.tgz#192f851a30e5ca11112a3d0aa53137659a78ca7a" |
@@ -5900,7 +6143,7 @@ lodash.isarguments@^3.1.0: | |||
5900 | resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" | 6143 | resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" |
5901 | integrity sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg== | 6144 | integrity sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg== |
5902 | 6145 | ||
5903 | lodash.merge@^4.6.2: | 6146 | lodash.merge@4.6.2, lodash.merge@^4.6.2: |
5904 | version "4.6.2" | 6147 | version "4.6.2" |
5905 | resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" | 6148 | resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" |
5906 | integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== | 6149 | integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== |
@@ -5929,6 +6172,11 @@ logform@^2.3.2, logform@^2.4.0: | |||
5929 | safe-stable-stringify "^2.3.1" | 6172 | safe-stable-stringify "^2.3.1" |
5930 | triple-beam "^1.3.0" | 6173 | triple-beam "^1.3.0" |
5931 | 6174 | ||
6175 | long@^2.4.0: | ||
6176 | version "2.4.0" | ||
6177 | resolved "https://registry.yarnpkg.com/long/-/long-2.4.0.tgz#9fa180bb1d9500cdc29c4156766a1995e1f4524f" | ||
6178 | integrity sha512-ijUtjmO/n2A5PaosNG9ZGDsQ3vxJg7ZW8vsY8Kp0f2yIZWhSJvjmegV7t+9RPQKxKrvj8yKGehhS+po14hPLGQ== | ||
6179 | |||
5932 | loose-envify@^1.0.0: | 6180 | loose-envify@^1.0.0: |
5933 | version "1.4.0" | 6181 | version "1.4.0" |
5934 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" | 6182 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" |
@@ -6320,6 +6568,11 @@ mocha@^10.0.0: | |||
6320 | yargs-parser "20.2.4" | 6568 | yargs-parser "20.2.4" |
6321 | yargs-unparser "2.0.0" | 6569 | yargs-unparser "2.0.0" |
6322 | 6570 | ||
6571 | module-details-from-path@^1.0.3: | ||
6572 | version "1.0.3" | ||
6573 | resolved "https://registry.yarnpkg.com/module-details-from-path/-/module-details-from-path-1.0.3.tgz#114c949673e2a8a35e9d35788527aa37b679da2b" | ||
6574 | integrity sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A== | ||
6575 | |||
6323 | moment-timezone@^0.5.34: | 6576 | moment-timezone@^0.5.34: |
6324 | version "0.5.34" | 6577 | version "0.5.34" |
6325 | resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.34.tgz#a75938f7476b88f155d3504a9343f7519d9a405c" | 6578 | resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.34.tgz#a75938f7476b88f155d3504a9343f7519d9a405c" |
@@ -6556,6 +6809,11 @@ node-gyp-build@^4.2.0, node-gyp-build@^4.2.2, node-gyp-build@^4.3.0: | |||
6556 | resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.4.0.tgz#42e99687ce87ddeaf3a10b99dc06abc11021f3f4" | 6809 | resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.4.0.tgz#42e99687ce87ddeaf3a10b99dc06abc11021f3f4" |
6557 | integrity sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ== | 6810 | integrity sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ== |
6558 | 6811 | ||
6812 | node-int64@^0.4.0: | ||
6813 | version "0.4.0" | ||
6814 | resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" | ||
6815 | integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== | ||
6816 | |||
6559 | node-media-server@^2.1.4: | 6817 | node-media-server@^2.1.4: |
6560 | version "2.3.12" | 6818 | version "2.3.12" |
6561 | resolved "https://registry.yarnpkg.com/node-media-server/-/node-media-server-2.3.12.tgz#5380a60a26545144fa1e7954f08ece6f255d28b4" | 6819 | resolved "https://registry.yarnpkg.com/node-media-server/-/node-media-server-2.3.12.tgz#5380a60a26545144fa1e7954f08ece6f255d28b4" |
@@ -6713,6 +6971,11 @@ open@7: | |||
6713 | is-docker "^2.0.0" | 6971 | is-docker "^2.0.0" |
6714 | is-wsl "^2.1.1" | 6972 | is-wsl "^2.1.1" |
6715 | 6973 | ||
6974 | opentracing@^0.14.4: | ||
6975 | version "0.14.7" | ||
6976 | resolved "https://registry.yarnpkg.com/opentracing/-/opentracing-0.14.7.tgz#25d472bd0296dc0b64d7b94cbc995219031428f5" | ||
6977 | integrity sha512-vz9iS7MJ5+Bp1URw8Khvdyw1H/hGvzHWlKQ7eRrQojSCDL1/SrWfrY9QebLw97n2deyRtzHRC3MkQfVNUCo91Q== | ||
6978 | |||
6716 | optionator@^0.9.1: | 6979 | optionator@^0.9.1: |
6717 | version "0.9.1" | 6980 | version "0.9.1" |
6718 | resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" | 6981 | resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" |
@@ -6998,12 +7261,12 @@ pg-pool@^3.5.1: | |||
6998 | resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.5.1.tgz#f499ce76f9bf5097488b3b83b19861f28e4ed905" | 7261 | resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.5.1.tgz#f499ce76f9bf5097488b3b83b19861f28e4ed905" |
6999 | integrity sha512-6iCR0wVrro6OOHFsyavV+i6KYL4lVNyYAB9RD18w66xSzN+d8b66HiwuP30Gp1SH5O9T82fckkzsRjlrhD0ioQ== | 7262 | integrity sha512-6iCR0wVrro6OOHFsyavV+i6KYL4lVNyYAB9RD18w66xSzN+d8b66HiwuP30Gp1SH5O9T82fckkzsRjlrhD0ioQ== |
7000 | 7263 | ||
7001 | pg-protocol@^1.5.0: | 7264 | pg-protocol@*, pg-protocol@^1.5.0: |
7002 | version "1.5.0" | 7265 | version "1.5.0" |
7003 | resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.5.0.tgz#b5dd452257314565e2d54ab3c132adc46565a6a0" | 7266 | resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.5.0.tgz#b5dd452257314565e2d54ab3c132adc46565a6a0" |
7004 | integrity sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ== | 7267 | integrity sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ== |
7005 | 7268 | ||
7006 | pg-types@^2.1.0: | 7269 | pg-types@^2.1.0, pg-types@^2.2.0: |
7007 | version "2.2.0" | 7270 | version "2.2.0" |
7008 | resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" | 7271 | resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" |
7009 | integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== | 7272 | integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== |
@@ -7148,6 +7411,11 @@ process-nextick-args@~2.0.0: | |||
7148 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" | 7411 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" |
7149 | integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== | 7412 | integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== |
7150 | 7413 | ||
7414 | process@^0.10.0: | ||
7415 | version "0.10.1" | ||
7416 | resolved "https://registry.yarnpkg.com/process/-/process-0.10.1.tgz#842457cc51cfed72dc775afeeafb8c6034372725" | ||
7417 | integrity sha512-dyIett8dgGIZ/TXKUzeYExt7WA6ldDzys9vTDU/cCA9L17Ypme+KzS+NjQCjpn9xsvi/shbMC+yP/BcFMBz0NA== | ||
7418 | |||
7151 | process@^0.11.10: | 7419 | process@^0.11.10: |
7152 | version "0.11.10" | 7420 | version "0.11.10" |
7153 | resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" | 7421 | resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" |
@@ -7618,6 +7886,15 @@ require-from-string@^2.0.2: | |||
7618 | resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" | 7886 | resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" |
7619 | integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== | 7887 | integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== |
7620 | 7888 | ||
7889 | require-in-the-middle@^5.0.3: | ||
7890 | version "5.1.0" | ||
7891 | resolved "https://registry.yarnpkg.com/require-in-the-middle/-/require-in-the-middle-5.1.0.tgz#b768f800377b47526d026bbf5a7f727f16eb412f" | ||
7892 | integrity sha512-M2rLKVupQfJ5lf9OvqFGIT+9iVLnTmjgbOmpil12hiSQNn5zJTKGPoIisETNjfK+09vP3rpm1zJajmErpr2sEQ== | ||
7893 | dependencies: | ||
7894 | debug "^4.1.1" | ||
7895 | module-details-from-path "^1.0.3" | ||
7896 | resolve "^1.12.0" | ||
7897 | |||
7621 | require-main-filename@^2.0.0: | 7898 | require-main-filename@^2.0.0: |
7622 | version "2.0.0" | 7899 | version "2.0.0" |
7623 | resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" | 7900 | resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" |
@@ -7647,7 +7924,7 @@ resolve-tspaths@^0.6.0: | |||
7647 | commander "9.2.0" | 7924 | commander "9.2.0" |
7648 | fast-glob "3.2.11" | 7925 | fast-glob "3.2.11" |
7649 | 7926 | ||
7650 | resolve@^1.10.1, resolve@^1.15.1, resolve@^1.18.1, resolve@^1.20.0, resolve@^1.22.0: | 7927 | resolve@^1.10.1, resolve@^1.12.0, resolve@^1.15.1, resolve@^1.18.1, resolve@^1.20.0, resolve@^1.22.0: |
7651 | version "1.22.1" | 7928 | version "1.22.1" |
7652 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" | 7929 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" |
7653 | integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== | 7930 | integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== |
@@ -7910,6 +8187,11 @@ shell-quote@^1.7.3: | |||
7910 | resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123" | 8187 | resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123" |
7911 | integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw== | 8188 | integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw== |
7912 | 8189 | ||
8190 | shimmer@^1.2.1: | ||
8191 | version "1.2.1" | ||
8192 | resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" | ||
8193 | integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== | ||
8194 | |||
7913 | short-uuid@^4.2.0: | 8195 | short-uuid@^4.2.0: |
7914 | version "4.2.0" | 8196 | version "4.2.0" |
7915 | resolved "https://registry.yarnpkg.com/short-uuid/-/short-uuid-4.2.0.tgz#3706d9e7287ac589dc5ffe324d3e34817a07540b" | 8197 | resolved "https://registry.yarnpkg.com/short-uuid/-/short-uuid-4.2.0.tgz#3706d9e7287ac589dc5ffe324d3e34817a07540b" |
@@ -8258,6 +8540,11 @@ string-argv@^0.1.1: | |||
8258 | resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.1.2.tgz#c5b7bc03fb2b11983ba3a72333dd0559e77e4738" | 8540 | resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.1.2.tgz#c5b7bc03fb2b11983ba3a72333dd0559e77e4738" |
8259 | integrity sha512-mBqPGEOMNJKXRo7z0keX0wlAhbBAjilUdPW13nN0PecVryZxdHIeM7TqbsSUA7VYuS00HGC6mojP7DlQzfa9ZA== | 8541 | integrity sha512-mBqPGEOMNJKXRo7z0keX0wlAhbBAjilUdPW13nN0PecVryZxdHIeM7TqbsSUA7VYuS00HGC6mojP7DlQzfa9ZA== |
8260 | 8542 | ||
8543 | string-template@~0.2.1: | ||
8544 | version "0.2.1" | ||
8545 | resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" | ||
8546 | integrity sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw== | ||
8547 | |||
8261 | "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: | 8548 | "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: |
8262 | version "4.2.3" | 8549 | version "4.2.3" |
8263 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" | 8550 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" |
@@ -8431,6 +8718,15 @@ thirty-two@^1.0.2: | |||
8431 | resolved "https://registry.yarnpkg.com/thirty-two/-/thirty-two-1.0.2.tgz#4ca2fffc02a51290d2744b9e3f557693ca6b627a" | 8718 | resolved "https://registry.yarnpkg.com/thirty-two/-/thirty-two-1.0.2.tgz#4ca2fffc02a51290d2744b9e3f557693ca6b627a" |
8432 | integrity sha512-OEI0IWCe+Dw46019YLl6V10Us5bi574EvlJEOcAkB29IzQ/mYD1A6RyNHLjZPiHCmuodxvgF6U+vZO1L15lxVA== | 8719 | integrity sha512-OEI0IWCe+Dw46019YLl6V10Us5bi574EvlJEOcAkB29IzQ/mYD1A6RyNHLjZPiHCmuodxvgF6U+vZO1L15lxVA== |
8433 | 8720 | ||
8721 | thriftrw@^3.5.0: | ||
8722 | version "3.12.0" | ||
8723 | resolved "https://registry.yarnpkg.com/thriftrw/-/thriftrw-3.12.0.tgz#30857847755e7f036b2e0a79d11c9f55075539d9" | ||
8724 | integrity sha512-4YZvR4DPEI41n4Opwr4jmrLGG4hndxr7387kzRFIIzxHQjarPusH4lGXrugvgb7TtPrfZVTpZCVe44/xUxowEw== | ||
8725 | dependencies: | ||
8726 | bufrw "^1.3.0" | ||
8727 | error "7.0.2" | ||
8728 | long "^2.4.0" | ||
8729 | |||
8434 | through2@^0.6.3, through2@~0.6.1: | 8730 | through2@^0.6.3, through2@~0.6.1: |
8435 | version "0.6.5" | 8731 | version "0.6.5" |
8436 | resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48" | 8732 | resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48" |
@@ -9202,7 +9498,12 @@ xmlhttprequest-ssl@~2.0.0: | |||
9202 | resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz#91360c86b914e67f44dce769180027c0da618c67" | 9498 | resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz#91360c86b914e67f44dce769180027c0da618c67" |
9203 | integrity sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A== | 9499 | integrity sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A== |
9204 | 9500 | ||
9205 | "xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@~4.0.1: | 9501 | xorshift@^1.1.1: |
9502 | version "1.2.0" | ||
9503 | resolved "https://registry.yarnpkg.com/xorshift/-/xorshift-1.2.0.tgz#30a4cdd8e9f8d09d959ed2a88c42a09c660e8148" | ||
9504 | integrity sha512-iYgNnGyeeJ4t6U11NpA/QiKy+PXn5Aa3Azg5qkwIFz1tBLllQrjjsk9yzD7IAK0naNU4JxdeDgqW9ov4u/hc4g== | ||
9505 | |||
9506 | "xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@~4.0.0, xtend@~4.0.1: | ||
9206 | version "4.0.2" | 9507 | version "4.0.2" |
9207 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" | 9508 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" |
9208 | integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== | 9509 | integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== |