Track the amount of times views are rendered
This commit is contained in:
parent
cdaa97443e
commit
7b5fd8742e
|
@ -7,6 +7,7 @@
|
||||||
%thead
|
%thead
|
||||||
%tr
|
%tr
|
||||||
%th= t('sherlock.time_inclusive')
|
%th= t('sherlock.time_inclusive')
|
||||||
|
%th= t('sherlock.count')
|
||||||
%th= t('sherlock.path')
|
%th= t('sherlock.path')
|
||||||
%th
|
%th
|
||||||
%tbody
|
%tbody
|
||||||
|
@ -15,6 +16,7 @@
|
||||||
%td
|
%td
|
||||||
= sample.duration.round(2)
|
= sample.duration.round(2)
|
||||||
= t('sherlock.milliseconds')
|
= t('sherlock.milliseconds')
|
||||||
|
%td= @transaction.view_counts.fetch(sample.file, 1)
|
||||||
%td= sample.relative_path
|
%td= sample.relative_path
|
||||||
%td
|
%td
|
||||||
= link_to(t('sherlock.view'),
|
= link_to(t('sherlock.view'),
|
||||||
|
|
|
@ -34,3 +34,4 @@ en:
|
||||||
query_plan: Query Plan
|
query_plan: Query Plan
|
||||||
events: Events
|
events: Events
|
||||||
percent: '%'
|
percent: '%'
|
||||||
|
count: Count
|
||||||
|
|
|
@ -2,7 +2,7 @@ module Gitlab
|
||||||
module Sherlock
|
module Sherlock
|
||||||
class Transaction
|
class Transaction
|
||||||
attr_reader :id, :type, :path, :queries, :file_samples, :started_at,
|
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)
|
# type - The type of transaction (e.g. "GET", "POST", etc)
|
||||||
# path - The path of the transaction (e.g. the HTTP request path)
|
# path - The path of the transaction (e.g. the HTTP request path)
|
||||||
|
@ -15,20 +15,19 @@ module Gitlab
|
||||||
@started_at = nil
|
@started_at = nil
|
||||||
@finished_at = nil
|
@finished_at = nil
|
||||||
@thread = Thread.current
|
@thread = Thread.current
|
||||||
|
@view_counts = Hash.new(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Runs the transaction and returns the block's return value.
|
# Runs the transaction and returns the block's return value.
|
||||||
def run
|
def run
|
||||||
@started_at = Time.now
|
@started_at = Time.now
|
||||||
|
|
||||||
subscriber = subscribe_to_active_record
|
retval = with_subscriptions do
|
||||||
|
profile_lines { yield }
|
||||||
retval = profile_lines { yield }
|
end
|
||||||
|
|
||||||
@finished_at = Time.now
|
@finished_at = Time.now
|
||||||
|
|
||||||
ActiveSupport::Notifications.unsubscribe(subscriber)
|
|
||||||
|
|
||||||
retval
|
retval
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -81,21 +80,51 @@ module Gitlab
|
||||||
retval
|
retval
|
||||||
end
|
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
|
private
|
||||||
|
|
||||||
def track_query(query, bindings, start, finish)
|
def track_query(query, bindings, start, finish)
|
||||||
@queries << Query.new_with_bindings(query, bindings, start, finish)
|
@queries << Query.new_with_bindings(query, bindings, start, finish)
|
||||||
end
|
end
|
||||||
|
|
||||||
def subscribe_to_active_record
|
def track_view(path)
|
||||||
ActiveSupport::Notifications.subscribe('sql.active_record') do |_, start, finish, _, data|
|
@view_counts[path] += 1
|
||||||
# In case somebody uses a multi-threaded server locally (e.g. Puma) we
|
end
|
||||||
# _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 with_subscriptions
|
||||||
end
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -53,6 +53,16 @@ describe Gitlab::Sherlock::Transaction do
|
||||||
end
|
end
|
||||||
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
|
describe '#run' do
|
||||||
it 'runs the transaction' do
|
it 'runs the transaction' do
|
||||||
allow(transaction).to receive(:profile_lines).and_yield
|
allow(transaction).to receive(:profile_lines).and_yield
|
||||||
|
@ -162,4 +172,51 @@ describe Gitlab::Sherlock::Transaction do
|
||||||
end
|
end
|
||||||
end
|
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
|
end
|
||||||
|
|
Loading…
Reference in New Issue