logstruct 0.1.2 → 0.1.3

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.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -1
  3. data/README.md +4 -6
  4. data/lib/log_struct/concerns/configuration.rb +2 -2
  5. data/lib/log_struct/config_struct/integrations.rb +5 -0
  6. data/lib/log_struct/enums/log_field.rb +12 -1
  7. data/lib/log_struct/integrations/action_mailer/error_handling.rb +121 -27
  8. data/lib/log_struct/integrations/action_mailer/event_logging.rb +30 -14
  9. data/lib/log_struct/integrations/action_mailer/metadata_collection.rb +18 -24
  10. data/lib/log_struct/integrations/action_mailer.rb +13 -6
  11. data/lib/log_struct/integrations/active_job/log_subscriber.rb +2 -2
  12. data/lib/log_struct/integrations/active_storage.rb +8 -8
  13. data/lib/log_struct/integrations/ahoy.rb +2 -3
  14. data/lib/log_struct/integrations/carrierwave.rb +8 -10
  15. data/lib/log_struct/integrations/good_job/log_subscriber.rb +5 -5
  16. data/lib/log_struct/integrations/good_job/logger.rb +2 -6
  17. data/lib/log_struct/integrations/good_job.rb +1 -1
  18. data/lib/log_struct/integrations/host_authorization.rb +27 -36
  19. data/lib/log_struct/integrations/lograge.rb +1 -1
  20. data/lib/log_struct/integrations/shrine.rb +21 -24
  21. data/lib/log_struct/integrations/sidekiq/logger.rb +8 -1
  22. data/lib/log_struct/log/action_mailer/delivered.rb +14 -49
  23. data/lib/log_struct/log/action_mailer/delivery.rb +14 -49
  24. data/lib/log_struct/log/action_mailer/error.rb +72 -0
  25. data/lib/log_struct/log/action_mailer.rb +15 -2
  26. data/lib/log_struct/log/active_job/enqueue.rb +9 -73
  27. data/lib/log_struct/log/active_job/finish.rb +9 -76
  28. data/lib/log_struct/log/active_job/schedule.rb +9 -73
  29. data/lib/log_struct/log/active_job/start.rb +9 -76
  30. data/lib/log_struct/log/active_job.rb +2 -2
  31. data/lib/log_struct/log/active_model_serializers.rb +5 -45
  32. data/lib/log_struct/log/active_storage/delete.rb +8 -46
  33. data/lib/log_struct/log/active_storage/download.rb +9 -55
  34. data/lib/log_struct/log/active_storage/exist.rb +9 -49
  35. data/lib/log_struct/log/active_storage/metadata.rb +9 -49
  36. data/lib/log_struct/log/active_storage/stream.rb +9 -49
  37. data/lib/log_struct/log/active_storage/upload.rb +9 -64
  38. data/lib/log_struct/log/active_storage/url.rb +9 -49
  39. data/lib/log_struct/log/active_storage.rb +2 -2
  40. data/lib/log_struct/log/ahoy.rb +5 -43
  41. data/lib/log_struct/log/carrierwave/delete.rb +15 -69
  42. data/lib/log_struct/log/carrierwave/download.rb +15 -77
  43. data/lib/log_struct/log/carrierwave/upload.rb +15 -83
  44. data/lib/log_struct/log/carrierwave.rb +13 -4
  45. data/lib/log_struct/log/dotenv/load.rb +5 -33
  46. data/lib/log_struct/log/dotenv/restore.rb +5 -33
  47. data/lib/log_struct/log/dotenv/save.rb +5 -33
  48. data/lib/log_struct/log/dotenv/update.rb +5 -33
  49. data/lib/log_struct/log/error.rb +7 -40
  50. data/lib/log_struct/log/good_job/enqueue.rb +9 -72
  51. data/lib/log_struct/log/good_job/error.rb +9 -89
  52. data/lib/log_struct/log/good_job/finish.rb +9 -78
  53. data/lib/log_struct/log/good_job/log.rb +11 -75
  54. data/lib/log_struct/log/good_job/schedule.rb +7 -78
  55. data/lib/log_struct/log/good_job/start.rb +7 -78
  56. data/lib/log_struct/log/good_job.rb +2 -2
  57. data/lib/log_struct/log/plain.rb +5 -32
  58. data/lib/log_struct/log/puma/shutdown.rb +5 -32
  59. data/lib/log_struct/log/puma/start.rb +5 -56
  60. data/lib/log_struct/log/request.rb +7 -90
  61. data/lib/log_struct/log/security/blocked_host.rb +12 -73
  62. data/lib/log_struct/log/security/csrf_violation.rb +6 -67
  63. data/lib/log_struct/log/security/ip_spoof.rb +6 -73
  64. data/lib/log_struct/log/shrine/delete.rb +6 -41
  65. data/lib/log_struct/log/shrine/download.rb +6 -44
  66. data/lib/log_struct/log/shrine/exist.rb +6 -44
  67. data/lib/log_struct/log/shrine/metadata.rb +8 -46
  68. data/lib/log_struct/log/shrine/upload.rb +6 -53
  69. data/lib/log_struct/log/sidekiq.rb +5 -42
  70. data/lib/log_struct/log/sql.rb +5 -65
  71. data/lib/log_struct/log.rb +2 -2
  72. data/lib/log_struct/monkey_patches/active_support/tagged_logging/formatter.rb +12 -1
  73. data/lib/log_struct/railtie.rb +0 -22
  74. data/lib/log_struct/semantic_logger/concerns/log_methods.rb +100 -0
  75. data/lib/log_struct/semantic_logger/logger.rb +46 -15
  76. data/lib/log_struct/semantic_logger/setup.rb +11 -7
  77. data/lib/log_struct/shared/{shared/add_request_fields.rb → add_request_fields.rb} +2 -2
  78. data/lib/log_struct/shared/{shared/merge_additional_data_fields.rb → merge_additional_data_fields.rb} +1 -1
  79. data/lib/log_struct/shared/{shared/serialize_common.rb → serialize_common.rb} +9 -3
  80. data/lib/log_struct/{log/shared → shared}/serialize_common_public.rb +2 -2
  81. data/lib/log_struct/version.rb +1 -1
  82. data/lib/log_struct.rb +4 -1
  83. data/logstruct.gemspec +1 -1
  84. metadata +9 -11
  85. data/lib/log_struct/integrations/action_mailer/callbacks.rb +0 -100
  86. data/lib/log_struct/log/shared/add_request_fields.rb +0 -4
  87. data/lib/log_struct/log/shared/merge_additional_data_fields.rb +0 -4
  88. data/lib/log_struct/log/shared/serialize_common.rb +0 -4
