Class: Gitlab::Metrics::RequestsRackMiddleware
- Inherits:
-
Object
- Object
- Gitlab::Metrics::RequestsRackMiddleware
- Defined in:
- lib/gitlab/metrics/requests_rack_middleware.rb
Constant Summary collapse
- HTTP_METHODS =
{ "delete" => %w[200 202 204 303 400 401 403 404 500 503], "get" => %w[200 204 301 302 303 304 307 400 401 403 404 410 422 429 500 503], "head" => %w[200 204 301 302 303 401 403 404 410 500], "options" => %w[200 404], "patch" => %w[200 202 204 400 403 404 409 416 500], "post" => %w[200 201 202 204 301 302 303 304 400 401 403 404 406 409 410 412 422 429 500 503], "put" => %w[200 202 204 400 401 403 404 405 406 409 410 422 500] }.freeze
- HEALTH_ENDPOINT =
%r{^/-/(liveness|readiness|health|metrics)/?$}
- FEATURE_CATEGORY_DEFAULT =
::Gitlab::FeatureCategories::FEATURE_CATEGORY_DEFAULT
- ENDPOINT_MISSING =
'unknown'
- FEATURE_CATEGORIES_TO_INITIALIZE =
These were the top 5 categories at a point in time, chosen as a reasonable default. If we initialize every category we’ll end up with an explosion in unused metric combinations, but we want the most common ones to be always present.
['system_access', 'code_review_workflow', 'continuous_integration', 'not_owned', 'source_code_management', FEATURE_CATEGORY_DEFAULT].freeze
- REQUEST_URGENCY_KEY =
'gitlab.request_urgency'
Class Method Summary collapse
- .http_health_requests_total ⇒ Object
- .http_request_duration_seconds ⇒ Object
- .http_requests_total ⇒ Object
- .initialize_metrics ⇒ Object
- .rack_uncaught_errors_count ⇒ Object
Instance Method Summary collapse
- #call(env) ⇒ Object
- #endpoint_id ⇒ Object
- #feature_category ⇒ Object
- #health_endpoint?(path) ⇒ Boolean
-
#initialize(app) ⇒ RequestsRackMiddleware
constructor
A new instance of RequestsRackMiddleware.
- #labels_from_context ⇒ Object
- #record_apdex(urgency, elapsed) ⇒ Object
- #record_error(urgency, status) ⇒ Object
- #urgency_for_env(env) ⇒ Object
Constructor Details
#initialize(app) ⇒ RequestsRackMiddleware
Returns a new instance of RequestsRackMiddleware.
32 33 34 |
# File 'lib/gitlab/metrics/requests_rack_middleware.rb', line 32 def initialize(app) @app = app end |
Class Method Details
.http_health_requests_total ⇒ Object
49 50 51 |
# File 'lib/gitlab/metrics/requests_rack_middleware.rb', line 49 def self.http_health_requests_total ::Gitlab::Metrics.counter(:http_health_requests_total, 'Health endpoint request count') end |
.http_request_duration_seconds ⇒ Object
44 45 46 47 |
# File 'lib/gitlab/metrics/requests_rack_middleware.rb', line 44 def self.http_request_duration_seconds ::Gitlab::Metrics.histogram(:http_request_duration_seconds, 'Request handling execution time', {}, [0.05, 0.1, 0.25, 0.5, 0.7, 1, 2.5, 5, 10, 25]) end |
.http_requests_total ⇒ Object
36 37 38 |
# File 'lib/gitlab/metrics/requests_rack_middleware.rb', line 36 def self.http_requests_total ::Gitlab::Metrics.counter(:http_requests_total, 'Request count') end |
.initialize_metrics ⇒ Object
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/gitlab/metrics/requests_rack_middleware.rb', line 53 def self.initialize_metrics # This initialization is done to avoid gaps in scraped metrics after # restarts. It makes sure all counters/histograms are available at # process start. # # For example `rate(http_requests_total{status="500"}[1m])` would return # no data until the first 500 error would occur. HTTP_METHODS.each do |method, statuses| http_request_duration_seconds.get({ method: method }) statuses.product(FEATURE_CATEGORIES_TO_INITIALIZE) do |status, feature_category| http_requests_total.get({ method: method, status: status, feature_category: feature_category }) end end Gitlab::Metrics::RailsSlis.initialize_request_slis! end |
Instance Method Details
#call(env) ⇒ Object
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/gitlab/metrics/requests_rack_middleware.rb', line 71 def call(env) method = env['REQUEST_METHOD'].downcase method = 'INVALID' unless HTTP_METHODS.key?(method) started = ::Gitlab::Metrics::System.monotonic_time health_endpoint = health_endpoint?(env['PATH_INFO']) status = 'undefined' begin status, headers, body = @app.call(env) return [status, headers, body] if health_endpoint urgency = urgency_for_env(env) if ::Gitlab::Metrics.record_duration_for_status?(status) elapsed = ::Gitlab::Metrics::System.monotonic_time - started self.class.http_request_duration_seconds.observe({ method: method }, elapsed) record_apdex(urgency, elapsed) end record_error(urgency, status) [status, headers, body] rescue StandardError self.class.rack_uncaught_errors_count.increment raise ensure if health_endpoint self.class.http_health_requests_total.increment(status: status.to_s, method: method) else self.class.http_requests_total.increment( status: status.to_s, method: method, feature_category: feature_category.presence || FEATURE_CATEGORY_DEFAULT ) end end end |
#endpoint_id ⇒ Object
118 119 120 |
# File 'lib/gitlab/metrics/requests_rack_middleware.rb', line 118 def endpoint_id ::Gitlab::ApplicationContext.current_context_attribute(:caller_id) end |
#feature_category ⇒ Object
114 115 116 |
# File 'lib/gitlab/metrics/requests_rack_middleware.rb', line 114 def feature_category ::Gitlab::ApplicationContext.current_context_attribute(:feature_category) end |
#health_endpoint?(path) ⇒ Boolean
108 109 110 111 112 |
# File 'lib/gitlab/metrics/requests_rack_middleware.rb', line 108 def health_endpoint?(path) return false if path.blank? HEALTH_ENDPOINT.match?(CGI.unescape(path)) end |
#labels_from_context ⇒ Object
136 137 138 139 140 141 |
# File 'lib/gitlab/metrics/requests_rack_middleware.rb', line 136 def labels_from_context { feature_category: feature_category.presence || FEATURE_CATEGORY_DEFAULT, endpoint_id: endpoint_id.presence || ENDPOINT_MISSING } end |
#record_apdex(urgency, elapsed) ⇒ Object
122 123 124 125 126 127 |
# File 'lib/gitlab/metrics/requests_rack_middleware.rb', line 122 def record_apdex(urgency, elapsed) Gitlab::Metrics::RailsSlis.request_apdex.increment( labels: labels_from_context.merge(request_urgency: urgency.name), success: elapsed < urgency.duration ) end |
#record_error(urgency, status) ⇒ Object
129 130 131 132 133 134 |
# File 'lib/gitlab/metrics/requests_rack_middleware.rb', line 129 def record_error(urgency, status) Gitlab::Metrics::RailsSlis.request_error_rate.increment( labels: labels_from_context.merge(request_urgency: urgency.name), error: ::Gitlab::Metrics.server_error?(status) ) end |
#urgency_for_env(env) ⇒ Object
143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/gitlab/metrics/requests_rack_middleware.rb', line 143 def urgency_for_env(env) endpoint_urgency = if env[REQUEST_URGENCY_KEY].present? env[REQUEST_URGENCY_KEY] elsif env['api.endpoint'].present? env['api.endpoint'].[:for].try(:urgency_for_app, env['api.endpoint']) elsif env['action_controller.instance'].present? && env['action_controller.instance'].respond_to?(:urgency) env['action_controller.instance'].urgency end endpoint_urgency || Gitlab::EndpointAttributes::DEFAULT_URGENCY end |