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 {
this.$sqlProfileModal = $container.find('#modal-peek-pg-queries');
this.$lineProfileLink = $container.find('.js-toggle-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.showModalOnLoad();
}
......@@ -25,6 +27,7 @@ export default class PerformanceBar {
initEventListeners() {
this.$sqlProfileLink.on('click', () => this.handleSQLProfileLink());
this.$lineProfileLink.on('click', e => this.handleLineProfileLink(e));
this.$gitalyProfileLink.on('click', () => this.handleGitalyProfileLink());
$(document).on('click', '.js-lineprof-file', PerformanceBar.toggleLineProfileFile);
}
......@@ -52,6 +55,10 @@ export default class PerformanceBar {
}
}
handleGitalyProfileLink() {
PerformanceBar.toggleModal(this.$gitalyProfileModal);
}
static toggleModal($modal) {
if ($modal.length) {
$modal.modal('toggle');
......
- local_assigns.fetch(:view)
%strong
%span{ data: { defer_to: "#{view.defer_key}-duration" } } ...
\/
%span{ data: { defer_to: "#{view.defer_key}-calls" } } ...
Gitaly
%a.js-toggle-modal-peek-gitaly
%span{ data: { defer_to: "#{view.defer_key}-duration" } }...
\/
%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
#
def self.call(storage, service, rpc, request, remote_storage: nil, timeout: nil)
start = Gitlab::Metrics::System.monotonic_time
@last_request = request.is_a?(Google::Protobuf::MessageExts) ? request.to_h : nil
enforce_gitaly_request_limits(:call)
kwargs = request_kwargs(storage, timeout, remote_storage: remote_storage)
......@@ -258,6 +260,9 @@ module Gitlab
gitaly_migrate_call_duration_seconds.observe({ gitaly_enabled: is_enabled, feature: feature }, total_time)
feature_stack.shift
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
......@@ -344,6 +349,19 @@ module Gitlab
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
path = Rails.root.join(SERVER_VERSION_FILE)
path.read.chomp
......
......@@ -10,11 +10,28 @@ module Peek
end
def results
{ duration: formatted_duration, calls: calls }
{
duration: formatted_duration,
calls: calls,
details: details
}
end
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
ms = duration * 1000
if ms >= 1000
......
......@@ -3,12 +3,12 @@
*
* - Removed the dependency on jquery.tipsy
* - 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
* - Removed the keypress, pjax:end, page:change, and turbolinks:load handlers
*/
(function($) {
var fetchRequestResults, getRequestId, peekEnabled, updatePerformanceBar;
var fetchRequestResults, getRequestId, peekEnabled, updatePerformanceBar, createTable, createTableRow;
getRequestId = function() {
return $('#peek').data('requestId');
};
......@@ -16,39 +16,61 @@
return $('#peek').length;
};
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[key]).forEach(function(label) {
var data, table, target;
data = results.data[key][label];
table = createTable(key, label, data);
target = $("[data-defer-to=" + key + "-" + label + "]");
if (label == 'queries') {
table = document.createElement('table');
if (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) {
tr = document.createElement('tr');
duration_td = document.createElement('td');
sql_td = document.createElement('td');
strong = document.createElement('strong');
if (label != 'queries' && label != 'details') { return; }
strong.append(data[i]['duration'] + 'ms');
duration_td.appendChild(strong);
tr.appendChild(duration_td);
table = document.createElement('table');
sql_td.appendChild(document.createTextNode(data[i]['sql']));
tr.appendChild(sql_td);
for (var i = 0; i < data.length; i += 1) {
table.appendChild(createTableRow(data[i]));
}
table.appendChild(tr);
}
table.className = 'table';
table.className = 'table';
$("[data-defer-to=" + key + "-" + label + "]").html(table);
} else {
$("[data-defer-to=" + key + "-" + label + "]").text(results.data[key][label]);
}
});
return table;
};
createTableRow = function(row) {
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() {
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