@@ -53,7 +53,7 @@ module LogStruct
53
53
 
54
54
  # Log the store operation with structured data
55
55
  log_data = Log::CarrierWave::Upload.new(
56
- storage: storage.class.name,
56
+ storage: storage.class.name.split("::").last.downcase.to_sym,
57
57
  file_id: identifier,
58
58
  filename: file.filename,
59
59
  mime_type: file.content_type,
@@ -62,11 +62,9 @@ module LogStruct
62
62
  uploader: self.class.name,
63
63
  model: model.class.name,
64
64
  mount_point: mounted_as.to_s,
65
- additional_data: {
66
- version: version_name.to_s,
67
- store_path: store_path,
68
- extension: file.extension
69
- }
65
+ version: version_name.to_s,
66
+ store_path: store_path,
67
+ extension: file.extension
70
68
  )
71
69
 
72
70
  ::Rails.logger.info(log_data)
@@ -85,7 +83,7 @@ module LogStruct
85
83
 
86
84
  # Log the retrieve operation with structured data
87
85
  log_data = Log::CarrierWave::Download.new(
88
- storage: storage.class.name,
86
+ storage: storage.class.name.split("::").last.downcase.to_sym,
89
87
  file_id: identifier,
90
88
  filename: file&.filename,
91
89
  mime_type: file&.content_type,
@@ -94,9 +92,9 @@ module LogStruct
94
92
  uploader: self.class.name,
95
93
  model: model.class.name,
96
94
  mount_point: mounted_as.to_s,
97
- additional_data: {
98
- version: version_name.to_s
99
- }
95
+ version: version_name.to_s,
96
+ store_path: store_path,
97
+ extension: file&.extension
100
98
  )
