Commit 558e451c authored by Roy Zwambag's avatar Roy Zwambag

Add a memory report link in the Performance Bar

The memory report was previously present for admins.
We now move the memory report to the performance bar
so that more users can use it.

Changelog: changed
parent 8c38522a
...@@ -138,6 +138,9 @@ export default { ...@@ -138,6 +138,9 @@ export default {
window.location.href, window.location.href,
); );
}, },
memoryReportPath() {
return mergeUrlParams({ performance_bar: 'memory' }, window.location.href);
},
}, },
safeHtmlConfig: { ADD_TAGS: ['gl-emoji'] }, safeHtmlConfig: { ADD_TAGS: ['gl-emoji'] },
}; };
...@@ -182,6 +185,15 @@ export default { ...@@ -182,6 +185,15 @@ export default {
s__('PerformanceBar|Download') s__('PerformanceBar|Download')
}}</a> }}</a>
</div> </div>
<div
v-if="currentRequest.details && env === 'development'"
id="peek-memory-report"
class="view"
>
<a class="gl-text-blue-200" :href="memoryReportPath()">{{
s__('PerformanceBar|Memory report')
}}</a>
</div>
<div v-if="currentRequest.details" id="peek-flamegraph" class="view"> <div v-if="currentRequest.details" id="peek-flamegraph" class="view">
<span class="gl-text-white-200">{{ s__('PerformanceBar|Flamegraph with mode:') }}</span> <span class="gl-text-white-200">{{ s__('PerformanceBar|Flamegraph with mode:') }}</span>
<a class="gl-text-blue-200" :href="flamegraphPath('wall')">{{ <a class="gl-text-blue-200" :href="flamegraphPath('wall')">{{
......
...@@ -3,4 +3,5 @@ ...@@ -3,4 +3,5 @@
Rails.application.configure do |config| Rails.application.configure do |config|
config.middleware.use(Gitlab::RequestProfiler::Middleware) config.middleware.use(Gitlab::RequestProfiler::Middleware)
config.middleware.use(Gitlab::Middleware::Speedscope) config.middleware.use(Gitlab::Middleware::Speedscope)
config.middleware.use(Gitlab::Middleware::MemoryReport)
end end
# frozen_string_literal: true
module Gitlab
module Middleware
class MemoryReport
def initialize(app)
@app = app
end
def call(env)
request = ActionDispatch::Request.new(env)
return @app.call(env) unless rendering_memory_profiler?(request)
begin
require 'memory_profiler'
report = MemoryProfiler.report do
@app.call(env)
end
report = report_to_string(report)
headers = { 'Content-Type' => 'text/plain' }
[200, headers, [report]]
rescue StandardError => e
::Gitlab::ErrorTracking.track_exception(e)
[500, { 'Content-Type' => 'text/plain' }, ["Could not generate memory report: #{e}"]]
end
end
private
def rendering_memory_profiler?(request)
Rails.env.development? && request.params['performance_bar'] == 'memory'
end
def report_to_string(report)
io = StringIO.new
report.pretty_print(io, detailed_report: true, scale_bytes: true, normalize_paths: true)
io.string
end
end
end
end
...@@ -26187,6 +26187,9 @@ msgstr "" ...@@ -26187,6 +26187,9 @@ msgstr ""
msgid "PerformanceBar|Memory" msgid "PerformanceBar|Memory"
msgstr "" msgstr ""
msgid "PerformanceBar|Memory report"
msgstr ""
msgid "PerformanceBar|Redis calls" msgid "PerformanceBar|Redis calls"
msgstr "" msgstr ""
......
# frozen_string_literal: true
require 'spec_helper'
require 'memory_profiler'
RSpec.describe Gitlab::Middleware::MemoryReport do
let(:app) { proc { |env| [200, { 'Content-Type' => 'text/plain' }, ['Hello world!']] } }
let(:middleware) { described_class.new(app) }
describe '#call' do
shared_examples 'returns original response' do
it 'returns original response' do
expect(MemoryProfiler).not_to receive(:report)
status, headers, body = middleware.call(env)
expect(status).to eq(200)
expect(headers).to eq({ 'Content-Type' => 'text/plain' })
expect(body.first).to eq('Hello world!')
end
it 'does not call the MemoryProfiler' do
expect(MemoryProfiler).not_to receive(:report)
middleware.call(env)
end
end
context 'when the Rails environment is not development' do
let(:env) { Rack::MockRequest.env_for('/') }
it_behaves_like 'returns original response'
end
context 'when the Rails environment is development' do
before do
allow(Rails.env).to receive(:development?).and_return(true)
end
context 'when memory report is not requested' do
let(:env) { Rack::MockRequest.env_for('/') }
it_behaves_like 'returns original response'
end
context 'when memory report is requested' do
let(:env) { Rack::MockRequest.env_for('/', params: { 'performance_bar' => 'memory' }) }
before do
allow(env).to receive(:[]).and_call_original
allow(app).to receive(:call).and_return(empty_memory_report)
end
let(:empty_memory_report) do
report = MemoryProfiler::Results.new
report.register_results(MemoryProfiler::StatHash.new, MemoryProfiler::StatHash.new, 1)
end
it 'returns a memory report' do
expect(MemoryProfiler).to receive(:report).and_yield
status, headers, body = middleware.call(env)
expect(status).to eq(200)
expect(headers).to eq({ 'Content-Type' => 'text/plain' })
expect(body.first).to include('Total allocated: 0 B')
end
context 'when something goes wrong with creating the report' do
before do
expect(MemoryProfiler).to receive(:report).and_raise(StandardError, 'something went terribly wrong!')
end
it 'logs the error' do
expect(::Gitlab::ErrorTracking).to receive(:track_exception)
middleware.call(env)
end
it 'returns the error' do
status, headers, body = middleware.call(env)
expect(status).to eq(500)
expect(headers).to eq({ 'Content-Type' => 'text/plain' })
expect(body.first).to include('Could not generate memory report: something went terribly wrong!')
end
end
end
end
end
end
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