import memoizee from 'memoizee' import { Meter } from '@opentelemetry/api-metrics' import { MEMOIZE_TTL } from '@server/initializers/constants' import { buildAvailableActivities } from '@server/lib/activitypub/activity' import { StatsManager } from '@server/lib/stat-manager' export class StatsObserverBuilder { private readonly getInstanceStats = memoizee(() => { return StatsManager.Instance.getStats() }, { maxAge: MEMOIZE_TTL.GET_STATS_FOR_OPEN_TELEMETRY_METRICS }) constructor (private readonly meter: Meter) { } buildObservers () { this.buildUserStatsObserver() this.buildVideoStatsObserver() this.buildCommentStatsObserver() this.buildPlaylistStatsObserver() this.buildChannelStatsObserver() this.buildInstanceFollowsStatsObserver() this.buildRedundancyStatsObserver() this.buildActivityPubStatsObserver() } private buildUserStatsObserver () { this.meter.createObservableGauge('peertube_users_total', { description: 'Total users on the instance' }).addCallback(async observableResult => { const stats = await this.getInstanceStats() observableResult.observe(stats.totalUsers) }) this.meter.createObservableGauge('peertube_active_users_total', { description: 'Total active users on the instance' }).addCallback(async observableResult => { const stats = await this.getInstanceStats() observableResult.observe(stats.totalDailyActiveUsers, { activeInterval: 'daily' }) observableResult.observe(stats.totalWeeklyActiveUsers, { activeInterval: 'weekly' }) observableResult.observe(stats.totalMonthlyActiveUsers, { activeInterval: 'monthly' }) }) } private buildChannelStatsObserver () { this.meter.createObservableGauge('peertube_channels_total', { description: 'Total channels on the instance' }).addCallback(async observableResult => { const stats = await this.getInstanceStats() observableResult.observe(stats.totalLocalVideoChannels, { channelOrigin: 'local' }) }) this.meter.createObservableGauge('peertube_active_channels_total', { description: 'Total active channels on the instance' }).addCallback(async observableResult => { const stats = await this.getInstanceStats() observableResult.observe(stats.totalLocalDailyActiveVideoChannels, { channelOrigin: 'local', activeInterval: 'daily' }) observableResult.observe(stats.totalLocalWeeklyActiveVideoChannels, { channelOrigin: 'local', activeInterval: 'weekly' }) observableResult.observe(stats.totalLocalMonthlyActiveVideoChannels, { channelOrigin: 'local', activeInterval: 'monthly' }) }) } private buildVideoStatsObserver () { this.meter.createObservableGauge('peertube_videos_total', { description: 'Total videos on the instance' }).addCallback(async observableResult => { const stats = await this.getInstanceStats() observableResult.observe(stats.totalLocalVideos, { videoOrigin: 'local' }) observableResult.observe(stats.totalVideos - stats.totalLocalVideos, { videoOrigin: 'remote' }) }) this.meter.createObservableGauge('peertube_video_views_total', { description: 'Total video views made on the instance' }).addCallback(async observableResult => { const stats = await this.getInstanceStats() observableResult.observe(stats.totalLocalVideoViews, { viewOrigin: 'local' }) }) this.meter.createObservableGauge('peertube_video_bytes_total', { description: 'Total bytes of videos' }).addCallback(async observableResult => { const stats = await this.getInstanceStats() observableResult.observe(stats.totalLocalVideoFilesSize, { videoOrigin: 'local' }) }) } private buildCommentStatsObserver () { this.meter.createObservableGauge('peertube_comments_total', { description: 'Total comments on the instance' }).addCallback(async observableResult => { const stats = await this.getInstanceStats() observableResult.observe(stats.totalLocalVideoComments, { accountOrigin: 'local' }) }) } private buildPlaylistStatsObserver () { this.meter.createObservableGauge('peertube_playlists_total', { description: 'Total playlists on the instance' }).addCallback(async observableResult => { const stats = await this.getInstanceStats() observableResult.observe(stats.totalLocalPlaylists, { playlistOrigin: 'local' }) }) } private buildInstanceFollowsStatsObserver () { this.meter.createObservableGauge('peertube_instance_followers_total', { description: 'Total followers of the instance' }).addCallback(async observableResult => { const stats = await this.getInstanceStats() observableResult.observe(stats.totalInstanceFollowers) }) this.meter.createObservableGauge('peertube_instance_following_total', { description: 'Total following of the instance' }).addCallback(async observableResult => { const stats = await this.getInstanceStats() observableResult.observe(stats.totalInstanceFollowing) }) } private buildRedundancyStatsObserver () { this.meter.createObservableGauge('peertube_redundancy_used_bytes_total', { description: 'Total redundancy used of the instance' }).addCallback(async observableResult => { const stats = await this.getInstanceStats() for (const r of stats.videosRedundancy) { observableResult.observe(r.totalUsed, { strategy: r.strategy }) } }) this.meter.createObservableGauge('peertube_redundancy_available_bytes_total', { description: 'Total redundancy available of the instance' }).addCallback(async observableResult => { const stats = await this.getInstanceStats() for (const r of stats.videosRedundancy) { observableResult.observe(r.totalSize, { strategy: r.strategy }) } }) } private buildActivityPubStatsObserver () { const availableActivities = buildAvailableActivities() this.meter.createObservableGauge('peertube_ap_inbox_success_total', { description: 'Total inbox messages processed with success' }).addCallback(async observableResult => { const stats = await this.getInstanceStats() for (const type of availableActivities) { observableResult.observe(stats[`totalActivityPub${type}MessagesSuccesses`], { activityType: type }) } }) this.meter.createObservableGauge('peertube_ap_inbox_error_total', { description: 'Total inbox messages processed with error' }).addCallback(async observableResult => { const stats = await this.getInstanceStats() for (const type of availableActivities) { observableResult.observe(stats[`totalActivityPub${type}MessagesErrors`], { activityType: type }) } }) this.meter.createObservableGauge('peertube_ap_inbox_waiting_total', { description: 'Total inbox messages waiting for being processed' }).addCallback(async observableResult => { const stats = await this.getInstanceStats() observableResult.observe(stats.totalActivityPubMessagesWaiting) }) } }