#435: fetch data for BuildLists graph

This commit is contained in:
Vokhmin Alexey V 2014-10-09 01:01:03 +04:00
parent 71e7b3b37e
commit af7f9c6a15
8 changed files with 164 additions and 40 deletions

View File

@ -1,7 +1,74 @@
class StatisticsController < ApplicationController
RANGES = [
RANGE_TWENTY_FOUR_HOURS = 'twenty_four_hours',
RANGE_LAST_7_DAYS = 'last_7_days',
RANGE_LAST_30_DAYS = 'last_30_days',
RANGE_LAST_60_DAYS = 'last_60_days',
RANGE_LAST_90_DAYS = 'last_90_days',
RANGE_LAST_180_DAYS = 'last_180_days',
RANGE_LAST_YEAR = 'last_year',
RANGE_CUSTOM = 'custom',
]
before_filter :init_variables
def index
# TODO
respond_to do |format|
format.html
format.json do
scope = Statistic.for_period(@range_start, @range_end)
@build_lists = scope.build_lists(@range_start, @range_end, @unit)
end
end
end
private
def init_variables
case params[:range]
when RANGE_TWENTY_FOUR_HOURS
@range_end = Time.now.utc
@range_start = @range_end - 1.day
@unit = :hour
when RANGE_LAST_7_DAYS
@range_end = Date.today
@range_start = @range_end - 7.days
@unit = :day
when RANGE_LAST_30_DAYS
@range_end = Date.today
@range_start = @range_end - 30.days
@unit = :day
when RANGE_LAST_60_DAYS
@range_end = Date.today
@range_start = @range_end - 30.days
@unit = :day
when RANGE_LAST_90_DAYS
@range_end = Date.today
@range_start = @range_end - 90.days
@unit = :day
when RANGE_LAST_180_DAYS
@range_end = Date.today
@range_start = @range_end - 180.days
@unit = :month
when RANGE_LAST_YEAR
@range_end = Date.today
@range_start = @range_end - 1.year
@unit = :month
when RANGE_CUSTOM
@range_start = Time.parse(params[:range_start]).utc
@range_end = Time.parse(params[:range_end]).utc
diff = @range_end - @range_start
@unit =
if diff <= 24.hours
:hour
elsif diff <= 90.days
:day
else
:month
end
end
end
end

View File

@ -1,18 +1,8 @@
module StatisticsHelper
RANGES = %w(
twenty_four_hours
last_7_days
last_30_days
last_60_days
last_90_days
last_180_days
last_year
custom
)
def statistics_range_options
options_for_select(
RANGES.map { |r| [I18n.t(r, scope: 'statistics.helper.period'), r] }
StatisticsController::RANGES.map { |r| [I18n.t(r, scope: 'statistics.helper.period'), r] }
)
end

View File

@ -1,11 +1,9 @@
class Statistic < ActiveRecord::Base
# TYPES = %w()
belongs_to :user
belongs_to :project
validates :user_id,
uniqueness: { scope: [:project_id, :type, :activity_at] },
uniqueness: { scope: [:project_id, :key, :activity_at] },
presence: true
validates :email,
@ -17,7 +15,7 @@ class Statistic < ActiveRecord::Base
validates :project_name_with_owner,
presence: true
validates :type,
validates :key,
presence: true
validates :counter,
@ -30,30 +28,93 @@ class Statistic < ActiveRecord::Base
:email,
:project_id,
:project_name_with_owner,
:type,
:key,
:counter,
:activity_at
def self.now_statsd_increment(options = {})
scope :for_period, -> (start_date, end_date) { where(activity_at: (start_date..end_date)) }
def self.build_lists(range_start, range_end, unit)
items = select("SUM(counter) as count, date_trunc('#{ unit }', activity_at) as activity_at").
group("date_trunc('#{ unit }', activity_at)").order('activity_at')
build_started = items.where(key: "build_list.#{BuildList::BUILD_STARTED}")
success = items.where(key: "build_list.#{BuildList::SUCCESS}")
build_error = items.where(key: "build_list.#{BuildList::BUILD_ERROR}")
build_published = items.where(key: "build_list.#{BuildList::BUILD_PUBLISHED}")
{
build_started: prepare_collection(build_started, range_start, range_end, unit),
success: prepare_collection(success, range_start, range_end, unit),
build_error: prepare_collection(build_error, range_start, range_end, unit),
build_published: prepare_collection(build_published, range_start, range_end, unit),
}
end
def self.prepare_collection(items, range_start, range_end, unit)
format = unit == :hour ? '%F %H:00:00' : '%F'
items = items.map do |item|
{ x: item.activity_at.strftime(format), y: item.count }
end
if items.size == 0
start = range_start
while start <= range_end
items.unshift({ x: start.strftime(format), y: 0 })
start += 1.send(unit)
end
end
if items[0].try(:[], :x) != range_start.strftime(format)
items.unshift({ x: range_start.strftime(format), y: 0 })
end
if items[-1].try(:[], :x) != range_end.strftime(format)
items << { x: range_end.strftime(format), y: 0 }
end
items
end
protected
def format
@format ||= case period.unit
when 'hour'
'%F %H:00:00'
else # 'day', 'month'
'%F'
end
end
def self.now_statsd_increment(activity_at: nil, user_id: nil, project_id: nil, key: nil)
# Truncates a DateTime to the minute
activity_at = options[:activity_at].utc.change(min: 0)
user = User.find options[:user_id]
project = Project.find options[:project_id]
activity_at = activity_at.utc.change(min: 0)
user = User.find user_id
project = Project.find project_id
Statistic.create(
user: user,
user_id: user_id,
email: user.email,
project: project,
project_id: project_id,
project_name_with_owner: project.name_with_owner,
type: options[:type],
key: key,
activity_at: activity_at
)
ensure
Statistic.where(
user_id: options[:user_id],
project_id: options[:project_id],
type: options[:type],
user_id: user_id,
project_id: project_id,
key: key,
activity_at: activity_at
).update_all('counter = counter + ?', options[:counter])
).update_all('counter = counter + 1')
end
def self.fill_in
BuildList.find_each do |bl|
Statistic.now_statsd_increment({
activity_at: bl.updated_at,
key: "build_list.#{bl.status}",
project_id: bl.project_id,
user_id: bl.user_id,
})
end
end
def self.statsd_increment(options = {})

