Commit d30576c5 authored by Sean McGivern's avatar Sean McGivern

Add Gitaly call details to the performance bar

The same as the SQL queries, show the details of Gitaly calls in the performance
bar, as a modal that can be opened in the same way.
parent 1bab4dcf
...@@ -18,6 +18,8 @@ export default class PerformanceBar { ...@@ -18,6 +18,8 @@ export default class PerformanceBar {
this.$sqlProfileModal = $container.find('#modal-peek-pg-queries'); this.$sqlProfileModal = $container.find('#modal-peek-pg-queries');
this.$lineProfileLink = $container.find('.js-toggle-modal-peek-line-profile'); this.$lineProfileLink = $container.find('.js-toggle-modal-peek-line-profile');
this.$lineProfileModal = $('#modal-peek-line-profile'); this.$lineProfileModal = $('#modal-peek-line-profile');
this.$gitalyProfileLink = $container.find('.js-toggle-modal-peek-gitaly');
this.$gitalyProfileModal = $container.find('#modal-peek-gitaly-details');
this.initEventListeners(); this.initEventListeners();
this.showModalOnLoad(); this.showModalOnLoad();
} }
...@@ -25,6 +27,7 @@ export default class PerformanceBar { ...@@ -25,6 +27,7 @@ export default class PerformanceBar {
initEventListeners() { initEventListeners() {
this.$sqlProfileLink.on('click', () => this.handleSQLProfileLink()); this.$sqlProfileLink.on('click', () => this.handleSQLProfileLink());
this.$lineProfileLink.on('click', e => this.handleLineProfileLink(e)); this.$lineProfileLink.on('click', e => this.handleLineProfileLink(e));
this.$gitalyProfileLink.on('click', () => this.handleGitalyProfileLink());
$(document).on('click', '.js-lineprof-file', PerformanceBar.toggleLineProfileFile); $(document).on('click', '.js-lineprof-file', PerformanceBar.toggleLineProfileFile);
} }
...@@ -52,6 +55,10 @@ export default class PerformanceBar { ...@@ -52,6 +55,10 @@ export default class PerformanceBar {
} }
} }
handleGitalyProfileLink() {
PerformanceBar.toggleModal(this.$gitalyProfileModal);
}
static toggleModal($modal) { static toggleModal($modal) {
if ($modal.length) { if ($modal.length) {
$modal.modal('toggle'); $modal.modal('toggle');
......
- local_assigns.fetch(:view) - local_assigns.fetch(:view)
%strong %strong
%span{ data: { defer_to: "#{view.defer_key}-duration" } } ... %a.js-toggle-modal-peek-gitaly
\/ %span{ data: { defer_to: "#{view.defer_key}-duration" } }...
%span{ data: { defer_to: "#{view.defer_key}-calls" } } ... \/
Gitaly %span{ data: { defer_to: "#{view.defer_key}-calls" } }...
#modal-peek-gitaly-details.modal{ tabindex: -1 }
.modal-dialog.modal-full
.modal-content
.modal-header
%button.close.btn.btn-link.btn-sm{ type: 'button', data: { dismiss: 'modal' } } X
%h4
Gitaly requests
.modal-body{ data: { defer_to: "#{view.defer_key}-details" } }...
Gitaly
---
title: Add Gitaly call details to performance bar
merge_request:
author:
type: added
...@@ -119,6 +119,8 @@ module Gitlab ...@@ -119,6 +119,8 @@ module Gitlab
# #
def self.call(storage, service, rpc, request, remote_storage: nil, timeout: nil) def self.call(storage, service, rpc, request, remote_storage: nil, timeout: nil)
start = Gitlab::Metrics::System.monotonic_time start = Gitlab::Metrics::System.monotonic_time
@last_request = request.is_a?(Google::Protobuf::MessageExts) ? request.to_h : nil
enforce_gitaly_request_limits(:call) enforce_gitaly_request_limits(:call)
kwargs = request_kwargs(storage, timeout, remote_storage: remote_storage) kwargs = request_kwargs(storage, timeout, remote_storage: remote_storage)
...@@ -258,6 +260,9 @@ module Gitlab ...@@ -258,6 +260,9 @@ module Gitlab
gitaly_migrate_call_duration_seconds.observe({ gitaly_enabled: is_enabled, feature: feature }, total_time) gitaly_migrate_call_duration_seconds.observe({ gitaly_enabled: is_enabled, feature: feature }, total_time)
feature_stack.shift feature_stack.shift
Thread.current[:gitaly_feature_stack] = nil if feature_stack.empty? Thread.current[:gitaly_feature_stack] = nil if feature_stack.empty?
add_call_details(feature: feature,
duration: total_time,
request: is_enabled ? @last_request : {})
end end
end end
end end
...@@ -344,6 +349,19 @@ module Gitlab ...@@ -344,6 +349,19 @@ module Gitlab
end end
end end
def self.add_call_details(details)
return unless RequestStore.active? && RequestStore.store[:peek_enabled]
RequestStore.store['gitaly_call_details'] ||= []
RequestStore.store['gitaly_call_details'] << details
end
def self.call_details
return [] unless RequestStore.active? && RequestStore.store[:peek_enabled]
RequestStore.store['gitaly_call_details'] || []
end
def self.expected_server_version def self.expected_server_version
path = Rails.root.join(SERVER_VERSION_FILE) path = Rails.root.join(SERVER_VERSION_FILE)
path.read.chomp path.read.chomp
......
...@@ -10,11 +10,28 @@ module Peek ...@@ -10,11 +10,28 @@ module Peek
end end
def results def results
{ duration: formatted_duration, calls: calls } {
duration: formatted_duration,
calls: calls,
details: details
}
end end
private private
def details
::Gitlab::GitalyClient.call_details
.sort { |a, b| b[:duration] <=> a[:duration] }
.map(&method(:format_call_details))
end
def format_call_details(call)
pretty_request = call[:request].reject { |k, v| v.blank? }.to_h.pretty_inspect
call.merge(duration: (call[:duration] * 1000).round(3),
request: pretty_request)
end
def formatted_duration def formatted_duration
ms = duration * 1000 ms = duration * 1000
if ms >= 1000 if ms >= 1000
......
...@@ -3,12 +3,12 @@ ...@@ -3,12 +3,12 @@
* *
* - Removed the dependency on jquery.tipsy * - Removed the dependency on jquery.tipsy
* - Removed the initializeTipsy and toggleBar functions * - Removed the initializeTipsy and toggleBar functions
* - Customized updatePerformanceBar to handle SQL queries report specificities * - Customized updatePerformanceBar to handle SQL query and Gitaly call lists
* - Changed /peek/results to /-/peek/results * - Changed /peek/results to /-/peek/results
* - Removed the keypress, pjax:end, page:change, and turbolinks:load handlers * - Removed the keypress, pjax:end, page:change, and turbolinks:load handlers
*/ */
(function($) { (function($) {
var fetchRequestResults, getRequestId, peekEnabled, updatePerformanceBar; var fetchRequestResults, getRequestId, peekEnabled, updatePerformanceBar, createTable, createTableRow;
getRequestId = function() { getRequestId = function() {
return $('#peek').data('requestId'); return $('#peek').data('requestId');
}; };
...@@ -16,39 +16,61 @@ ...@@ -16,39 +16,61 @@
return $('#peek').length; return $('#peek').length;
}; };
updatePerformanceBar = function(results) { updatePerformanceBar = function(results) {
var key, label, data, table, html, tr, duration_td, sql_td, strong;
Object.keys(results.data).forEach(function(key) { Object.keys(results.data).forEach(function(key) {
Object.keys(results.data[key]).forEach(function(label) { Object.keys(results.data[key]).forEach(function(label) {
var data, table, target;
data = results.data[key][label]; data = results.data[key][label];
table = createTable(key, label, data);
target = $("[data-defer-to=" + key + "-" + label + "]");
if (label == 'queries') { if (table) {
table = document.createElement('table'); target.html(table);
} else {
target.text(data);
}
});
});
return $(document).trigger('peek:render', [getRequestId(), results]);
};
createTable = function(key, label, data) {
var table;
for (var i = 0; i < data.length; i += 1) { if (label != 'queries' && label != 'details') { return; }
tr = document.createElement('tr');
duration_td = document.createElement('td');
sql_td = document.createElement('td');
strong = document.createElement('strong');
strong.append(data[i]['duration'] + 'ms'); table = document.createElement('table');
duration_td.appendChild(strong);
tr.appendChild(duration_td);
sql_td.appendChild(document.createTextNode(data[i]['sql'])); for (var i = 0; i < data.length; i += 1) {
tr.appendChild(sql_td); table.appendChild(createTableRow(data[i]));
}
table.appendChild(tr); table.className = 'table';
}
table.className = 'table'; return table;
$("[data-defer-to=" + key + "-" + label + "]").html(table); };
} else { createTableRow = function(row) {
$("[data-defer-to=" + key + "-" + label + "]").text(results.data[key][label]); var tr, duration_td, strong;
}
}); tr = document.createElement('tr');
duration_td = document.createElement('td');
strong = document.createElement('strong');
strong.append(row['duration'] + 'ms');
duration_td.appendChild(strong);
tr.appendChild(duration_td);
['sql', 'feature', 'enabled', 'request'].forEach(function(key) {
var td;
if (!row[key]) { return; }
td = document.createElement('td');
td.appendChild(document.createTextNode(row[key]));
tr.appendChild(td);
}); });
return $(document).trigger('peek:render', [getRequestId(), results]);
return tr;
}; };
fetchRequestResults = function() { fetchRequestResults = function() {
return $.ajax('/-/peek/results', { return $.ajax('/-/peek/results', {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment