ruby 36 lines · 7 steps

Per-request context with CurrentAttributes in Rails

A Rack middleware, a Current model, and tagged logging combine to attach a request ID to every log line and make it globally reachable.

Explained by highlit
1module RequestTagging
2 class Middleware
3 def initialize(app)
4 @app = app
5 end
6 
7 def call(env)
8 request_id = env["action_dispatch.request_id"]
9 Current.request_id = request_id
10 @app.call(env)
11 ensure
12 Current.reset
13 end
14 end
15end
16 
17class Current < ActiveSupport::CurrentAttributes
18 attribute :request_id
19end
20 
21Rails.application.configure do
22 config.log_tags = [
23 :request_id,
24 ->(req) { "ip=#{req.remote_ip}" },
25 ->(req) { "method=#{req.request_method}" }
26 ]
27 
28 config.logger = ActiveSupport::TaggedLogging.new(
29 ActiveSupport::Logger.new($stdout)
30 )
31 
32 config.middleware.insert_after(
33 ActionDispatch::RequestId,
34 RequestTagging::Middleware
35 )
36end
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1CurrentAttributes gives you request-scoped global state that stays isolated across concurrent requests.
  2. 2Wrapping mutable per-request state in an ensure block guarantees cleanup even when the request raises.
  3. 3Tagged logging plus a shared request ID lets you trace every log line back to a single request.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Per-request context with CurrentAttributes in Rails — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code