trace_request_id 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f42a8225e6860b237f499a3b00e8d1204d1035873cbd8b9c69caee39b8de100c
4
+ data.tar.gz: a9934505dcb9b0528e20edddce2eb27edfa03d26f6f5a8a568c7ea7df8b4da74
5
+ SHA512:
6
+ metadata.gz: 8d04f12d5654cb4a7ebc16934b430cdc853a100911b4c9406ab297a2398e33522921c7977f435849dba1d95951475b0682640d216a69af44fccf1574c47c456f
7
+ data.tar.gz: 0cfa01653d617229b8057f8d80494ea7fa6461536448050e0b07ed7e424957cc2686b2e6b5cdce2c8e92ae0352722fed23837df244dbce87b569e1953eaf0276
data/README.md ADDED
@@ -0,0 +1,127 @@
1
+ # TraceRequestId
2
+
3
+ A Ruby gem that stores X-Request-Id in thread context and passes it to Sidekiq jobs to trace user journeys.
4
+ This gem helps maintain request context across different parts of your application, making it easier to track
5
+ and debug user requests through your system.
6
+
7
+ ## Features
8
+
9
+ - Thread-safe storage of request IDs
10
+ - Automatic UUID generation for new requests
11
+ - Sidekiq integration for passing request IDs to background jobs
12
+ - Rails middleware support for automatic request ID handling
13
+ - Simple API for managing request IDs
14
+
15
+ ## Installation
16
+
17
+ Add this line to your application's Gemfile:
18
+
19
+ ```ruby
20
+ gem 'trace_request_id'
21
+ ```
22
+
23
+ And then execute:
24
+
25
+ $ bundle install
26
+
27
+ Or install it yourself as:
28
+
29
+ $ gem install trace_request_id
30
+
31
+ ## Usage
32
+
33
+ ### Basic Usage
34
+
35
+ ```ruby
36
+ # Get the current request ID (returns nil if not set)
37
+ TraceRequestId.id
38
+
39
+ # Set a request ID
40
+ TraceRequestId.id = "custom-request-id"
41
+
42
+ # Get or initialize a request ID (generates UUID if not set)
43
+ TraceRequestId.id(init: true)
44
+
45
+ # Clear the current request ID
46
+ TraceRequestId.clear
47
+ ```
48
+
49
+ ### Sinatra Integration
50
+
51
+ ```ruby
52
+ class MyApplication < Sinatra::Base
53
+ use Rack::TraceId
54
+ end
55
+ ```
56
+
57
+ ### Rails Integration
58
+
59
+ The gem provides a Rails middleware that automatically handles request IDs.
60
+
61
+ It registers Rails middleware using Railtie, inserting it after ActionDispatch::RequestId
62
+
63
+ The middleware:
64
+ - Extracts the request ID from the Rails request (set by ActionDispatch::RequestId)
65
+ - Stores it in the thread context for the duration of the request
66
+ - Cleans up the thread context after the request completes
67
+
68
+ ### Sidekiq Integration
69
+
70
+ The gem registers Sidekiq middleware automatically using Railtie.
71
+ The gem provides both client and server middleware to maintain request context across background jobs.
72
+
73
+ #### Client Middleware
74
+
75
+ - Captures the current trace ID from the thread context
76
+ - Stores it in the job payload before saving to Redis
77
+ - Generates a new UUID if no trace ID exists
78
+
79
+ #### Server Middleware
80
+
81
+ - Restores the trace ID from the job payload to the worker thread context
82
+ - Automatically cleans up the thread context after the job completes
83
+
84
+ ## Thread Safety
85
+
86
+ The gem is designed to be thread-safe. Each thread maintains its own request ID context, making it safe to use in multi-threaded environments.
87
+
88
+ Example of thread isolation:
89
+
90
+ ```ruby
91
+ # Main thread
92
+ TraceRequestId.id = "main-thread-id"
93
+
94
+ # Different threads maintain separate contexts
95
+ thread1 = Thread.new do
96
+ TraceRequestId.id = "thread1-id"
97
+ # TraceRequestId.id returns "thread1-id"
98
+ end
99
+
100
+ thread2 = Thread.new do
101
+ TraceRequestId.id = "thread2-id"
102
+ # TraceRequestId.id returns "thread2-id"
103
+ end
104
+
105
+ # Main thread still has its original ID
106
+ # TraceRequestId.id returns "main-thread-id"
107
+ ```
108
+
109
+ ## Development
110
+
111
+ After checking out the repo, run `bin/setup` to install dependencies.
112
+ Then, to run the tests:
113
+ - rspec --pattern spec/*.rb
114
+ - cd spec/dummy_app
115
+ - rspec
116
+ - cd ../spec/dummy_app_no_sidekiq
117
+ - rspec
118
+ - cd ../spec/dummy_sinatra
119
+ - rspec
120
+
121
+ ## Contributing
122
+
123
+ Bug reports and pull requests are welcome on GitHub at https://github.com/den1049/trace_request_id.
124
+
125
+ ## License
126
+
127
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ module Rack
6
+ # Middleware to store +request_id+ in the thread context as +trace_id+ and clean it up at the end of the request.
7
+ #
8
+ # For rails app it needs to be inserted after ActionDispatch::RequestId to ensure that request_id
9
+ # will be retrieved or generated with ActionDispatch::RequestId.
10
+ # config.middleware.insert_after ActionDispatch::RequestId, Rack::TraceId
11
+ class TraceId
12
+ def initialize(app)
13
+ @app = app
14
+ end
15
+
16
+ def call(env)
17
+ with_trace_id(env) do
18
+ @app.call(env)
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ # Extracts +request_id+ from +env+ argument, then wraps block with thread context store and clear steps
25
+ def with_trace_id(env)
26
+ TraceRequestId.id = env_request_id(env)
27
+
28
+ yield
29
+ ensure
30
+ TraceRequestId.clear
31
+ end
32
+
33
+ def env_request_id(env)
34
+ return env['HTTP_X_REQUEST_ID'] || SecureRandom.uuid unless defined?(ActionDispatch::Request)
35
+
36
+ # extract request_id assigned by ActionDispatch::RequestId middleware
37
+ req = ActionDispatch::Request.new env
38
+ req.request_id
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TraceRequestId
4
+ class Railtie < Rails::Railtie # :nodoc:
5
+ initializer 'trace_request_id.configure_rails_initialization' do |app|
6
+ app.middleware.insert_after ActionDispatch::RequestId, Rack::TraceId
7
+ register_sidekiq_middleware if defined?(Sidekiq)
8
+ end
9
+
10
+ private
11
+
12
+ def register_sidekiq_middleware
13
+ register_sidekiq_client_middleware
14
+ register_sidekiq_server_middleware
15
+ register_sidekiq_test_middleware if defined?(Sidekiq::Testing)
16
+ end
17
+
18
+ def register_sidekiq_client_middleware
19
+ Sidekiq.configure_client do |config|
20
+ config.client_middleware do |chain|
21
+ chain.add SidekiqClientMiddleware
22
+ end
23
+ end
24
+ end
25
+
26
+ def register_sidekiq_server_middleware
27
+ Sidekiq.configure_server do |config|
28
+ config.client_middleware do |chain|
29
+ chain.add SidekiqClientMiddleware
30
+ end
31
+
32
+ config.server_middleware do |chain|
33
+ chain.add SidekiqServerMiddleware
34
+ end
35
+ end
36
+ end
37
+
38
+ def register_sidekiq_test_middleware
39
+ # attach Sidekiq middleware to Sidekiq:Testing
40
+ Sidekiq::Testing.server_middleware do |chain|
41
+ chain.add SidekiqServerMiddleware
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TraceRequestId
4
+ # Stores +trace_id+ from the thread context to the job context before saving it to Redis.
5
+ #
6
+ # It needs to be inserted in the SidekiqClient chain at the start.
7
+ # Sidekiq.configure_client do |config|
8
+ # config.client_middleware do |chain|
9
+ # chain.add TraceRequestId::SidekiqClientMiddleware
10
+ # # ... other client middlewares
11
+ # end
12
+ # end
13
+ #
14
+ # Sidekiq.configure_server do |config|
15
+ # config.client_middleware do |chain|
16
+ # chain.add TraceRequestId::SidekiqClientMiddleware
17
+ # # ... other client middlewares
18
+ # end
19
+ # end
20
+ class SidekiqClientMiddleware
21
+ def call(_worker_class, job, _queue, _redis_pool = '')
22
+ job[TraceRequestId::TRACE_ID] = TraceRequestId.id(init: true)
23
+ yield
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TraceRequestId
4
+ # Restores +trace_id+ from the job context (Redis) to the thread context before starting a job.
5
+ #
6
+ # It needs to be inserted in the SidekiqClient chain at the start.
7
+ # Sidekiq.configure_server do |config|
8
+ # config.server_middleware do |chain|
9
+ # chain.add TraceRequestId::SidekiqServerMiddleware
10
+ # # ... other server middlewares
11
+ # end
12
+ # end
13
+ class SidekiqServerMiddleware
14
+ def call(_worker, job, _queue)
15
+ TraceRequestId.id = job[TraceRequestId::TRACE_ID]
16
+
17
+ yield
18
+ ensure
19
+ TraceRequestId.clear
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TraceRequestId
4
+ VERSION = '0.1.2'
5
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'trace_request_id/version'
4
+ require_relative 'rack/trace_id'
5
+ require_relative 'trace_request_id/railtie' if defined?(Rails::Railtie)
6
+ require_relative 'trace_request_id/sidekiq_client_middleware' if defined?(Sidekiq)
7
+ require_relative 'trace_request_id/sidekiq_server_middleware' if defined?(Sidekiq)
8
+
9
+ # Module to store trace id in the thread context
10
+ class TraceRequestId
11
+ TRACE_ID = '__trace_id'
12
+
13
+ class << self
14
+ # Get the current trace id, or +nil+ if one has not been set.
15
+ def id(init: false)
16
+ self.id = new_trace_id_value if init && current_trace_id.to_s.strip.empty?
17
+
18
+ current_trace_id
19
+ end
20
+
21
+ # Set the new trace id.
22
+ def id=(new_trace_id)
23
+ Thread.current.thread_variable_set(TRACE_ID, new_trace_id)
24
+ end
25
+
26
+ # Clear the trace id from the current thread.
27
+ def clear
28
+ Thread.current.thread_variable_set(TRACE_ID, nil)
29
+ end
30
+
31
+ private
32
+
33
+ def current_trace_id
34
+ Thread.current.thread_variable_get(TRACE_ID)
35
+ end
36
+
37
+ def new_trace_id_value
38
+ SecureRandom.uuid
39
+ end
40
+ end
41
+ end
metadata ADDED
@@ -0,0 +1,55 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: trace_request_id
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Denis
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-06-18 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: |-
14
+ This gem helps track user journey storing X-Request-Id in the thread context
15
+ and passing it to Sidekiq jobs
16
+ email:
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - README.md
22
+ - lib/rack/trace_id.rb
23
+ - lib/trace_request_id.rb
24
+ - lib/trace_request_id/railtie.rb
25
+ - lib/trace_request_id/sidekiq_client_middleware.rb
26
+ - lib/trace_request_id/sidekiq_server_middleware.rb
27
+ - lib/trace_request_id/version.rb
28
+ homepage: https://github.com/den1049/trace_request_id
29
+ licenses:
30
+ - MIT
31
+ metadata:
32
+ homepage_uri: https://github.com/den1049/trace_request_id
33
+ source_code_uri: https://github.com/den1049/trace_request_id
34
+ changelog_uri: https://github.com/den1049/trace_request_id/blob/main/CHANGELOG.md
35
+ rubygems_mfa_required: 'true'
36
+ post_install_message:
37
+ rdoc_options: []
38
+ require_paths:
39
+ - lib
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: 2.7.0
45
+ required_rubygems_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ requirements: []
51
+ rubygems_version: 3.1.6
52
+ signing_key:
53
+ specification_version: 4
54
+ summary: A gem to store X-Request-Id in thread context and pass it to Sidekiq jobs
55
+ test_files: []