logstruct 0.1.9 → 0.1.10

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 95828f14e3935518654b94939f2cee577f296d454fa3666a8e5f1eb9ababb1dd
4
- data.tar.gz: dcd8ff40d991a79573fe60e678ea85590b9597f1e0163f132f8eff79015a88ff
3
+ metadata.gz: b138e5ba6e0739ee31d032606f4d7508463deeee00b64e3a870d34d4316e7567
4
+ data.tar.gz: f36bc4a9cb5ee2ab42b77a581efd1b28c7c23a75191429ac5b5926023d33a594
5
5
  SHA512:
6
- metadata.gz: 868f9dc4e320fbdf752b0e3b901280b5a972b9759592869587bf3673d905ddb3b554851c0dfe977eafe543be37b37105f9f759cccc8d06a009771585c931ce58
7
- data.tar.gz: b8402c46a941a578261933249acddff294551d5fd5b1823ed54e48ce2f17ba1e760919a540ef38918706004093a1b3c0f5a89e16405037e4e86cbd6a114bc363
6
+ metadata.gz: c06589605729de5ac9ea44694e82712d2d175201adab6052b6eff1a2ae2cc8cc6b476ed7200d1fa6bf6a79db6eb280847b4ca34559a501bc327129db4574acfe
7
+ data.tar.gz: 992fc803c47c57367ca906179bf9b356618e42bf840ac6a3de4b7296d90be0db8d513177c57643e1564967624f444d0af00f2582844e4d68825a03f8e911ac37
data/CHANGELOG.md CHANGED
@@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  ### Changed
11
11
 
12
+ ## [0.1.10] - 2026-01-23
13
+
14
+ ### Added
15
+
16
+ - **Feature**: `request_id` now appears on all logs during a request, not just the request log
17
+
12
18
  ## [0.1.9] - 2026-01-23
13
19
 
14
20
  ### Changed
@@ -32,7 +32,7 @@ module LogStruct
32
32
  SourceIp = new(:source_ip)
33
33
  UserAgent = new(:user_agent)
34
34
  Referer = new(:referer)
35
- RequestId = new(:request_id)
35
+ RequestId = new(:req_id)
36
36
  Host = new(:host)
37
37
  ContentType = new(:content_type)
38
38
  Accept = new(:accept)
@@ -54,12 +54,6 @@ module LogStruct
54
54
  end
55
55
  log_data[:tags] = tags if tags.present?
56
56
 
57
- # Get request_id from ActionDispatch if available
58
- if ::ActionDispatch::Request.respond_to?(:current_request_id) &&
59
- T.unsafe(::ActionDispatch::Request).current_request_id.present?
60
- log_data[:request_id] = T.unsafe(::ActionDispatch::Request).current_request_id
61
- end
62
-
63
57
  # Get job_id from ActiveJob if available
64
58
  if defined?(::ActiveJob::Logging) && ::ActiveJob::Logging.respond_to?(:job_id) &&
65
59
  T.unsafe(::ActiveJob::Logging).job_id.present?
@@ -63,7 +63,6 @@ module LogStruct
63
63
  source_ip: request.ip,
64
64
  user_agent: request.user_agent,
65
65
  referer: request.referer,
66
- request_id: request.request_id,
67
66
  x_forwarded_for: request.x_forwarded_for,
68
67
  allowed_hosts: allowed_hosts_array&.empty? ? nil : allowed_hosts_array,
69
68
  allow_ip_hosts: allow_ip_hosts_value
@@ -101,6 +101,12 @@ module LogStruct
101
101
  headers = event.payload[:headers]
102
102
  return if headers.blank?
103
103
 
104
+ # Rails' ActionDispatch::RequestId middleware stores request_id in headers
105
+ # Only set if not already present in payload (payload takes precedence)
106
+ if options[:request_id].blank? && headers["action_dispatch.request_id"].present?
107
+ options[:request_id] = headers["action_dispatch.request_id"]
108
+ end
109
+
104
110
  options[:user_agent] = headers["HTTP_USER_AGENT"]
