提交 d30576c5 编写于 作者: S 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.
上级 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% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册