Track the amount of times views are rendered
This commit is contained in:
parent
cdaa97443e
commit
7b5fd8742e
|
@ -7,6 +7,7 @@
|
|||
%thead
|
||||
%tr
|
||||
%th= t('sherlock.time_inclusive')
|
||||
%th= t('sherlock.count')
|
||||
%th= t('sherlock.path')
|
||||
%th
|
||||
%tbody
|
||||
|
@ -15,6 +16,7 @@
|
|||
%td
|
||||
= sample.duration.round(2)
|
||||
= t('sherlock.milliseconds')
|
||||
%td= @transaction.view_counts.fetch(sample.file, 1)
|
||||
%td= sample.relative_path
|
||||
%td
|
||||
= link_to(t('sherlock.view'),
|
||||
|
|
|
@ -34,3 +34,4 @@ en:
|
|||
query_plan: Query Plan
|
||||
events: Events
|
||||
percent: '%'
|
||||
count: Count
|
||||
|
|
|
@ -2,7 +2,7 @@ module Gitlab
|
|||
module Sherlock
|
||||
class Transaction
|
||||
attr_reader :id, :type, :path, :queries, :file_samples, :started_at,
|
||||
:finished_at
|
||||
:finished_at, :view_counts
|
||||
|
||||
# type - The type of transaction (e.g. "GET", "POST", etc)
|
||||
# path - The path of the transaction (e.g. the HTTP request path)
|
||||
|
@ -15,20 +15,19 @@ module Gitlab
|
|||
@started_at = nil
|
||||
@finished_at = nil
|
||||
@thread = Thread.current
|
||||
@view_counts = Hash.new(0)
|
||||
end
|
||||
|
||||
# Runs the transaction and returns the block's return value.
|
||||
def run
|
||||
@started_at = Time.now
|
||||
|
||||
subscriber = subscribe_to_active_record
|
||||
|
||||
retval = profile_lines { yield }
|
||||
retval = with_subscriptions do
|
||||
profile_lines { yield }
|
||||
end
|
||||
|
||||
@finished_at = Time.now
|
||||
|
||||
ActiveSupport::Notifications.unsubscribe(subscriber)
|
||||
|
||||
retval
|
||||
end
|
||||
|
||||
|
@ -81,21 +80,51 @@ module Gitlab
|
|||
retval
|
||||
end
|
||||
|
||||
def subscribe_to_active_record
|
||||
ActiveSupport::Notifications.subscribe('sql.active_record') do |_, start, finish, _, data|
|
||||
next unless same_thread?
|
||||
|
||||
track_query(data[:sql].strip, data[:binds], start, finish)
|
||||
end
|
||||
end
|
||||
|
||||
def subscribe_to_action_view
|
||||
regex = /render_(template|partial)\.action_view/
|
||||
|
||||
ActiveSupport::Notifications.subscribe(regex) do |_, start, finish, _, data|
|
||||
next unless same_thread?
|
||||
|
||||
track_view(data[:identifier])
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def track_query(query, bindings, start, finish)
|
||||
@queries << Query.new_with_bindings(query, bindings, start, finish)
|
||||
end
|
||||
|
||||
def subscribe_to_active_record
|
||||
ActiveSupport::Notifications.subscribe('sql.active_record') do |_, start, finish, _, data|
|
||||
# In case somebody uses a multi-threaded server locally (e.g. Puma) we
|
||||
# _only_ want to track queries that originate from the transaction
|
||||
# thread.
|
||||
next unless Thread.current == @thread
|
||||
|
||||
track_query(data[:sql].strip, data[:binds], start, finish)
|
||||
def track_view(path)
|
||||
@view_counts[path] += 1
|
||||
end
|
||||
|
||||
def with_subscriptions
|
||||
ar_subscriber = subscribe_to_active_record
|
||||
av_subscriber = subscribe_to_action_view
|
||||
|
||||
retval = yield
|
||||
|
||||
ActiveSupport::Notifications.unsubscribe(ar_subscriber)
|
||||
ActiveSupport::Notifications.unsubscribe(av_subscriber)
|
||||
|
||||
retval
|
||||
end
|
||||
|
||||
# In case somebody uses a multi-threaded server locally (e.g. Puma) we
|
||||
# _only_ want to track notifications that originate from the transaction
|
||||
# thread.
|
||||
def same_thread?
|
||||
Thread.current == @thread
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -53,6 +53,16 @@ describe Gitlab::Sherlock::Transaction do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#view_counts' do
|
||||
it 'returns a Hash' do
|
||||
expect(transaction.view_counts).to be_an_instance_of(Hash)
|
||||
end
|
||||
|
||||
it 'sets the default value of a key to 0' do
|
||||
expect(transaction.view_counts['cats.rb']).to be_zero
|
||||
end
|
||||
end
|
||||
|
||||
describe '#run' do
|
||||
it 'runs the transaction' do
|
||||
allow(transaction).to receive(:profile_lines).and_yield
|
||||
|
@ -162,4 +172,51 @@ describe Gitlab::Sherlock::Transaction do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#subscribe_to_active_record' do
|
||||
let(:subscription) { transaction.subscribe_to_active_record }
|
||||
let(:time) { Time.now }
|
||||
let(:query_data) { { sql: 'SELECT 1', binds: [] } }
|
||||
|
||||
after do
|
||||
ActiveSupport::Notifications.unsubscribe(subscription)
|
||||
end
|
||||
|
||||
it 'tracks executed queries' do
|
||||
expect(transaction).to receive(:track_query).
|
||||
with('SELECT 1', [], time, time)
|
||||
|
||||
subscription.publish('test', time, time, nil, query_data)
|
||||
end
|
||||
|
||||
it 'only tracks queries triggered from the transaction thread' do
|
||||
expect(transaction).to_not receive(:track_query)
|
||||
|
||||
Thread.new { subscription.publish('test', time, time, nil, query_data) }.
|
||||
join
|
||||
end
|
||||
end
|
||||
|
||||
describe '#subscribe_to_action_view' do
|
||||
let(:subscription) { transaction.subscribe_to_action_view }
|
||||
let(:time) { Time.now }
|
||||
let(:view_data) { { identifier: 'foo.rb' } }
|
||||
|
||||
after do
|
||||
ActiveSupport::Notifications.unsubscribe(subscription)
|
||||
end
|
||||
|
||||
it 'tracks rendered views' do
|
||||
expect(transaction).to receive(:track_view).with('foo.rb')
|
||||
|
||||
subscription.publish('test', time, time, nil, view_data)
|
||||
end
|
||||
|
||||
it 'only tracks views rendered from the transaction thread' do
|
||||
expect(transaction).to_not receive(:track_view)
|
||||
|
||||
Thread.new { subscription.publish('test', time, time, nil, view_data) }.
|
||||
join
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue