stat-manager.ts 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. import Bluebird from 'bluebird'
  2. import { CONFIG } from '@server/initializers/config.js'
  3. import { ActorFollowModel } from '@server/models/actor/actor-follow.js'
  4. import { VideoRedundancyModel } from '@server/models/redundancy/video-redundancy.js'
  5. import { UserModel } from '@server/models/user/user.js'
  6. import { VideoModel } from '@server/models/video/video.js'
  7. import { VideoChannelModel } from '@server/models/video/video-channel.js'
  8. import { VideoCommentModel } from '@server/models/video/video-comment.js'
  9. import { VideoFileModel } from '@server/models/video/video-file.js'
  10. import { VideoPlaylistModel } from '@server/models/video/video-playlist.js'
  11. import { ActivityType, ServerStats, VideoRedundancyStrategyWithManual } from '@peertube/peertube-models'
  12. import { UserRegistrationModel } from '@server/models/user/user-registration.js'
  13. import { AbuseModel } from '@server/models/abuse/abuse.js'
  14. import { pick } from '@peertube/peertube-core-utils'
  15. class StatsManager {
  16. private static instance: StatsManager
  17. private readonly instanceStartDate = new Date()
  18. private readonly inboxMessages = {
  19. processed: 0,
  20. errors: 0,
  21. successes: 0,
  22. waiting: 0,
  23. errorsPerType: this.buildAPPerType(),
  24. successesPerType: this.buildAPPerType()
  25. }
  26. private constructor () {}
  27. updateInboxWaiting (inboxMessagesWaiting: number) {
  28. this.inboxMessages.waiting = inboxMessagesWaiting
  29. }
  30. addInboxProcessedSuccess (type: ActivityType) {
  31. this.inboxMessages.processed++
  32. this.inboxMessages.successes++
  33. this.inboxMessages.successesPerType[type]++
  34. }
  35. addInboxProcessedError (type: ActivityType) {
  36. this.inboxMessages.processed++
  37. this.inboxMessages.errors++
  38. this.inboxMessages.errorsPerType[type]++
  39. }
  40. async getStats () {
  41. const { totalLocalVideos, totalLocalVideoViews, totalVideos } = await VideoModel.getStats()
  42. const { totalLocalVideoComments, totalVideoComments } = await VideoCommentModel.getStats()
  43. const {
  44. totalUsers,
  45. totalDailyActiveUsers,
  46. totalWeeklyActiveUsers,
  47. totalMonthlyActiveUsers,
  48. totalAdmins,
  49. totalModerators
  50. } = await UserModel.getStats()
  51. const { totalInstanceFollowers, totalInstanceFollowing } = await ActorFollowModel.getStats()
  52. const { totalLocalVideoFilesSize } = await VideoFileModel.getStats()
  53. const {
  54. totalLocalVideoChannels,
  55. totalLocalDailyActiveVideoChannels,
  56. totalLocalWeeklyActiveVideoChannels,
  57. totalLocalMonthlyActiveVideoChannels
  58. } = await VideoChannelModel.getStats()
  59. const { totalLocalPlaylists } = await VideoPlaylistModel.getStats()
  60. const videosRedundancyStats = await this.buildRedundancyStats()
  61. const data: ServerStats = {
  62. totalUsers,
  63. totalDailyActiveUsers,
  64. totalWeeklyActiveUsers,
  65. totalMonthlyActiveUsers,
  66. totalModerators: CONFIG.STATS.TOTAL_MODERATORS.ENABLED
  67. ? totalModerators
  68. : null,
  69. totalAdmins: CONFIG.STATS.TOTAL_ADMINS.ENABLED
  70. ? totalAdmins
  71. : null,
  72. totalLocalVideos,
  73. totalLocalVideoViews,
  74. totalLocalVideoComments,
  75. totalLocalVideoFilesSize,
  76. totalVideos,
  77. totalVideoComments,
  78. totalLocalVideoChannels,
  79. totalLocalDailyActiveVideoChannels,
  80. totalLocalWeeklyActiveVideoChannels,
  81. totalLocalMonthlyActiveVideoChannels,
  82. totalLocalPlaylists,
  83. totalInstanceFollowers,
  84. totalInstanceFollowing,
  85. videosRedundancy: videosRedundancyStats,
  86. ...await this.buildAbuseStats(),
  87. ...await this.buildRegistrationRequestsStats(),
  88. ...this.buildAPStats()
  89. }
  90. return data
  91. }
  92. private buildActivityPubMessagesProcessedPerSecond () {
  93. const now = new Date()
  94. const startedSeconds = (now.getTime() - this.instanceStartDate.getTime()) / 1000
  95. return this.inboxMessages.processed / startedSeconds
  96. }
  97. private buildRedundancyStats () {
  98. const strategies = CONFIG.REDUNDANCY.VIDEOS.STRATEGIES
  99. .map(r => ({
  100. strategy: r.strategy as VideoRedundancyStrategyWithManual,
  101. size: r.size
  102. }))
  103. strategies.push({ strategy: 'manual', size: null })
  104. return Bluebird.mapSeries(strategies, r => {
  105. return VideoRedundancyModel.getStats(r.strategy)
  106. .then(stats => Object.assign(stats, { strategy: r.strategy, totalSize: r.size }))
  107. })
  108. }
  109. private buildAPPerType () {
  110. return {
  111. Create: 0,
  112. Update: 0,
  113. Delete: 0,
  114. Follow: 0,
  115. Accept: 0,
  116. Reject: 0,
  117. Announce: 0,
  118. Undo: 0,
  119. Like: 0,
  120. Dislike: 0,
  121. Flag: 0,
  122. View: 0
  123. }
  124. }
  125. private buildAPStats () {
  126. return {
  127. totalActivityPubMessagesProcessed: this.inboxMessages.processed,
  128. totalActivityPubMessagesSuccesses: this.inboxMessages.successes,
  129. // Dirty, but simpler and with type checking
  130. totalActivityPubCreateMessagesSuccesses: this.inboxMessages.successesPerType.Create,
  131. totalActivityPubUpdateMessagesSuccesses: this.inboxMessages.successesPerType.Update,
  132. totalActivityPubDeleteMessagesSuccesses: this.inboxMessages.successesPerType.Delete,
  133. totalActivityPubFollowMessagesSuccesses: this.inboxMessages.successesPerType.Follow,
  134. totalActivityPubAcceptMessagesSuccesses: this.inboxMessages.successesPerType.Accept,
  135. totalActivityPubRejectMessagesSuccesses: this.inboxMessages.successesPerType.Reject,
  136. totalActivityPubAnnounceMessagesSuccesses: this.inboxMessages.successesPerType.Announce,
  137. totalActivityPubUndoMessagesSuccesses: this.inboxMessages.successesPerType.Undo,
  138. totalActivityPubLikeMessagesSuccesses: this.inboxMessages.successesPerType.Like,
  139. totalActivityPubDislikeMessagesSuccesses: this.inboxMessages.successesPerType.Dislike,
  140. totalActivityPubFlagMessagesSuccesses: this.inboxMessages.successesPerType.Flag,
  141. totalActivityPubViewMessagesSuccesses: this.inboxMessages.successesPerType.View,
  142. totalActivityPubCreateMessagesErrors: this.inboxMessages.errorsPerType.Create,
  143. totalActivityPubUpdateMessagesErrors: this.inboxMessages.errorsPerType.Update,
  144. totalActivityPubDeleteMessagesErrors: this.inboxMessages.errorsPerType.Delete,
  145. totalActivityPubFollowMessagesErrors: this.inboxMessages.errorsPerType.Follow,
  146. totalActivityPubAcceptMessagesErrors: this.inboxMessages.errorsPerType.Accept,
  147. totalActivityPubRejectMessagesErrors: this.inboxMessages.errorsPerType.Reject,
  148. totalActivityPubAnnounceMessagesErrors: this.inboxMessages.errorsPerType.Announce,
  149. totalActivityPubUndoMessagesErrors: this.inboxMessages.errorsPerType.Undo,
  150. totalActivityPubLikeMessagesErrors: this.inboxMessages.errorsPerType.Like,
  151. totalActivityPubDislikeMessagesErrors: this.inboxMessages.errorsPerType.Dislike,
  152. totalActivityPubFlagMessagesErrors: this.inboxMessages.errorsPerType.Flag,
  153. totalActivityPubViewMessagesErrors: this.inboxMessages.errorsPerType.View,
  154. totalActivityPubMessagesErrors: this.inboxMessages.errors,
  155. activityPubMessagesProcessedPerSecond: this.buildActivityPubMessagesProcessedPerSecond(),
  156. totalActivityPubMessagesWaiting: this.inboxMessages.waiting
  157. }
  158. }
  159. private async buildRegistrationRequestsStats () {
  160. if (!CONFIG.STATS.REGISTRATION_REQUESTS.ENABLED) {
  161. return {
  162. averageRegistrationRequestResponseTimeMs: null,
  163. totalRegistrationRequests: null,
  164. totalRegistrationRequestsProcessed: null
  165. }
  166. }
  167. const res = await UserRegistrationModel.getStats()
  168. return pick(res, [ 'averageRegistrationRequestResponseTimeMs', 'totalRegistrationRequests', 'totalRegistrationRequestsProcessed' ])
  169. }
  170. private async buildAbuseStats () {
  171. if (!CONFIG.STATS.ABUSES.ENABLED) {
  172. return {
  173. averageAbuseResponseTimeMs: null,
  174. totalAbuses: null,
  175. totalAbusesProcessed: null
  176. }
  177. }
  178. const res = await AbuseModel.getStats()
  179. return pick(res, [ 'averageAbuseResponseTimeMs', 'totalAbuses', 'totalAbusesProcessed' ])
  180. }
  181. static get Instance () {
  182. return this.instance || (this.instance = new this())
  183. }
  184. }
  185. // ---------------------------------------------------------------------------
  186. export {
  187. StatsManager
  188. }