# frozen_string_literal: true
class Admin::Metrics::Dimension::BaseDimension
+ CACHE_TTL = 5.minutes.freeze
+
def self.with_params?
false
end
+ attr_reader :loaded
+
+ alias loaded? loaded
+
def initialize(start_at, end_at, limit, params)
@start_at = start_at&.to_datetime
@end_at = end_at&.to_datetime
@limit = limit&.to_i
@params = params
+ @loaded = false
end
def key
raise NotImplementedError
end
+ def cache_key
+ ["metrics/dimension/#{key}", @start_at, @end_at, @limit, canonicalized_params].join(';')
+ end
+
def data
- raise NotImplementedError
+ load
end
def self.model_name
protected
+ def load
+ unless loaded?
+ @values = Rails.cache.fetch(cache_key, expires_in: CACHE_TTL) { perform_query }
+ @loaded = true
+ end
+
+ @values
+ end
+
+ def perform_query
+ raise NotImplementedError
+ end
+
def time_period
(@start_at..@end_at)
end
def params
- raise NotImplementedError
+ {}
+ end
+
+ def canonicalized_params
+ params.to_h.to_a.sort_by { |k, _v| k.to_s }.map { |k, v| "#{k}=#{v}" }.join(';')
end
end
'languages'
end
- def data
+ protected
+
+ def perform_query
sql = <<-SQL.squish
SELECT locale, count(*) AS value
FROM users
'servers'
end
- def data
+ protected
+
+ def perform_query
sql = <<-SQL.squish
SELECT accounts.domain, count(*) AS value
FROM statuses
'software_versions'
end
- def data
+ protected
+
+ def perform_query
[mastodon_version, ruby_version, postgresql_version, redis_version]
end
- private
-
def mastodon_version
value = Mastodon::Version.to_s
'sources'
end
- def data
+ protected
+
+ def perform_query
sql = <<-SQL.squish
SELECT oauth_applications.name, count(*) AS value
FROM users
'space_usage'
end
- def data
+ protected
+
+ def perform_query
[postgresql_size, redis_size, media_size]
end
- private
-
def postgresql_size
value = ActiveRecord::Base.connection.execute('SELECT pg_database_size(current_database())').first['pg_database_size']
'tag_languages'
end
- def data
+ protected
+
+ def perform_query
sql = <<-SQL.squish
SELECT COALESCE(statuses.language, 'und') AS language, count(*) AS value
FROM statuses
rows.map { |row| { key: row['language'], human_key: standard_locale_name(row['language']), value: row['value'].to_s } }
end
- private
-
def params
@params.permit(:id)
end
'tag_servers'
end
- def data
+ protected
+
+ def perform_query
sql = <<-SQL.squish
SELECT accounts.domain, count(*) AS value
FROM statuses
rows.map { |row| { key: row['domain'] || Rails.configuration.x.local_domain, human_key: row['domain'] || Rails.configuration.x.local_domain, value: row['value'].to_s } }
end
- private
-
def params
@params.permit(:id)
end
'active_users'
end
- def total
+ protected
+
+ def perform_total_query
activity_tracker.sum(time_period.first, time_period.last)
end
- def previous_total
+ def perform_previous_total_query
activity_tracker.sum(previous_time_period.first, previous_time_period.last)
end
- def data
+ def perform_data_query
activity_tracker.get(time_period.first, time_period.last).map { |date, value| { date: date.to_time(:utc).iso8601, value: value.to_s } }
end
- protected
-
def activity_tracker
@activity_tracker ||= ActivityTracker.new('activity:logins', :unique)
end
# frozen_string_literal: true
class Admin::Metrics::Measure::BaseMeasure
+ CACHE_TTL = 5.minutes.freeze
+
def self.with_params?
false
end
+ attr_reader :loaded
+
+ alias loaded? loaded
+
def initialize(start_at, end_at, params)
@start_at = start_at&.to_datetime
@end_at = end_at&.to_datetime
@params = params
+ @loaded = false
+ end
+
+ def cache_key
+ ["metrics/measure/#{key}", @start_at, @end_at, canonicalized_params].join(';')
end
def key
end
def total
- raise NotImplementedError
+ load[:total]
end
def previous_total
- raise NotImplementedError
+ load[:previous_total]
end
def data
- raise NotImplementedError
+ load[:data]
end
def self.model_name
protected
+ def load
+ unless loaded?
+ @values = Rails.cache.fetch(cache_key, expires_in: CACHE_TTL) { perform_queries }.with_indifferent_access
+ @loaded = true
+ end
+
+ @values
+ end
+
+ def perform_queries
+ {
+ total: perform_total_query,
+ previous_total: perform_previous_total_query,
+ data: perform_data_query,
+ }
+ end
+
+ def perform_total_query
+ raise NotImplementedError
+ end
+
+ def perform_previous_total_query
+ raise NotImplementedError
+ end
+
+ def perform_data_query
+ raise NotImplementedError
+ end
+
def time_period
(@start_at..@end_at)
end
end
def params
- raise NotImplementedError
+ {}
+ end
+
+ def canonicalized_params
+ params.to_h.to_a.sort_by { |k, _v| k.to_s }.map { |k, v| "#{k}=#{v}" }.join(';')
end
end
'interactions'
end
- def total
+ protected
+
+ def perform_total_query
activity_tracker.sum(time_period.first, time_period.last)
end
- def previous_total
+ def perform_previous_total_query
activity_tracker.sum(previous_time_period.first, previous_time_period.last)
end
- def data
+ def perform_data_query
activity_tracker.get(time_period.first, time_period.last).map { |date, value| { date: date.to_time(:utc).iso8601, value: value.to_s } }
end
- protected
-
def activity_tracker
@activity_tracker ||= ActivityTracker.new('activity:interactions', :basic)
end
'new_users'
end
- def total
+ protected
+
+ def perform_total_query
User.where(created_at: time_period).count
end
- def previous_total
+ def perform_previous_total_query
User.where(created_at: previous_time_period).count
end
- def data
+ def perform_data_query
sql = <<-SQL.squish
SELECT axis.*, (
WITH new_users AS (
'opened_reports'
end
- def total
+ protected
+
+ def perform_total_query
Report.where(created_at: time_period).count
end
- def previous_total
+ def perform_previous_total_query
Report.where(created_at: previous_time_period).count
end
- def data
+ def perform_data_query
sql = <<-SQL.squish
SELECT axis.*, (
WITH new_reports AS (
'resolved_reports'
end
- def total
+ protected
+
+ def perform_total_query
Report.resolved.where(action_taken_at: time_period).count
end
- def previous_total
+ def perform_previous_total_query
Report.resolved.where(action_taken_at: previous_time_period).count
end
- def data
+ def perform_data_query
sql = <<-SQL.squish
SELECT axis.*, (
WITH resolved_reports AS (
'tag_accounts'
end
- def total
+ protected
+
+ def perform_total_query
tag.history.aggregate(time_period).accounts
end
- def previous_total
+ def perform_previous_total_query
tag.history.aggregate(previous_time_period).accounts
end
- def data
+ def perform_data_query
time_period.map { |date| { date: date.to_time(:utc).iso8601, value: tag.history.get(date).accounts.to_s } }
end
- protected
-
def tag
@tag ||= Tag.find(params[:id])
end
'tag_servers'
end
- def total
+ protected
+
+ def perform_total_query
tag.statuses.where('statuses.id BETWEEN ? AND ?', Mastodon::Snowflake.id_at(@start_at, with_random: false), Mastodon::Snowflake.id_at(@end_at, with_random: false)).joins(:account).count('distinct accounts.domain')
end
- def previous_total
+ def perform_previous_total_query
tag.statuses.where('statuses.id BETWEEN ? AND ?', Mastodon::Snowflake.id_at(@start_at - length_of_period, with_random: false), Mastodon::Snowflake.id_at(@end_at - length_of_period, with_random: false)).joins(:account).count('distinct accounts.domain')
end
- def data
+ def perform_data_query
sql = <<-SQL.squish
SELECT axis.*, (
SELECT count(distinct accounts.domain) AS value
rows.map { |row| { date: row['day'], value: row['value'].to_s } }
end
- protected
-
def tag
@tag ||= Tag.find(params[:id])
end
'tag_uses'
end
- def total
+ protected
+
+ def perform_total_query
tag.history.aggregate(time_period).uses
end
- def previous_total
+ def perform_previous_total_query
tag.history.aggregate(previous_time_period).uses
end
- def data
+ def perform_data_query
time_period.map { |date| { date: date.to_time(:utc).iso8601, value: tag.history.get(date).uses.to_s } }
end
- protected
-
def tag
@tag ||= Tag.find(params[:id])
end
# frozen_string_literal: true
class Admin::Metrics::Retention
+ CACHE_TTL = 5.minutes.freeze
+
class Cohort < ActiveModelSerializers::Model
attributes :period, :frequency, :data
end
attributes :date, :rate, :value
end
+ attr_reader :loaded
+
+ alias loaded? loaded
+
def initialize(start_at, end_at, frequency)
@start_at = start_at&.to_date
@end_at = end_at&.to_date
@frequency = %w(day month).include?(frequency) ? frequency : 'day'
+ @loaded = false
+ end
+
+ def cache_key
+ ['metrics/retention', @start_at, @end_at, @frequency].join(';')
end
def cohorts
+ load
+ end
+
+ protected
+
+ def load
+ unless loaded?
+ @values = Rails.cache.fetch(cache_key, expires_in: CACHE_TTL) { perform_query }
+ @loaded = true
+ end
+
+ @values
+ end
+
+ def perform_query
sql = <<-SQL.squish
SELECT axis.*, (
WITH new_users AS (