105
111
  options[:referer] = headers["HTTP_REFERER"]
106
112
  options[:content_type] = headers["CONTENT_TYPE"]
@@ -144,7 +150,6 @@ module LogStruct
144
150
  view: view,
145
151
  database: db,
146
152
  params: params,
147
- request_id: normalized_data[:request_id]&.to_s,
148
153
  source_ip: normalized_data[:source_ip]&.to_s,
149
154
  user_agent: normalized_data[:user_agent]&.to_s,
150
155
  referer: normalized_data[:referer]&.to_s,
@@ -71,7 +71,6 @@ module LogStruct
71
71
  http_method: env["REQUEST_METHOD"],
72
72
  user_agent: env["HTTP_USER_AGENT"],
73
73
  referer: env["HTTP_REFERER"],
74
- request_id: request.request_id,
75
74
  message: ip_spoof_error.message,
76
75
  client_ip: env["HTTP_CLIENT_IP"],
77
76
  x_forwarded_for: env["HTTP_X_FORWARDED_FOR"],
@@ -90,7 +89,6 @@ module LogStruct
90
89
  source_ip: request.remote_ip,
91
90
  user_agent: request.user_agent,
92
91
  referer: request.referer,
93
- request_id: request.request_id,
94
92
  message: error.message,
95
93
  timestamp: Time.now
96
94
  )
@@ -137,7 +135,6 @@ module LogStruct
137
135
  def extract_request_context(env, request = nil)
138
136
  request ||= ::ActionDispatch::Request.new(env)