View File

@ -14,7 +14,7 @@
= image_tag 'loading-large.gif'
.no-data{ ng_hide: 'loading || statistics.build_lists' }
= t('.no_data')
%canvas#build_lists_chart ng-show='statistics.build_lists'
%canvas#build_lists_chart{ ng_show: 'statistics.build_lists' }
.span3
.panel-wrapper

View File

@ -0,0 +1 @@
json.build_lists @build_lists

View File

@ -15,6 +15,11 @@ en:
total_user_sessions: "Total user sessions"
no_data: "No data available"
build_lists:
build_started_title: "Build started"
success_title: "Build complete"
build_error_title: "Build error"
build_published_title: "Build has been published"
helper:
period:

View File

@ -5,7 +5,7 @@ class CreateStatistics < ActiveRecord::Migration
t.string :email, null: false
t.integer :project_id, null: false
t.string :project_name_with_owner, null: false
t.string :type, null: false
t.string :key, null: false
t.integer :counter, null: false, default: 0
t.datetime :activity_at, null: false
@ -15,13 +15,13 @@ class CreateStatistics < ActiveRecord::Migration
add_index :statistics, :user_id
add_index :statistics, :project_id
add_index :statistics, :type
add_index :statistics, [:user_id, :type, :activity_at]
add_index :statistics, [:project_id, :type, :activity_at]
add_index :statistics, [:type, :activity_at]
add_index :statistics, :key
add_index :statistics, [:user_id, :key, :activity_at]
add_index :statistics, [:project_id, :key, :activity_at]
add_index :statistics, [:key, :activity_at]
add_index :statistics, :activity_at
add_index :statistics, [:user_id, :project_id, :type, :activity_at], unique: true,
add_index :statistics, [:user_id, :project_id, :key, :activity_at], unique: true,
name: 'index_statistics_on_all_keys'
end

View File

@ -586,18 +586,18 @@ ActiveRecord::Schema.define(version: 20141006182907) do
t.string "email", null: false
t.integer "project_id", null: false
t.string "project_name_with_owner", null: false
t.string "type", null: false
t.string "key", null: false
t.integer "counter", default: 0, null: false
t.datetime "activity_at", null: false
t.datetime "created_at"
t.datetime "updated_at"
t.index ["activity_at"], :name => "index_statistics_on_activity_at"
t.index ["project_id", "type", "activity_at"], :name => "index_statistics_on_project_id_and_type_and_activity_at"
t.index ["key", "activity_at"], :name => "index_statistics_on_key_and_activity_at"
t.index ["key"], :name => "index_statistics_on_key"
t.index ["project_id", "key", "activity_at"], :name => "index_statistics_on_project_id_and_key_and_activity_at"
t.index ["project_id"], :name => "index_statistics_on_project_id"
t.index ["type", "activity_at"], :name => "index_statistics_on_type_and_activity_at"
t.index ["type"], :name => "index_statistics_on_type"
t.index ["user_id", "project_id", "type", "activity_at"], :name => "index_statistics_on_all_keys", :unique => true
t.index ["user_id", "type", "activity_at"], :name => "index_statistics_on_user_id_and_type_and_activity_at"
t.index ["user_id", "key", "activity_at"], :name => "index_statistics_on_user_id_and_key_and_activity_at"
t.index ["user_id", "project_id", "key", "activity_at"], :name => "index_statistics_on_all_keys", :unique => true
t.index ["user_id"], :name => "index_statistics_on_user_id"
end