101
99
 
102
100
  ::Rails.logger.info(log_data)
@@ -49,7 +49,7 @@ module LogStruct
49
49
  **base_fields.to_kwargs,
50
50
  scheduled_at: (job&.scheduled_at ? Time.at(job.scheduled_at.to_i) : nil),
51
51
  duration_ms: event.duration.to_f,
52
- additional_data: {enqueue_caller: job&.enqueue_caller_location},
52
+ enqueue_caller: job&.enqueue_caller_location,
53
53
  timestamp: ts
54
54
  ))
55
55
  end
@@ -91,7 +91,7 @@ module LogStruct
91
91
  finished_at: end_ts,
92
92
  process_id: ::Process.pid,
93
93
  thread_id: Thread.current.object_id.to_s(36),
94
- additional_data: {result: payload[:result]},
94
+ result: payload[:result]&.to_s,
95
95
  timestamp: start_ts
96
96
  ))
97
97
  end
@@ -109,9 +109,9 @@ module LogStruct
109
109
  logger.error(Log::GoodJob::Error.new(
110
110
  **base_fields.to_kwargs,
111
111
  exception_executions: execution&.exception_executions,
112
- err_class: exception&.class&.name,
112
+ error_class: exception&.class&.name,
113
113
  error_message: exception&.message,
114
- backtrace: exception&.backtrace&.first(20),
114
+ backtrace: exception&.backtrace,
115
115
  duration_ms: event.duration.to_f,
116
116
  process_id: ::Process.pid,
117
117
  thread_id: Thread.current.object_id.to_s(36),
@@ -146,7 +146,7 @@ module LogStruct
146
146
  Log::GoodJob::BaseFields.new(
147
147
  job_id: job&.job_id,
148
148
  job_class: job&.job_class,
149
- queue_name: job&.queue_name,
149
+ queue_name: job&.queue_name&.to_sym,
150
150
  arguments: job&.arguments,
151
151
  executions: execution&.executions
152
152
  )
@@ -46,11 +46,6 @@ module LogStruct
46
46
  end
47
47
  end
48
48
 
49
- # Emit a GoodJob::Log event with context and extra fields as additional_data
50
- extras = {}
51
- extras[:scheduled_at] = job_context[:scheduled_at] if job_context.key?(:scheduled_at)
52
- extras[:priority] = job_context[:priority] if job_context.key?(:priority)
53
-
54
49
  log_struct = Log::GoodJob::Log.new(
55
50
  message: message || (block ? block.call : ""),
56
51
  process_id: ::Process.pid,
@@ -59,7 +54,8 @@ module LogStruct
59
54
  job_class: job_context[:job_class],
60
55
  queue_name: job_context[:queue_name],
61
56
  executions: job_context[:executions],
62
- additional_data: extras
57
+ scheduled_at: job_context[:scheduled_at],
58
+ priority: job_context[:priority]
63
59
  )
64
60
 
65
61
  super(log_struct, payload, &nil)
@@ -82,7 +82,7 @@ module LogStruct
82
82
  if goodjob_module.respond_to?(:on_thread_error=)
83
83
  goodjob_module.on_thread_error = ->(exception) do
84
84
  log_entry = LogStruct::Log::GoodJob::Error.new(
85
- err_class: exception.class.name,
85
+ error_class: exception.class.name,
86
86
  error_message: exception.message,
87
87
  backtrace: exception.backtrace,
88
88
  process_id: ::Process.pid,
@@ -3,6 +3,7 @@
3
3
 
4
4
  require "action_dispatch/middleware/host_authorization"
5
5
  require_relative "../enums/event"
6
+ require_relative "../log/security/blocked_host"
6
7
 
7
8
  module LogStruct
8
9
  module Integrations
@@ -34,23 +35,6 @@ module LogStruct
34
35
  return nil unless config.enabled
35
36
  return nil unless config.integrations.enable_host_authorization
36
37
 
37
- # In test environment, ensure HostAuthorization does not block requests
38
- # from the default integration test hosts. Allow all hosts explicitly.
39
- if ::Rails.env.test? && ::Rails.application.config.respond_to?(:hosts)
40
- begin
41
- ::Rails.application.config.hosts << /.*\z/
42
- rescue
43
- # best-effort; ignore if hosts not configurable
44
- end
45
- # Additionally, exclude all requests from HostAuthorization in test
46
- begin
47
- ::Rails.application.config.host_authorization ||= {}
48
- ::Rails.application.config.host_authorization[:exclude] = ->(_request) { true }
49
- rescue
50
- # best-effort
51
- end
52
- end
53
-
54
38
  # Define the response app as a separate variable to fix block alignment
55
39
  response_app = lambda do |env|
56
40
  request = ::ActionDispatch::Request.new(env)
@@ -58,32 +42,39 @@ module LogStruct
58
42
  # This can be helpful later when reviewing logs.
59
43
  blocked_hosts = env["action_dispatch.blocked_hosts"]
60
44
 
61
- # Create a security error to be handled
62
- blocked_host_error = ::ActionController::BadRequest.new(
63
- "Blocked host detected: #{request.host}"
64
- )
45
+ # Build allowed_hosts array
46
+ allowed_hosts_array = T.let(nil, T.nilable(T::Array[String]))
47
+ if blocked_hosts.respond_to?(:allowed_hosts)
48
+ allowed_hosts_array = blocked_hosts.allowed_hosts
49
+ end
50
+
51
+ # Get allow_ip_hosts value
52
+ allow_ip_hosts_value = T.let(nil, T.nilable(T::Boolean))
53
+ if blocked_hosts.respond_to?(:allow_ip_hosts)
54
+ allow_ip_hosts_value = blocked_hosts.allow_ip_hosts
55
+ end
65
56
 
66
- # Create request context hash
67
- context = {
57
+ # Create structured log entry for blocked host
58
+ log_entry = LogStruct::Log::Security::BlockedHost.new(
59
+ message: "Blocked host detected: #{request.host}",
68
60
  blocked_host: request.host,
69
- client_ip: request.ip,
70
- x_forwarded_for: request.x_forwarded_for,
71
- http_method: request.method,
72
61
  path: request.path,
62
+ http_method: request.method,
63
+ source_ip: request.ip,
73
64
  user_agent: request.user_agent,
74
- allowed_hosts: blocked_hosts.allowed_hosts,
75
- allow_ip_hosts: blocked_hosts.allow_ip_hosts
76
- }
77
-
78
- # Handle error according to configured mode (log, report, raise)
79
- LogStruct.handle_exception(
80
- blocked_host_error,
81
- source: Source::Security,
82
- context: context
65
+ referer: request.referer,
66
+ request_id: request.request_id,
67
+ x_forwarded_for: request.x_forwarded_for,
68
+ allowed_hosts: allowed_hosts_array&.empty? ? nil : allowed_hosts_array,
69
+ allow_ip_hosts: allow_ip_hosts_value
83
70
  )
84
71
 
72
+ # Log the blocked host
73
+ LogStruct.warn(log_entry)
74
+
85
75
  # Use pre-defined headers and response if we are only logging or reporting
86
- [FORBIDDEN_STATUS, RESPONSE_HEADERS, [RESPONSE_HTML]]
76
+ # Dup the headers so they can be modified by downstream middleware
77
+ [FORBIDDEN_STATUS, RESPONSE_HEADERS.dup, [RESPONSE_HTML]]
87
78
  end
88
79
 
89
80
  # Merge our response_app into existing host_authorization config to preserve excludes
@@ -50,7 +50,7 @@ module LogStruct
50
50
  Log::Request.new(
51
51
  http_method: data[:method]&.to_s,
52
52
  path: data[:path]&.to_s,
53
- format: data[:format]&.to_s,
53
+ format: data[:format]&.to_sym,
54
54
  controller: data[:controller]&.to_s,
55
55
  action: data[:action]&.to_s,
56
56
  status: status,
@@ -37,50 +37,47 @@ module LogStruct
37
37
  end
38
38
 
39
39
  # Create structured log data
40
+ # Ensure storage is always a symbol
41
+ storage_sym = payload[:storage].to_sym
42
+
40
43
  log_data = case event_type
41
44
  when Event::Upload
42
45
  Log::Shrine::Upload.new(
43
- storage: payload[:storage],
46
+ storage: storage_sym,
44
47
  location: payload[:location],
45
- uploader: payload[:uploader],
48
+ uploader: payload[:uploader]&.to_s,
46
49
  upload_options: payload[:upload_options],
47
50
  options: payload[:options],
48
- duration_ms: event.duration,
49
- additional_data: payload.except(:storage, :location, :uploader, :upload_options, :options)
51
+ duration_ms: event.duration.to_f
50
52
  )
51
53
  when Event::Download
52
54
  Log::Shrine::Download.new(
53
- storage: payload[:storage],
55
+ storage: storage_sym,
54
56
  location: payload[:location],
55
- download_options: payload[:download_options],
56
- additional_data: payload.except(:storage, :location, :download_options)
57
+ download_options: payload[:download_options]
57
58
  )
58
59
  when Event::Delete
59
60
  Log::Shrine::Delete.new(
60
- storage: payload[:storage],
61
- location: payload[:location],
62
- additional_data: payload.except(:storage, :location)
61
+ storage: storage_sym,
62
+ location: payload[:location]
63
63
  )
64
64
  when Event::Metadata
65
- Log::Shrine::Metadata.new(
66
- storage: payload[:storage],
67
- location: payload[:location],
68
- metadata: payload[:metadata],
69
- additional_data: payload.except(:storage, :location, :metadata)
70
- )
65
+ metadata_params = {
66
+ storage: storage_sym,
67
+ metadata: payload[:metadata]
68
+ }
69
+ metadata_params[:location] = payload[:location] if payload[:location]
70
+ Log::Shrine::Metadata.new(**metadata_params)
71
71
  when Event::Exist
72
72
  Log::Shrine::Exist.new(
73
- storage: payload[:storage],
73
+ storage: storage_sym,
74
74
  location: payload[:location],
75
- exist: payload[:exist],
76
- additional_data: payload.except(:storage, :location, :exist)
75
+ exist: payload[:exist]
77
76
  )
78
77
  else
79
- Log::Shrine::Metadata.new(
80
- storage: payload[:storage],
81
- location: payload[:location],
82
- metadata: payload[:metadata]
83
- )
78
+ unknown_params = {storage: storage_sym, metadata: payload[:metadata]}
79
+ unknown_params[:location] = payload[:location] if payload[:location]
80
+ Log::Shrine::Metadata.new(**unknown_params)
84
81
  end
85
82
 
86
83
  # Pass the structured hash to the logger
@@ -23,11 +23,18 @@ module LogStruct
23
23
  # Override log methods to create Sidekiq log structs
24
24
  %i[debug info warn error fatal].each do |level|
25
25
  define_method(level) do |message = nil, payload = nil, &block|
26
+ # Ensure message is a String (Sidekiq may pass Hash for config logs)
27
+ msg = if message.nil?
28
+ block ? block.call.to_s : ""
29
+ else
30
+ message.to_s
31
+ end
32
+
26
33
  # Create a Sidekiq log struct with the message
27
34
  log_struct = Log::Sidekiq.new(
28
35
  level: LogStruct::Level.from_severity(level.to_s.upcase),
29
36
  event: Event::Log,
30
- message: message || (block ? block.call : ""),
37
+ message: msg,
31
38
  process_id: ::Process.pid,
32
39
  thread_id: Sidekiq.tid,
33
40
  context: ::Sidekiq::Context.current || {}
@@ -9,9 +9,9 @@
9
9
  require "log_struct/shared/interfaces/common_fields"
10
10
  require "log_struct/shared/interfaces/additional_data_field"
11
11
  require "log_struct/shared/interfaces/request_fields"
12
- require "log_struct/shared/shared/serialize_common"
13
- require "log_struct/shared/shared/merge_additional_data_fields"
14
- require "log_struct/shared/shared/add_request_fields"
12
+ require "log_struct/shared/serialize_common"
13
+ require "log_struct/shared/merge_additional_data_fields"
14
+ require "log_struct/shared/add_request_fields"
15
15
  require_relative "../../enums/source"
16
16
  require_relative "../../enums/event"
17
17
  require_relative "../../enums/level"
@@ -21,11 +21,6 @@ module LogStruct
21
21
  module Log
22
22
  class ActionMailer
23
23
  class Delivered < T::Struct
24
- # typed: strict
25
- # frozen_string_literal: true
26
-
27
- extend T::Sig
28
-
29
24
  extend T::Sig
30
25
 
31
26
  # Shared/common fields
@@ -37,62 +32,32 @@ module LogStruct
37
32
  const :to, T.nilable(T::Array[String]), default: nil
38
33
  const :from, T.nilable(String), default: nil
39
34
  const :subject, T.nilable(String), default: nil
40
-
41
- # Event-specific fields
35
+ const :message_id, T.nilable(String), default: nil
36
+ const :mailer_class, T.nilable(String), default: nil
37
+ const :mailer_action, T.nilable(String), default: nil
38
+ const :attachment_count, T.nilable(Integer), default: nil
42
39
 
43
40
  # Additional data
44
41
  include LogStruct::Log::Interfaces::AdditionalDataField
45
42
  const :additional_data, T.nilable(T::Hash[T.any(String, Symbol), T.untyped]), default: nil
46
43
  include LogStruct::Log::Shared::MergeAdditionalDataFields
47
44
 
48
- # Request fields (optional)
49
-
50
45
  # Serialize shared fields
51
46
  include LogStruct::Log::Interfaces::CommonFields
52
47
  include LogStruct::Log::Shared::SerializeCommon
53
48
 
54
- sig {
55
- params(to: T.untyped,
56
- from: T.untyped,
57
- subject: T.untyped).returns(T::Hash[LogStruct::LogField, T.untyped])
58
- }
59
- def self.base_hash(to: nil,
60
- from: nil,
61
- subject: nil)
62
- h = {}
49
+ sig { returns(T::Hash[LogStruct::LogField, T.untyped]) }
50
+ def to_h
51
+ h = T.let({}, T::Hash[LogStruct::LogField, T.untyped])
63
52
  h[LogField::To] = to unless to.nil?
64
53
  h[LogField::From] = from unless from.nil?
65
54
  h[LogField::Subject] = subject unless subject.nil?
55
+ h[LogField::MessageId] = message_id unless message_id.nil?
56
+ h[LogField::MailerClass] = mailer_class unless mailer_class.nil?
57
+ h[LogField::MailerAction] = mailer_action unless mailer_action.nil?
58
+ h[LogField::AttachmentCount] = attachment_count unless attachment_count.nil?
66
59
  h
67
60
  end
68
-
69
- sig {
70
- params(to: T.untyped,
71
- from: T.untyped,
72
- subject: T.untyped,
73
- additional_data: T.untyped,
74
- timestamp: T.untyped).returns(T::Hash[LogStruct::LogField, T.untyped])
75
- }
76
- def self.build(to: nil,
77
- from: nil,
78
- subject: nil,
79
- additional_data: nil,
80
- timestamp: Time.now)
81
- base_hash(to: to,
82
- from: from,
83
- subject: subject)
84
- end
85
-
86
- sig { returns(T::Hash[LogStruct::LogField, T.untyped]) }
87
- def to_h
88
- self.class.build(
89
- to: to,
90
- from: from,
91
- subject: subject,
92
- additional_data: additional_data,
93
- timestamp: timestamp
94
- )
95
- end
96
61
  end
97
62
  end
98
63
  end
@@ -9,9 +9,9 @@
9
9
  require "log_struct/shared/interfaces/common_fields"
10
10
  require "log_struct/shared/interfaces/additional_data_field"
11
11
  require "log_struct/shared/interfaces/request_fields"
12
- require "log_struct/shared/shared/serialize_common"
13
- require "log_struct/shared/shared/merge_additional_data_fields"
14
- require "log_struct/shared/shared/add_request_fields"
12
+ require "log_struct/shared/serialize_common"
13
+ require "log_struct/shared/merge_additional_data_fields"
14
+ require "log_struct/shared/add_request_fields"
15
15
  require_relative "../../enums/source"
16
16
  require_relative "../../enums/event"
17
17
  require_relative "../../enums/level"
@@ -21,11 +21,6 @@ module LogStruct
21
21
  module Log
22
22
  class ActionMailer
23
23
  class Delivery < T::Struct
24
- # typed: strict
25
- # frozen_string_literal: true
26
-
27
- extend T::Sig
28
-
29
24
  extend T::Sig
30
25
 
31
26
  # Shared/common fields
@@ -37,62 +32,32 @@ module LogStruct
37
32
  const :to, T.nilable(T::Array[String]), default: nil
38
33
  const :from, T.nilable(String), default: nil
39
34
  const :subject, T.nilable(String), default: nil
40
-
41
- # Event-specific fields
35
+ const :message_id, T.nilable(String), default: nil
36
+ const :mailer_class, T.nilable(String), default: nil
37
+ const :mailer_action, T.nilable(String), default: nil
38
+ const :attachment_count, T.nilable(Integer), default: nil
42
39
 
43
40
  # Additional data
44
41
  include LogStruct::Log::Interfaces::AdditionalDataField
45
42
  const :additional_data, T.nilable(T::Hash[T.any(String, Symbol), T.untyped]), default: nil
46
43
  include LogStruct::Log::Shared::MergeAdditionalDataFields
47
44
 
48
- # Request fields (optional)
49
-
50
45
  # Serialize shared fields
51
46
  include LogStruct::Log::Interfaces::CommonFields
52
47
  include LogStruct::Log::Shared::SerializeCommon
53
48
 
54
- sig {
55
- params(to: T.untyped,
56
- from: T.untyped,
57
- subject: T.untyped).returns(T::Hash[LogStruct::LogField, T.untyped])
58
- }
59
- def self.base_hash(to: nil,
60
- from: nil,
61
- subject: nil)
62
- h = {}
49
+ sig { returns(T::Hash[LogStruct::LogField, T.untyped]) }
50
+ def to_h
51
+ h = T.let({}, T::Hash[LogStruct::LogField, T.untyped])
63
52
  h[LogField::To] = to unless to.nil?
64
53
  h[LogField::From] = from unless from.nil?
65
54
  h[LogField::Subject] = subject unless subject.nil?
55
+ h[LogField::MessageId] = message_id unless message_id.nil?
56
+ h[LogField::MailerClass] = mailer_class unless mailer_class.nil?
57
+ h[LogField::MailerAction] = mailer_action unless mailer_action.nil?
58
+ h[LogField::AttachmentCount] = attachment_count unless attachment_count.nil?
66
59
  h
67
60
  end
68
-
69
- sig {
70
- params(to: T.untyped,
71
- from: T.untyped,
72
- subject: T.untyped,
73
- additional_data: T.untyped,
74
- timestamp: T.untyped).returns(T::Hash[LogStruct::LogField, T.untyped])
75
- }
76
- def self.build(to: nil,
77
- from: nil,
78
- subject: nil,
79
- additional_data: nil,
80
- timestamp: Time.now)
81
- base_hash(to: to,
82
- from: from,
83
- subject: subject)
84
- end
85
-
86
- sig { returns(T::Hash[LogStruct::LogField, T.untyped]) }
87
- def to_h
88
- self.class.build(
89
- to: to,
90
- from: from,
91
- subject: subject,
92
- additional_data: additional_data,
93
- timestamp: timestamp
94
- )
95
- end
96
61
  end
97
62
  end
98
63
  end
@@ -0,0 +1,72 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ # AUTO-GENERATED: DO NOT EDIT
5
+ # Generated by scripts/generate_structs.rb
6
+ # Schemas dir: schemas/log_sources/
7
+ # Template: tools/codegen/templates/sorbet/event.rb.erb
8
+
9
+ require "log_struct/shared/interfaces/common_fields"
10
+ require "log_struct/shared/interfaces/additional_data_field"
11
+ require "log_struct/shared/interfaces/request_fields"
12
+ require "log_struct/shared/serialize_common"
13
+ require "log_struct/shared/merge_additional_data_fields"
14
+ require "log_struct/shared/add_request_fields"
15
+ require_relative "../../enums/source"
16
+ require_relative "../../enums/event"
17
+ require_relative "../../enums/level"
18
+ require_relative "../../enums/log_field"
19
+
20
+ module LogStruct
21
+ module Log
22
+ class ActionMailer
23
+ class Error < T::Struct
24
+ extend T::Sig
25
+
26
+ # Shared/common fields
27
+ const :source, Source::Mailer, default: Source::Mailer
28
+ const :event, Event, default: Event::Error
29
+ const :timestamp, Time, factory: -> { Time.now }
30
+ const :level, Level, default: Level::Info
31
+
32
+ const :to, T.nilable(T::Array[String]), default: nil
33
+ const :from, T.nilable(String), default: nil
34
+ const :subject, T.nilable(String), default: nil
35
+ const :message_id, T.nilable(String), default: nil
36
+ const :mailer_class, T.nilable(String), default: nil
37
+ const :mailer_action, T.nilable(String), default: nil
38
+ const :attachment_count, T.nilable(Integer), default: nil
39
+
40
+ # Event-specific fields
41
+ const :error_class, T.class_of(StandardError)
42
+ const :message, String
43
+ const :backtrace, T.nilable(T::Array[String]), default: nil
44
+
45
+ # Additional data
46
+ include LogStruct::Log::Interfaces::AdditionalDataField
47
+ const :additional_data, T.nilable(T::Hash[T.any(String, Symbol), T.untyped]), default: nil
48
+ include LogStruct::Log::Shared::MergeAdditionalDataFields
49
+
50
+ # Serialize shared fields
51
+ include LogStruct::Log::Interfaces::CommonFields
52
+ include LogStruct::Log::Shared::SerializeCommon
53
+
54
+ sig { returns(T::Hash[LogStruct::LogField, T.untyped]) }
55
+ def to_h
56
+ h = T.let({}, T::Hash[LogStruct::LogField, T.untyped])
57
+ h[LogField::To] = to unless to.nil?
58
+ h[LogField::From] = from unless from.nil?
59
+ h[LogField::Subject] = subject unless subject.nil?
60
+ h[LogField::MessageId] = message_id unless message_id.nil?
61
+ h[LogField::MailerClass] = mailer_class unless mailer_class.nil?
62
+ h[LogField::MailerAction] = mailer_action unless mailer_action.nil?
63
+ h[LogField::AttachmentCount] = attachment_count unless attachment_count.nil?
64
+ h[LogField::ErrorClass] = error_class
65
+ h[LogField::Message] = message
66
+ h[LogField::Backtrace] = backtrace unless backtrace.nil?
67
+ h
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -8,6 +8,7 @@
8
8
 
9
9
  require_relative "action_mailer/delivery"
10
10
  require_relative "action_mailer/delivered"
11
+ require_relative "action_mailer/error"
11
12
 
12
13
  module LogStruct
13
14
  module Log
@@ -17,12 +18,20 @@ module LogStruct
17
18
  const :to, T.nilable(T::Array[String]), default: nil
18
19
  const :from, T.nilable(String), default: nil
19
20
  const :subject, T.nilable(String), default: nil
21
+ const :message_id, T.nilable(String), default: nil
22
+ const :mailer_class, T.nilable(String), default: nil
23
+ const :mailer_action, T.nilable(String), default: nil
24
+ const :attachment_count, T.nilable(Integer), default: nil
20
25
 
21
26
  Kwargs = T.type_alias do
22
27
  {
23
28
  to: T.nilable(T::Array[String]),
24
29
  from: T.nilable(String),
25
- subject: T.nilable(String)
30
+ subject: T.nilable(String),
31
+ message_id: T.nilable(String),
32
+ mailer_class: T.nilable(String),
33
+ mailer_action: T.nilable(String),
34
+ attachment_count: T.nilable(Integer)
26
35
  }
27
36
  end
28
37
 
@@ -31,7 +40,11 @@ module LogStruct
31
40
  {
32
41
  to: to,
33
42
  from: from,
34
- subject: subject
43
+ subject: subject,
44
+ message_id: message_id,
45
+ mailer_class: mailer_class,
46
+ mailer_action: mailer_action,
47
+ attachment_count: attachment_count
35
48
  }
36
49
  end
37
50
  end