139
137
  {
140
- request_id: request.request_id,
141
138
  path: request.path,
142
139
  method: request.method,
143
140
  user_agent: request.user_agent,
@@ -0,0 +1,28 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module LogStruct
5
+ module Integrations
6
+ module RequestContext
7
+ # Middleware that captures request_id and stores it in SemanticLogger's
8
+ # named_tags so all logs during the request include the request_id.
9
+ class Middleware
10
+ extend T::Sig
11
+
12
+ sig { params(app: T.untyped).void }
13
+ def initialize(app)
14
+ @app = app
15
+ end
16
+
17
+ sig { params(env: T.untyped).returns(T.untyped) }
18
+ def call(env)
19
+ request = ::ActionDispatch::Request.new(env)
20
+ ::SemanticLogger.push_named_tags(request_id: request.request_id)
21
+ @app.call(env)
22
+ ensure
23
+ ::SemanticLogger.pop_named_tags
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,27 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "request_context/middleware"
5
+
6
+ module LogStruct
7
+ module Integrations
8
+ # Request context integration that captures request_id for all logs
9
+ module RequestContext
10
+ extend T::Sig
11
+ extend IntegrationInterface
12
+
13
+ sig { override.params(config: LogStruct::Configuration).returns(T.nilable(T::Boolean)) }
14
+ def self.setup(config)
15
+ return nil unless config.enabled
16
+
17
+ # Insert after RequestId middleware so request_id is available
18
+ ::Rails.application.middleware.insert_after(
19
+ ::ActionDispatch::RequestId,
20
+ Integrations::RequestContext::Middleware
21
+ )
22
+
23
+ true
24
+ end
25
+ end
26
+ end
27
+ end
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require_relative "integrations/integration_interface"
5
+ require_relative "integrations/request_context"
5
6
  require_relative "integrations/active_job"
6
7
  require_relative "integrations/active_record"
7
8
  require_relative "integrations/rack_error_handler"
@@ -77,6 +78,7 @@ module LogStruct
77
78
 
78
79
  sig { params(config: LogStruct::Configuration).void }
79
80
  def self.setup_middleware_integrations(config)
81
+ Integrations::RequestContext.setup(config)
80
82
  Integrations::HostAuthorization.setup(config) if config.integrations.enable_host_authorization
81
83
  Integrations::RackErrorHandler.setup(config) if config.integrations.enable_rack_error_handler
82
84
  end
@@ -33,7 +33,6 @@ module LogStruct
33
33
  const :source_ip, T.nilable(String), default: nil
34
34
  const :user_agent, T.nilable(String), default: nil
35
35
  const :referer, T.nilable(String), default: nil
36
- const :request_id, T.nilable(String), default: nil
37
36
 
38
37
  # Event-specific fields
39
38
  const :format, T.nilable(Symbol), default: nil
@@ -69,7 +68,6 @@ module LogStruct
69
68
  h[LogField::SourceIp] = source_ip unless source_ip.nil?
70
69
  h[LogField::UserAgent] = user_agent unless user_agent.nil?
71
70
  h[LogField::Referer] = referer unless referer.nil?
72
- h[LogField::RequestId] = request_id unless request_id.nil?
73
71
  h[LogField::Format] = format unless format.nil?
74
72
  h[LogField::Controller] = controller unless controller.nil?
75
73
  h[LogField::Action] = action unless action.nil?
@@ -34,7 +34,6 @@ module LogStruct
34
34
  const :source_ip, T.nilable(String), default: nil
35
35
  const :user_agent, T.nilable(String), default: nil
36
36
  const :referer, T.nilable(String), default: nil
37
- const :request_id, T.nilable(String), default: nil
38
37
 
39
38
  # Event-specific fields
40
39
  const :message, T.nilable(String), default: nil
@@ -65,7 +64,6 @@ module LogStruct
65
64
  h[LogField::SourceIp] = source_ip unless source_ip.nil?
66
65
  h[LogField::UserAgent] = user_agent unless user_agent.nil?
67
66
  h[LogField::Referer] = referer unless referer.nil?
68
- h[LogField::RequestId] = request_id unless request_id.nil?
69
67
  h[LogField::Message] = message unless message.nil?
70
68
  h[LogField::BlockedHost] = blocked_host unless blocked_host.nil?
71
69
  h[LogField::BlockedHosts] = blocked_hosts unless blocked_hosts.nil?
@@ -34,7 +34,6 @@ module LogStruct
34
34
  const :source_ip, T.nilable(String), default: nil
35
35
  const :user_agent, T.nilable(String), default: nil
36
36
  const :referer, T.nilable(String), default: nil
37
- const :request_id, T.nilable(String), default: nil
38
37
 
39
38
  # Event-specific fields
40
39
  const :message, T.nilable(String), default: nil
@@ -60,7 +59,6 @@ module LogStruct
60
59
  h[LogField::SourceIp] = source_ip unless source_ip.nil?
61
60
  h[LogField::UserAgent] = user_agent unless user_agent.nil?
62
61
  h[LogField::Referer] = referer unless referer.nil?
63
- h[LogField::RequestId] = request_id unless request_id.nil?
64
62
  h[LogField::Message] = message unless message.nil?
65
63
  h
66
64
  end
@@ -34,7 +34,6 @@ module LogStruct
34
34
  const :source_ip, T.nilable(String), default: nil
35
35
  const :user_agent, T.nilable(String), default: nil
36
36
  const :referer, T.nilable(String), default: nil
37
- const :request_id, T.nilable(String), default: nil
38
37
 
39
38
  # Event-specific fields
40
39
  const :message, T.nilable(String), default: nil
@@ -62,7 +61,6 @@ module LogStruct
62
61
  h[LogField::SourceIp] = source_ip unless source_ip.nil?
63
62
  h[LogField::UserAgent] = user_agent unless user_agent.nil?
64
63
  h[LogField::Referer] = referer unless referer.nil?
65
- h[LogField::RequestId] = request_id unless request_id.nil?
66
64
  h[LogField::Message] = message unless message.nil?
67
65
  h[LogField::ClientIp] = client_ip unless client_ip.nil?
68
66
  h[LogField::XForwardedFor] = x_forwarded_for unless x_forwarded_for.nil?
@@ -20,7 +20,6 @@ module LogStruct
20
20
  const :source_ip, T.nilable(String), default: nil
21
21
  const :user_agent, T.nilable(String), default: nil
22
22
  const :referer, T.nilable(String), default: nil
23
- const :request_id, T.nilable(String), default: nil
24
23
 
25
24
  Kwargs = T.type_alias do
26
25
  {
@@ -28,8 +27,7 @@ module LogStruct
28
27
  http_method: T.nilable(String),
29
28
  source_ip: T.nilable(String),
30
29
  user_agent: T.nilable(String),
31
- referer: T.nilable(String),
32
- request_id: T.nilable(String)
30
+ referer: T.nilable(String)
33
31
  }
34
32
  end
35
33
 
@@ -40,8 +38,7 @@ module LogStruct
40
38
  http_method: http_method,
41
39
  source_ip: source_ip,
42
40
  user_agent: user_agent,
43
- referer: referer,
44
- request_id: request_id
41
+ referer: referer
45
42
  }
