Class: Gitlab::RequestProfiler::Middleware

Inherits:
Object
  • Object
show all
Defined in:
lib/gitlab/request_profiler/middleware.rb

Instance Method Summary collapse

Constructor Details

#initialize(app) ⇒ Middleware

Returns a new instance of Middleware.


9
10
11
# File 'lib/gitlab/request_profiler/middleware.rb', line 9

def initialize(app)
  @app = app
end

Instance Method Details

#call(env) ⇒ Object


13
14
15
16
17
18
19
# File 'lib/gitlab/request_profiler/middleware.rb', line 13

def call(env)
  if profile?(env)
    call_with_profiling(env)
  else
    @app.call(env)
  end
end

#call_with_call_stack_profiling(env) ⇒ Object


51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/gitlab/request_profiler/middleware.rb', line 51

def call_with_call_stack_profiling(env)
  ret = nil
  report = RubyProf::Profile.profile do
    ret = catch(:warden) do # rubocop:disable Cop/BanCatchThrow
      @app.call(env)
    end
  end

  generate_report(env, 'execution', 'html') do |file|
    printer = RubyProf::CallStackPrinter.new(report)
    printer.print(file)
  end

  handle_request_ret(ret)
end

#call_with_memory_profiling(env) ⇒ Object


67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/gitlab/request_profiler/middleware.rb', line 67

def call_with_memory_profiling(env)
  ret = nil
  report = MemoryProfiler.report do
    ret = catch(:warden) do # rubocop:disable Cop/BanCatchThrow
      @app.call(env)
    end
  end

  generate_report(env, 'memory', 'txt') do |file|
    report.pretty_print(to_file: file)
  end

  handle_request_ret(ret)
end

#call_with_profiling(env) ⇒ Object


31
32
33
34
35
36
37
38
39
40
# File 'lib/gitlab/request_profiler/middleware.rb', line 31

def call_with_profiling(env)
  case env['HTTP_X_PROFILE_MODE']
  when 'execution', nil
    call_with_call_stack_profiling(env)
  when 'memory'
    call_with_memory_profiling(env)
  else
    raise ActionController::BadRequest, invalid_profile_mode(env)
  end
end

#generate_report(env, report_type, extension) ⇒ Object


82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/gitlab/request_profiler/middleware.rb', line 82

def generate_report(env, report_type, extension)
  file_name = "#{env['PATH_INFO'].tr('/', '|')}_#{Time.current.to_i}"\
              "_#{report_type}.#{extension}"
  file_path = "#{PROFILES_DIR}/#{file_name}"

  FileUtils.mkdir_p(PROFILES_DIR)

  begin
    File.open(file_path, 'wb') do |file|
      yield(file)
    end
  rescue
    FileUtils.rm(file_path)
  end
end

#handle_request_ret(ret) ⇒ Object


98
99
100
101
102
103
104
# File 'lib/gitlab/request_profiler/middleware.rb', line 98

def handle_request_ret(ret)
  if ret.is_a?(Array)
    ret
  else
    throw(:warden, ret) # rubocop:disable Cop/BanCatchThrow
  end
end

#invalid_profile_mode(env) ⇒ Object


42
43
44
45
46
47
48
49
# File 'lib/gitlab/request_profiler/middleware.rb', line 42

def invalid_profile_mode(env)
  <<~HEREDOC
    Invalid X-Profile-Mode: #{env['HTTP_X_PROFILE_MODE']}.
    Supported profile mode request header:
      - X-Profile-Mode: execution
      - X-Profile-Mode: memory
  HEREDOC
end

#profile?(env) ⇒ Boolean

Returns:

  • (Boolean)

21
22
23
24
25
26
27
28
29
# File 'lib/gitlab/request_profiler/middleware.rb', line 21

def profile?(env)
  header_token = env['HTTP_X_PROFILE_TOKEN']
  return unless header_token.present?

  profile_token = Gitlab::RequestProfiler.profile_token
  return unless profile_token.present?

  header_token == profile_token
end