Class: BrainzLab::Rails::Middleware
- Inherits:
-
Object
- Object
- BrainzLab::Rails::Middleware
- Defined in:
- lib/brainzlab/rails/railtie.rb
Overview
Middleware for request context
Instance Method Summary collapse
- #call(env) ⇒ Object
-
#initialize(app) ⇒ Middleware
constructor
A new instance of Middleware.
- #record_pulse_trace(request, started_at, status) ⇒ Object
- #should_trace_request?(request) ⇒ Boolean
Constructor Details
#initialize(app) ⇒ Middleware
Returns a new instance of Middleware.
211 212 213 |
# File 'lib/brainzlab/rails/railtie.rb', line 211 def initialize(app) @app = app end |
Instance Method Details
#call(env) ⇒ Object
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 |
# File 'lib/brainzlab/rails/railtie.rb', line 215 def call(env) request = ActionDispatch::Request.new(env) started_at = Time.now.utc # Set request context context = BrainzLab::Context.current request_id = request.request_id || env['action_dispatch.request_id'] context.request_id = request_id # Store request_id in thread local for log subscriber Thread.current[:brainzlab_request_id] = request_id # NOTE: session_id is captured AFTER @app.call (see below), never here. # Forcing a session load on the way in — before the app's session # middleware and any reset_session (login) — drops the session on # cookie/active_record_store apps, causing login loops. # Capture full request info for Reflex context.request_method = request.request_method context.request_path = request.path context.request_url = request.url context.request_params = begin filter_params(request.params.to_h) rescue ActionDispatch::Http::Parameters::ParseError {} end context.request_headers = extract_headers(env) # Add breadcrumb for request start BrainzLab::Reflex.( "#{request.request_method} #{request.path}", category: 'http.request', level: :info, data: { url: request.url } ) # Add request data to Recall context context.set_context( path: request.path, method: request.request_method, ip: request.remote_ip, user_agent: request.user_agent ) # Extract distributed tracing context from incoming request headers parent_context = BrainzLab::Pulse.extract!(env) # Start Pulse trace if enabled and path not excluded should_trace = should_trace_request?(request) if should_trace # Initialize spans array for this request Thread.current[:brainzlab_pulse_spans] = [] Thread.current[:brainzlab_pulse_breakdown] = nil BrainzLab::Pulse.start_trace( "#{request.request_method} #{request.path}", kind: 'request', parent_context: parent_context ) end status, headers, response = @app.call(env) # Capture session_id now that the app (and its session middleware) has # run. Read it only if the session was already loaded — never force a # load — so we never disturb the session lifecycle / Set-Cookie. begin rack_session = env['rack.session'] if rack_session && (!rack_session.respond_to?(:loaded?) || rack_session.loaded?) sid = rack_session.respond_to?(:id) ? rack_session.id : nil context.session_id = sid.to_s if sid && !sid.to_s.empty? end rescue StandardError nil end # Add breadcrumb for response BrainzLab::Reflex.( "Response #{status}", category: 'http.response', level: status >= 400 ? :error : :info, data: { status: status } ) [status, headers, response] rescue StandardError => e # Record error in Pulse trace if should_trace BrainzLab::Pulse.finish_trace( error: true, error_class: e.class.name, error_message: e. ) end raise ensure # Finish Pulse trace for successful requests record_pulse_trace(request, started_at, status) if should_trace && !$ERROR_INFO Thread.current[:brainzlab_request_id] = nil BrainzLab::Context.clear! BrainzLab::Pulse::Propagation.clear! end |
#record_pulse_trace(request, started_at, status) ⇒ Object
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 |
# File 'lib/brainzlab/rails/railtie.rb', line 334 def record_pulse_trace(request, started_at, status) ended_at = Time.now.utc context = BrainzLab::Context.current # Collect spans from instrumentation spans = Thread.current[:brainzlab_pulse_spans] || [] breakdown = Thread.current[:brainzlab_pulse_breakdown] || {} # Format spans for API formatted_spans = spans.map do |span| { span_id: span[:span_id], name: span[:name], kind: span[:kind], started_at: (span[:started_at]), ended_at: (span[:ended_at]), duration_ms: span[:duration_ms], data: span[:data] } end BrainzLab::Pulse.record_trace( "#{request.request_method} #{request.path}", kind: 'request', started_at: started_at, ended_at: ended_at, request_id: context.request_id, request_method: request.request_method, request_path: request.path, controller: context.controller, action: context.action, status: status, error: status.to_i >= 500, view_ms: breakdown[:view_ms], db_ms: breakdown[:db_ms], spans: formatted_spans ) rescue StandardError => e BrainzLab.configuration.logger&.error("[BrainzLab::Pulse] Failed to record trace: #{e.}") ensure # Clean up thread locals Thread.current[:brainzlab_pulse_spans] = nil Thread.current[:brainzlab_pulse_breakdown] = nil end |
#should_trace_request?(request) ⇒ Boolean
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 |
# File 'lib/brainzlab/rails/railtie.rb', line 318 def should_trace_request?(request) return false unless BrainzLab.configuration.pulse_enabled excluded = BrainzLab.configuration.pulse_excluded_paths || [] path = request.path # Check if path matches any excluded pattern excluded.none? do |pattern| if pattern.include?('*') File.fnmatch?(pattern, path) else path.start_with?(pattern) end end end |