46
43
  end
47
44
  end
@@ -79,6 +79,15 @@ module LogStruct
79
79
  )
80
80
  @logstruct_formatter.call(log.level, log.time, log.name, plain_log)
81
81
  end
82
+
83
+ # Add request_id from named_tags if present
84
+ request_id = log.named_tags[:request_id]
85
+ if request_id
86
+ data = JSON.parse(json)
87
+ data["req_id"] = request_id
88
+ json = data.to_json
89
+ end
90
+
82
91
  # SemanticLogger appenders typically add their own newline. Avoid double newlines by stripping ours.
83
92
  json.end_with?("\n") ? json.chomp : json
84
93
  end
@@ -148,7 +148,9 @@ module LogStruct
148
148
  end
149
149
 
150
150
  # Proxy object to provide ActiveJob-compatible formatter interface
151
- class FormatterProxy
151
+ # Also implements the standard Logger formatter interface (call method)
152
+ # for compatibility with Ruby's Logger (especially logger gem 1.7.0+)
153
+ class FormatterProxy < ::Logger::Formatter
152
154
  extend T::Sig
153
155
 
154
156
  sig { returns(T::Array[T.any(String, Symbol)]) }
@@ -20,7 +20,6 @@ module LogStruct
20
20
  hash[LogField::SourceIp.serialize] = source_ip if source_ip
21
21
  hash[LogField::UserAgent.serialize] = user_agent if user_agent
22
22
  hash[LogField::Referer.serialize] = referer if referer
23
- hash[LogField::RequestId.serialize] = request_id if request_id
24
23
  end
25
24
  end
26
25
  end
@@ -29,10 +29,6 @@ module LogStruct
29
29
  sig { abstract.returns(T.nilable(String)) }
30
30
  def referer
31
31
  end
32
-
33
- sig { abstract.returns(T.nilable(String)) }
34
- def request_id
35
- end
36
32
  end
37
33
  end
38
34
  end
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module LogStruct
5
- VERSION = "0.1.9"
5
+ VERSION = "0.1.10"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstruct
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - DocSpring
@@ -281,6 +281,8 @@ files:
281
281
  - lib/log_struct/integrations/rack.rb
282
282
  - lib/log_struct/integrations/rack_error_handler.rb
283
283
  - lib/log_struct/integrations/rack_error_handler/middleware.rb
284
+ - lib/log_struct/integrations/request_context.rb
285
+ - lib/log_struct/integrations/request_context/middleware.rb
284
286
  - lib/log_struct/integrations/shrine.rb
285
287
  - lib/log_struct/integrations/sidekiq.rb
286
288
  - lib/log_struct/integrations/sidekiq/logger.rb