Add backtrace to Gitaly performance bar

This adds the backtrace to a table to show exactly where the Gitaly call
was made to make it easier to understand where the call originated.

This change also collapses the details in the same row to improve the
usability when there is a backtrace.
This commit is contained in:
Stan Hu 2019-04-12 22:54:32 -07:00
parent b0c0f81d54
commit fbb3fd1397
7 changed files with 68 additions and 15 deletions

View file

@ -1,9 +1,11 @@
<script>
import GlModal from '~/vue_shared/components/gl_modal.vue';
import Icon from '~/vue_shared/components/icon.vue';
export default {
components: {
GlModal,
Icon,
},
props: {
currentRequest: {
@ -57,9 +59,31 @@ export default {
<template v-if="detailsList.length">
<tr v-for="(item, index) in detailsList" :key="index">
<td>
<strong>{{ item.duration }}ms</strong>
<span>{{ item.duration }}ms</span>
</td>
<td>
<div class="js-toggle-container">
<div
v-for="(key, keyIndex) in keys"
:key="key"
class="break-word"
:class="{ 'mb-3 bold': keyIndex == 0 }"
>
{{ item[key] }}
<button
v-if="keyIndex == 0 && item.backtrace"
class="text-expander js-toggle-button"
type="button"
:aria-label="__('Toggle backtrace')"
>
<icon :size="12" name="ellipsis_h" />
</button>
</div>
<pre v-if="item.backtrace" class="backtrace-row js-toggle-content mt-2">{{
item.backtrace
}}</pre>
</div>
</td>
<td v-for="key in keys" :key="key" class="break-word">{{ item[key] }}</td>
</tr>
</template>
<template v-else>

View file

@ -79,8 +79,12 @@
table {
color: $black;
strong {
color: $black;
td {
vertical-align: top;
}
.backtrace-row {
display: none;
}
}

View file

@ -0,0 +1,5 @@
---
title: Add backtrace to Gitaly performance bar
merge_request: 27345
author:
type: other

View file

@ -165,7 +165,10 @@ module Gitlab
current_transaction_labels.merge(gitaly_service: service.to_s, rpc: rpc.to_s),
duration)
add_call_details(feature: "#{service}##{rpc}", duration: duration, request: request_hash, rpc: rpc)
if peek_enabled?
add_call_details(feature: "#{service}##{rpc}", duration: duration, request: request_hash, rpc: rpc,
backtrace: Gitlab::Profiler.clean_backtrace(caller))
end
end
def self.query_time
@ -350,15 +353,17 @@ module Gitlab
Gitlab::SafeRequestStore["gitaly_call_permitted"] = 0
end
def self.add_call_details(details)
return unless Gitlab::SafeRequestStore[:peek_enabled]
def self.peek_enabled?
Gitlab::SafeRequestStore[:peek_enabled]
end
def self.add_call_details(details)
Gitlab::SafeRequestStore['gitaly_call_details'] ||= []
Gitlab::SafeRequestStore['gitaly_call_details'] << details
end
def self.list_call_details
return [] unless Gitlab::SafeRequestStore[:peek_enabled]
return [] unless peek_enabled?
Gitlab::SafeRequestStore['gitaly_call_details'] || []
end

View file

@ -16,7 +16,11 @@ module Gitlab
ee/lib/gitlab/middleware/
lib/gitlab/performance_bar/
lib/gitlab/request_profiler/
lib/gitlab/query_limiting/
lib/gitlab/tracing/
lib/gitlab/profiler.rb
lib/gitlab/correlation_id.rb
lib/gitlab/webpack/dev_server_middleware.rb
].freeze
# Takes a URL to profile (can be a fully-qualified URL, or an absolute path)

View file

@ -9559,6 +9559,9 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
msgid "Toggle backtrace"
msgstr ""
msgid "Toggle comments for this file"
msgstr ""

View file

@ -27,8 +27,8 @@ describe('detailedMetric', () => {
describe('when the current request has details', () => {
const requestDetails = [
{ duration: '100', feature: 'find_commit', request: 'abcdef' },
{ duration: '23', feature: 'rebase_in_progress', request: '' },
{ duration: '100', feature: 'find_commit', request: 'abcdef', backtrace: ['hello', 'world'] },
{ duration: '23', feature: 'rebase_in_progress', request: '', backtrace: ['world', 'hello'] },
];
beforeEach(() => {
@ -54,9 +54,11 @@ describe('detailedMetric', () => {
});
it('adds a modal with a table of the details', () => {
vm.$el.querySelectorAll('.performance-bar-modal td strong').forEach((duration, index) => {
expect(duration.innerText).toContain(requestDetails[index].duration);
});
vm.$el
.querySelectorAll('.performance-bar-modal td:nth-child(1)')
.forEach((duration, index) => {
expect(duration.innerText).toContain(requestDetails[index].duration);
});
vm.$el
.querySelectorAll('.performance-bar-modal td:nth-child(2)')
@ -65,10 +67,16 @@ describe('detailedMetric', () => {
});
vm.$el
.querySelectorAll('.performance-bar-modal td:nth-child(3)')
.querySelectorAll('.performance-bar-modal td:nth-child(2)')
.forEach((request, index) => {
expect(request.innerText).toEqual(requestDetails[index].request);
expect(request.innerText).toContain(requestDetails[index].request);
});
expect(vm.$el.querySelector('.text-expander.js-toggle-button')).not.toBeNull();
vm.$el.querySelectorAll('.performance-bar-modal td:nth-child(2)').forEach(request => {
expect(request.innerText).toContain('world');
});
});
it('displays the metric name', () => {