logstruct 0.0.1 → 0.0.2.pre.rc1

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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +26 -2
  3. data/LICENSE +21 -0
  4. data/README.md +67 -0
  5. data/lib/log_struct/concerns/configuration.rb +93 -0
  6. data/lib/log_struct/concerns/error_handling.rb +94 -0
  7. data/lib/log_struct/concerns/logging.rb +45 -0
  8. data/lib/log_struct/config_struct/error_handling_modes.rb +25 -0
  9. data/lib/log_struct/config_struct/filters.rb +80 -0
  10. data/lib/log_struct/config_struct/integrations.rb +89 -0
  11. data/lib/log_struct/configuration.rb +59 -0
  12. data/lib/log_struct/enums/error_handling_mode.rb +22 -0
  13. data/lib/log_struct/enums/error_reporter.rb +14 -0
  14. data/lib/log_struct/enums/event.rb +48 -0
  15. data/lib/log_struct/enums/level.rb +66 -0
  16. data/lib/log_struct/enums/source.rb +26 -0
  17. data/lib/log_struct/enums.rb +9 -0
  18. data/lib/log_struct/formatter.rb +224 -0
  19. data/lib/log_struct/handlers.rb +27 -0
  20. data/lib/log_struct/hash_utils.rb +21 -0
  21. data/lib/log_struct/integrations/action_mailer/callbacks.rb +100 -0
  22. data/lib/log_struct/integrations/action_mailer/error_handling.rb +173 -0
  23. data/lib/log_struct/integrations/action_mailer/event_logging.rb +90 -0
  24. data/lib/log_struct/integrations/action_mailer/metadata_collection.rb +78 -0
  25. data/lib/log_struct/integrations/action_mailer.rb +50 -0
  26. data/lib/log_struct/integrations/active_job/log_subscriber.rb +104 -0
  27. data/lib/log_struct/integrations/active_job.rb +38 -0
  28. data/lib/log_struct/integrations/active_record.rb +258 -0
  29. data/lib/log_struct/integrations/active_storage.rb +94 -0
  30. data/lib/log_struct/integrations/carrierwave.rb +111 -0
  31. data/lib/log_struct/integrations/good_job/log_subscriber.rb +228 -0
  32. data/lib/log_struct/integrations/good_job/logger.rb +73 -0
  33. data/lib/log_struct/integrations/good_job.rb +111 -0
  34. data/lib/log_struct/integrations/host_authorization.rb +81 -0
  35. data/lib/log_struct/integrations/integration_interface.rb +21 -0
  36. data/lib/log_struct/integrations/lograge.rb +114 -0
  37. data/lib/log_struct/integrations/rack.rb +31 -0
  38. data/lib/log_struct/integrations/rack_error_handler/middleware.rb +146 -0
  39. data/lib/log_struct/integrations/rack_error_handler.rb +32 -0
  40. data/lib/log_struct/integrations/shrine.rb +75 -0
  41. data/lib/log_struct/integrations/sidekiq/logger.rb +43 -0
  42. data/lib/log_struct/integrations/sidekiq.rb +39 -0
  43. data/lib/log_struct/integrations/sorbet.rb +49 -0
  44. data/lib/log_struct/integrations.rb +41 -0
  45. data/lib/log_struct/log/action_mailer.rb +55 -0
  46. data/lib/log_struct/log/active_job.rb +64 -0
  47. data/lib/log_struct/log/active_storage.rb +78 -0
  48. data/lib/log_struct/log/carrierwave.rb +82 -0
  49. data/lib/log_struct/log/error.rb +76 -0
  50. data/lib/log_struct/log/good_job.rb +151 -0
  51. data/lib/log_struct/log/interfaces/additional_data_field.rb +20 -0
  52. data/lib/log_struct/log/interfaces/common_fields.rb +42 -0
  53. data/lib/log_struct/log/interfaces/message_field.rb +20 -0
  54. data/lib/log_struct/log/interfaces/request_fields.rb +36 -0
  55. data/lib/log_struct/log/plain.rb +53 -0
  56. data/lib/log_struct/log/request.rb +76 -0
  57. data/lib/log_struct/log/security.rb +80 -0
  58. data/lib/log_struct/log/shared/add_request_fields.rb +29 -0
  59. data/lib/log_struct/log/shared/merge_additional_data_fields.rb +28 -0
  60. data/lib/log_struct/log/shared/serialize_common.rb +36 -0
  61. data/lib/log_struct/log/shrine.rb +70 -0
  62. data/lib/log_struct/log/sidekiq.rb +50 -0
  63. data/lib/log_struct/log/sql.rb +126 -0
  64. data/lib/log_struct/log.rb +43 -0
  65. data/lib/log_struct/log_keys.rb +102 -0
  66. data/lib/log_struct/monkey_patches/active_support/tagged_logging/formatter.rb +36 -0
  67. data/lib/log_struct/multi_error_reporter.rb +149 -0
  68. data/lib/log_struct/param_filters.rb +89 -0
  69. data/lib/log_struct/railtie.rb +31 -0
  70. data/lib/log_struct/semantic_logger/color_formatter.rb +209 -0
  71. data/lib/log_struct/semantic_logger/formatter.rb +94 -0
  72. data/lib/log_struct/semantic_logger/logger.rb +129 -0
  73. data/lib/log_struct/semantic_logger/setup.rb +219 -0
  74. data/lib/log_struct/sorbet/serialize_symbol_keys.rb +23 -0
  75. data/lib/log_struct/sorbet.rb +13 -0
  76. data/lib/log_struct/string_scrubber.rb +84 -0
  77. data/lib/log_struct/version.rb +6 -0
  78. data/lib/log_struct.rb +37 -0
  79. data/lib/logstruct.rb +2 -6
  80. data/logstruct.gemspec +52 -0
  81. metadata +221 -5
  82. data/Rakefile +0 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8dff0c6b2f4200e2699a4a62c6770ab74daeb3e334cd19864900302d8304fd66
4
- data.tar.gz: 9ae935a538a100f2b86dd75b2ef6678875b9cd9cf3590f22eb70b367e28a61be
3
+ metadata.gz: 3ce0ec5e8973926358ab0282f61945eb85bbaead27060a16b00e85685b2b83f2
4
+ data.tar.gz: d5146c601563992a8b426f8bcfea1db40d631995c7e16d7a771e98b78010c2ce
5
5
  SHA512:
6
- metadata.gz: 4d1500f3e9be588f0deaf313895721741c1e0b04e5ad57560c21f6f1df09796c399c7f73ce60b0f30889056d3c97cf27c0015fcdfc8abefedd6b89d4a45b6f11
7
- data.tar.gz: '0855b2fc13820466bd95f4dde5d27ad9c6d3babdc29277615533ae519998bea79c81260217ccd3f6ed7801d6da86837ea6475496a52421befcf90b00c4d30b6c'
6
+ metadata.gz: 0e30c656d03a93056e85e750189277007c05737f123d0b576b9f600f75a9b48dd3ff45fdf82e3990a8b9541793dd6402013f8bf982f0addc8f1191dcc4a32fe0
7
+ data.tar.gz: fe24218d1771ff69ecf9a4d2fd8901aed19472ee02c38e2e14f87d0c0c3293887492b1e038f79e0985d4be6350a402c544db4bf28cf718a4a8229e61dd98f6e8
data/CHANGELOG.md CHANGED
@@ -1,8 +1,32 @@
1
1
  # Changelog
2
2
 
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
3
8
  ## [0.0.1] - 2025-03-04
4
9
 
5
10
  ### Added
6
11
 
7
- - Initial release to secure name on RubyGems.org
8
- - Basic LogStruct module with version constant
12
+ - Pushed empty gem to RubyGems to secure the name
13
+
14
+ ## [0.0.2-rc1] - 2025-09-05
15
+
16
+ ### Added
17
+
18
+ - Unified GitHub Actions workflow to release RubyGem and sync/tag the Terraform provider; dry-run support for safe validation
19
+ - Provider catalog export script and automated provider CI (build/vet/test)
20
+ - Terraform docs page with quickstart, recipes, and provider README link
21
+ - API design doc (typed vs. untyped) planned; initial philosophy captured
22
+ - Coverage threshold gate (>= 80%) in CI; additional tests to lift coverage
23
+ - Release helper: scripts/create_release_tag.sh (creates annotated tag from version.rb)
24
+
25
+ ### Changed
26
+
27
+ - ActionMailer callbacks patched for Rails 7.0; event logging + metadata collection tested
28
+ - Provider CloudWatch filter builder refactored for testability; key lookups aligned with exported catalog (event/source)
29
+
30
+ ### Fixed
31
+
32
+ - Pre-commit hooks reporting; cspell dictionary updated; TypeScript import fixes in site
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 DocSpring Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,67 @@
1
+ # LogStruct
2
+
3
+ Adds JSON structured logging to any Rails app. Simply add the gem to your Gemfile and add an initializer to configure it. By default, your Rails app prints JSON logs to STDOUT (or to the configured destination when `RAILS_LOG_TO_STDOUT` is set). They're easy to search and filter, you can turn them into metrics and alerts, and they're great for building dashboards in CloudWatch, Grafana, or Datadog.
4
+
5
+ We support all your other favorite gems too, like Sidekiq, Sentry, and Shrine. (And if not, please open a PR!)
6
+
7
+ ## Features
8
+
9
+ - JSON logging enabled by default in production and test environments
10
+ - ActionMailer integration for email delivery logging
11
+ - ActiveJob integration for job execution logging
12
+ - Sidekiq integration for background job logging
13
+ - Shrine integration for file upload logging
14
+ - Error handling and reporting
15
+ - Metadata collection for rich context
16
+ - Lograge integration for structured request logging
17
+ - Sensitive data scrubbing for strings (inspired by the Logstop gem)
18
+ - Host authorization logging for security violations
19
+ - Rack middleware for enhanced error logging
20
+ - ActionMailer delivery callbacks for Rails 7.0.x (backported from Rails 7.1)
21
+ - Type checking with Sorbet and RBS annotations
22
+
23
+ ## Installation
24
+
25
+ Add this line to your application's Gemfile:
26
+
27
+ ```ruby
28
+ gem 'logstruct'
29
+ ```
30
+
31
+ And then execute:
32
+
33
+ ```bash
34
+ $ bundle install
35
+ ```
36
+
37
+ Or install it yourself as:
38
+
39
+ ```bash
40
+ $ gem install logstruct
41
+ ```
42
+
43
+ ## Configuration and Initialization
44
+
45
+ LogStruct is designed to be highly opinionated and work out of the box with minimal configuration.
46
+
47
+ Please see the [documentation](https://logstruct.com/docs/configuration/) for configuration options.
48
+
49
+ ### Important Notes on Integration
50
+
51
+ Once initialized, the gem automatically includes its modules into the appropriate base classes:
52
+
53
+ - `ActiveSupport::TaggedLogging` is patched to support both Hashes and Strings
54
+ - `ActionMailer::Base` includes error handling and event logging modules
55
+ - We configure `Lograge` for request logging
56
+ - A Rack middleware is inserted to catch and log errors, including security violations (IP spoofing, CSRF, blocked hosts, etc.)
57
+ - Structured logging is set up for ActiveJob, Sidekiq, Shrine, etc.
58
+ - Rails `config.filter_parameters` are merged into LogStruct's filters and then cleared (to avoid double filtering). Configure sensitive keys via `LogStruct.config.filters`.
59
+ - When `RAILS_LOG_TO_STDOUT` is set, we log to STDOUT only. Otherwise, we log to STDOUT by default without adding a file appender to avoid duplicate logs.
60
+
61
+ ## Documentation
62
+
63
+ Please see the [documentation](https://logstruct.com/docs) for more details. (All code examples are type-checked and tested, and it's harder to keep a README up to date.)
64
+
65
+ ## License
66
+
67
+ This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
@@ -0,0 +1,93 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "../configuration"
5
+
6
+ module LogStruct
7
+ module Concerns
8
+ # Concern for handling errors according to configured modes
9
+ module Configuration
10
+ module ClassMethods
11
+ extend T::Sig
12
+
13
+ sig { params(block: T.proc.params(config: LogStruct::Configuration).void).void }
14
+ def configure(&block)
15
+ yield(config)
16
+ end
17
+
18
+ sig { returns(LogStruct::Configuration) }
19
+ def config
20
+ LogStruct::Configuration.instance
21
+ end
22
+
23
+ # (Can't use alias_method since this module is extended into LogStruct)
24
+ sig { returns(LogStruct::Configuration) }
25
+ def configuration
26
+ config
27
+ end
28
+
29
+ # Setter method to replace the configuration (for testing purposes)
30
+ sig { params(config: LogStruct::Configuration).void }
31
+ def configuration=(config)
32
+ LogStruct::Configuration.set_instance(config)
33
+ end
34
+
35
+ sig { returns(T::Boolean) }
36
+ def enabled?
37
+ config.enabled
38
+ end
39
+
40
+ sig { void }
41
+ def set_enabled_from_rails_env!
42
+ # Set enabled based on current Rails environment and the LOGSTRUCT_ENABLED env var.
43
+ # Precedence:
44
+ # 1. Check if LOGSTRUCT_ENABLED env var is defined
45
+ # - Sets enabled=true only when value is "true"
46
+ # - Sets enabled=false when value is "false" (or any non-"true")
47
+ # 2. Otherwise, check if current Rails environment is in enabled_environments
48
+ # 3. Otherwise, leave as config.enabled (defaults to true)
49
+
50
+ # Then check if LOGSTRUCT_ENABLED env var is set
51
+ config.enabled = if ENV["LOGSTRUCT_ENABLED"]
52
+ # Override to true only if env var is "true"
53
+ ENV["LOGSTRUCT_ENABLED"] == "true"
54
+ else
55
+ config.enabled_environments.include?(::Rails.env.to_sym)
56
+ end
57
+ end
58
+
59
+ sig { returns(T::Boolean) }
60
+ def is_local?
61
+ config.local_environments.include?(::Rails.env.to_sym)
62
+ end
63
+
64
+ sig { returns(T::Boolean) }
65
+ def is_production?
66
+ !is_local?
67
+ end
68
+
69
+ sig { void }
70
+ def merge_rails_filter_parameters!
71
+ return unless ::Rails.application.config.respond_to?(:filter_parameters)
72
+
73
+ rails_filter_params = ::Rails.application.config.filter_parameters
74
+ return unless rails_filter_params.is_a?(Array)
75
+
76
+ # Convert all Rails filter parameters to symbols and merge with our filter keys
77
+ converted_params = rails_filter_params.map do |param|
78
+ param.respond_to?(:to_sym) ? param.to_sym : param
79
+ end
80
+
81
+ # Add Rails filter parameters to our filter keys
82
+ config.filters.filter_keys += converted_params
83
+
84
+ # Ensure no duplicates
85
+ config.filters.filter_keys.uniq!
86
+
87
+ # Clear Rails filter parameters since we've incorporated them
88
+ ::Rails.application.config.filter_parameters.clear
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,94 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module LogStruct
5
+ module Concerns
6
+ # Concern for handling errors according to configured modes
7
+ module ErrorHandling
8
+ module ClassMethods
9
+ extend T::Sig
10
+ extend T::Helpers
11
+
12
+ # Needed for raise
13
+ requires_ancestor { Module }
14
+
15
+ # Get the error handling mode for a given source
16
+ sig { params(source: Source).returns(ErrorHandlingMode) }
17
+ def error_handling_mode_for(source)
18
+ config = LogStruct.config
19
+
20
+ # Use a case statement for type-safety
21
+ case source
22
+ when Source::TypeChecking
23
+ config.error_handling_modes.type_checking_errors
24
+ when Source::LogStruct
25
+ config.error_handling_modes.logstruct_errors
26
+ when Source::Security
27
+ config.error_handling_modes.security_errors
28
+ when Source::Rails, Source::App, Source::Job, Source::Storage, Source::Mailer,
29
+ Source::Shrine, Source::CarrierWave, Source::Sidekiq
30
+ config.error_handling_modes.standard_errors
31
+ else
32
+ # Ensures the case statement is exhaustive
33
+ T.absurd(source)
34
+ end
35
+ end
36
+
37
+ # Log an errors with structured data
38
+ sig { params(error: StandardError, source: Source, context: T.nilable(T::Hash[Symbol, T.untyped])).void }
39
+ def log_error(error, source:, context: nil)
40
+ # Create structured log entry
41
+ error_log = Log::Error.from_exception(
42
+ source,
43
+ error,
44
+ context || {}
45
+ )
46
+ LogStruct.error(error_log)
47
+ end
48
+
49
+ # Report an error using the configured handler or MultiErrorReporter
50
+ sig { params(error: StandardError, source: Source, context: T.nilable(T::Hash[Symbol, T.untyped])).void }
51
+ def log_and_report_error(error, source:, context: nil)
52
+ log_error(error, source: source, context: context)
53
+ error_handler = LogStruct.config.error_reporting_handler
54
+ if error_handler
55
+ # Use the configured handler
56
+ error_handler.call(error, context, source)
57
+ else
58
+ # Fall back to MultiErrorReporter (detects Sentry, Bugsnag, etc.)
59
+ LogStruct::MultiErrorReporter.report_error(error, context || {})
60
+ end
61
+ end
62
+
63
+ # Handle an error according to the configured error handling mode (log, report, raise, etc)
64
+ sig { params(error: StandardError, source: Source, context: T.nilable(T::Hash[Symbol, T.untyped])).void }
65
+ def handle_exception(error, source:, context: nil)
66
+ mode = error_handling_mode_for(source)
67
+
68
+ # Log / report in production, raise locally (dev/test)
69
+ if mode == ErrorHandlingMode::LogProduction || mode == ErrorHandlingMode::ReportProduction
70
+ raise(error) if !LogStruct.is_production?
71
+ end
72
+
73
+ case mode
74
+ when ErrorHandlingMode::Ignore
75
+ # Do nothing
76
+
77
+ when ErrorHandlingMode::Raise
78
+ raise(error)
79
+
80
+ when ErrorHandlingMode::Log, ErrorHandlingMode::LogProduction
81
+ log_error(error, source: source, context: context)
82
+
83
+ when ErrorHandlingMode::Report, ErrorHandlingMode::ReportProduction
84
+ log_and_report_error(error, source: source, context: context)
85
+
86
+ else
87
+ # Ensures the case statement is exhaustive
88
+ T.absurd(mode)
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,45 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "../log"
5
+
6
+ module LogStruct
7
+ module Concerns
8
+ # Concern for handling errors according to configured modes
9
+ module Logging
10
+ module ClassMethods
11
+ extend T::Sig
12
+
13
+ # Log a log struct at debug level
14
+ sig { params(log: Log::Interfaces::CommonFields).void }
15
+ def debug(log)
16
+ Rails.logger.debug(log)
17
+ end
18
+
19
+ # Log a log struct at info level
20
+ sig { params(log: Log::Interfaces::CommonFields).void }
21
+ def info(log)
22
+ Rails.logger.info(log)
23
+ end
24
+
25
+ # Log a log struct at warn level
26
+ sig { params(log: Log::Interfaces::CommonFields).void }
27
+ def warn(log)
28
+ Rails.logger.warn(log)
29
+ end
30
+
31
+ # Log a log struct at error level
32
+ sig { params(log: Log::Interfaces::CommonFields).void }
33
+ def error(log)
34
+ Rails.logger.error(log)
35
+ end
36
+
37
+ # Log a log struct at fatal level
38
+ sig { params(log: Log::Interfaces::CommonFields).void }
39
+ def fatal(log)
40
+ Rails.logger.fatal(log)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,25 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module LogStruct
5
+ module ConfigStruct
6
+ class ErrorHandlingModes < T::Struct
7
+ include Sorbet::SerializeSymbolKeys
8
+
9
+ # How to handle different types of errors
10
+ # Modes:
11
+ # - Ignore - Ignore the error
12
+ # - Log - Log the error
13
+ # - Report - Log and report to error tracking service (but don't crash)
14
+ # - LogProduction - Log error in production, raise locally (dev/test)
15
+ # - ReportProduction - Report error in production, raise locally (dev/test)
16
+ # - Raise - Always raise the error
17
+
18
+ # Configurable error handling categories
19
+ prop :type_checking_errors, ErrorHandlingMode, default: ErrorHandlingMode::LogProduction
20
+ prop :logstruct_errors, ErrorHandlingMode, default: ErrorHandlingMode::LogProduction
21
+ prop :security_errors, ErrorHandlingMode, default: ErrorHandlingMode::Report
22
+ prop :standard_errors, ErrorHandlingMode, default: ErrorHandlingMode::Raise
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,80 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module LogStruct
5
+ module ConfigStruct
6
+ class Filters < T::Struct
7
+ include Sorbet::SerializeSymbolKeys
8
+
9
+ # Keys that should be filtered in nested structures such as request params and job arguments.
10
+ # Filtered data includes information about Hashes and Arrays.
11
+ #
12
+ # { _filtered: {
13
+ # _class: "Hash", # Class of the filtered value
14
+ # _bytes: 1234, # Length of JSON string in bytes
15
+ # _keys_count: 3, # Number of keys in the hash
16
+ # _keys: [:key1, :key2, :key3], # First 10 keys in the hash
17
+ # }
18
+ # }
19
+ #
20
+ # Default: [:password, :password_confirmation, :pass, :pw, :token, :secret,
21
+ # :credentials, :creds, :auth, :authentication, :authorization]
22
+ #
23
+ prop :filter_keys,
24
+ T::Array[Symbol],
25
+ factory: -> {
26
+ %i[
27
+ password password_confirmation pass pw token secret
28
+ credentials auth authentication authorization
29
+ credit_card ssn social_security
30
+ ]
31
+ }
32
+
33
+ # Keys where string values should include an SHA256 hash.
34
+ # Useful for tracing emails across requests (e.g. sign in, sign up) while protecting privacy.
35
+ # Default: [:email, :email_address]
36
+ prop :filter_keys_with_hashes,
37
+ T::Array[Symbol],
38
+ factory: -> { %i[email email_address] }
39
+
40
+ # Hash salt for SHA256 hashing (typically used for email addresses)
41
+ # Used for both param filters and string scrubbing
42
+ # Default: "l0g5t0p"
43
+ prop :hash_salt, String, default: "l0g5t0p"
44
+
45
+ # Hash length for SHA256 hashing (typically used for email addresses)
46
+ # Used for both param filters and string scrubbing
47
+ # Default: 12
48
+ prop :hash_length, Integer, default: 12
49
+
50
+ # Filter email addresses. Also controls email filtering for the ActionMailer integration
51
+ # (to, from, recipient fields, etc.)
52
+ # Default: true
53
+ prop :email_addresses, T::Boolean, default: true
54
+
55
+ # Filter URL passwords
56
+ # Default: true
57
+ prop :url_passwords, T::Boolean, default: true
58
+
59
+ # Filter credit card numbers
60
+ # Default: true
61
+ prop :credit_card_numbers, T::Boolean, default: true
62
+
63
+ # Filter phone numbers
64
+ # Default: true
65
+ prop :phone_numbers, T::Boolean, default: true
66
+
67
+ # Filter social security numbers
68
+ # Default: true
69
+ prop :ssns, T::Boolean, default: true
70
+
71
+ # Filter IP addresses
72
+ # Default: false
73
+ prop :ip_addresses, T::Boolean, default: false
74
+
75
+ # Filter MAC addresses
76
+ # Default: false
77
+ prop :mac_addresses, T::Boolean, default: false
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,89 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "active_support/notifications"
5
+
6
+ module LogStruct
7
+ module ConfigStruct
8
+ class Integrations < T::Struct
9
+ include Sorbet::SerializeSymbolKeys
10
+
11
+ # Enable or disable Sorbet error handler integration
12
+ # Default: true
13
+ prop :enable_sorbet_error_handlers, T::Boolean, default: true
14
+
15
+ # Enable or disable Lograge integration
16
+ # Default: true
17
+ prop :enable_lograge, T::Boolean, default: true
18
+
19
+ # Custom options for Lograge
20
+ # Default: nil
21
+ prop :lograge_custom_options, T.nilable(Handlers::LogrageCustomOptions), default: nil
22
+
23
+ # Enable or disable ActionMailer integration
24
+ # Default: true
25
+ prop :enable_actionmailer, T::Boolean, default: true
26
+
27
+ # Enable or disable host authorization logging
28
+ # Default: true
29
+ prop :enable_host_authorization, T::Boolean, default: true
30
+
31
+ # Enable or disable ActiveJob integration
32
+ # Default: true
33
+ prop :enable_activejob, T::Boolean, default: true
34
+
35
+ # Enable or disable Rack middleware
36
+ # Default: true
37
+ prop :enable_rack_error_handler, T::Boolean, default: true
38
+
39
+ # Enable or disable Sidekiq integration
40
+ # Default: true
41
+ prop :enable_sidekiq, T::Boolean, default: true
42
+
43
+ # Enable or disable Shrine integration
44
+ # Default: true
45
+ prop :enable_shrine, T::Boolean, default: true
46
+
47
+ # Enable or disable ActiveStorage integration
48
+ # Default: true
49
+ prop :enable_activestorage, T::Boolean, default: true
50
+
51
+ # Enable or disable CarrierWave integration
52
+ # Default: true
53
+ prop :enable_carrierwave, T::Boolean, default: true
54
+
55
+ # Enable or disable GoodJob integration
56
+ # Default: true
57
+ prop :enable_goodjob, T::Boolean, default: true
58
+
59
+ # Enable SemanticLogger integration for high-performance logging
60
+ # Default: true
61
+ prop :enable_semantic_logger, T::Boolean, default: true
62
+
63
+ # Enable colored JSON output in development
64
+ # Default: true
65
+ prop :enable_color_output, T::Boolean, default: true
66
+
67
+ # Color configuration for JSON output
68
+ # Default: nil (uses SemanticLogger defaults)
69
+ prop :color_map, T.nilable(T::Hash[Symbol, Symbol]), default: nil
70
+
71
+ # Filter noisy loggers (ActionView, etc.)
72
+ # Default: false
73
+ prop :filter_noisy_loggers, T::Boolean, default: false
74
+
75
+ # Enable SQL query logging through ActiveRecord instrumentation
76
+ # Default: false (can be resource intensive)
77
+ prop :enable_sql_logging, T::Boolean, default: false
78
+
79
+ # Only log SQL queries slower than this threshold (in milliseconds)
80
+ # Set to 0 or nil to log all queries
81
+ # Default: 100.0 (log queries taking >100ms)
82
+ prop :sql_slow_query_threshold, T.nilable(Float), default: 100.0
83
+
84
+ # Include bind parameters in SQL logs (disable in production for security)
85
+ # Default: true in development/test, false in production
86
+ prop :sql_log_bind_params, T::Boolean, factory: -> { !defined?(::Rails) || !::Rails.respond_to?(:env) || !::Rails.env.production? }
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,59 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "handlers"
5
+ require_relative "config_struct/error_handling_modes"
6
+ require_relative "config_struct/integrations"
7
+ require_relative "config_struct/filters"
8
+
9
+ module LogStruct
10
+ # Core configuration class that provides a type-safe API
11
+ class Configuration < T::Struct
12
+ extend T::Sig
13
+
14
+ include Sorbet::SerializeSymbolKeys
15
+
16
+ # -------------------------------------------------------------------------------------
17
+ # Props
18
+ # -------------------------------------------------------------------------------------
19
+
20
+ prop :enabled, T::Boolean, default: true
21
+ prop :enabled_environments, T::Array[Symbol], factory: -> { [:test, :production] }
22
+ prop :local_environments, T::Array[Symbol], factory: -> { [:development, :test] }
23
+ const :integrations, ConfigStruct::Integrations, factory: -> { ConfigStruct::Integrations.new }
24
+ const :filters, ConfigStruct::Filters, factory: -> { ConfigStruct::Filters.new }
25
+
26
+ # Custom log scrubbing handler for any additional string scrubbing
27
+ # Default: nil
28
+ prop :string_scrubbing_handler, T.nilable(Handlers::StringScrubber)
29
+
30
+ # Custom handler for error reporting
31
+ # Default: Errors are handled by MultiErrorReporter
32
+ # (auto-detects Sentry, Bugsnag, Rollbar, Honeybadger, etc.)
33
+ prop :error_reporting_handler, T.nilable(Handlers::ErrorReporter), default: nil
34
+
35
+ # How to handle errors from various sources
36
+ const :error_handling_modes,
37
+ ConfigStruct::ErrorHandlingModes,
38
+ factory: -> {
39
+ ConfigStruct::ErrorHandlingModes.new
40
+ }
41
+
42
+ # -------------------------------------------------------------------------------------
43
+ # Class Methods
44
+ # -------------------------------------------------------------------------------------
45
+
46
+ # Class‐instance variable
47
+ @instance = T.let(nil, T.nilable(Configuration))
48
+
49
+ sig { returns(Configuration) }
50
+ def self.instance
51
+ @instance ||= T.let(Configuration.new, T.nilable(Configuration))
52
+ end
53
+
54
+ sig { params(config: Configuration).void }
55
+ def self.set_instance(config)
56
+ @instance = config
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,22 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module LogStruct
5
+ # Enum for error handling modes
6
+ class ErrorHandlingMode < T::Enum
7
+ enums do
8
+ # Always ignore the error
9
+ Ignore = new(:ignore)
10
+ # Always log the error
11
+ Log = new(:log)
12
+ # Always report to tracking service and continue
13
+ Report = new(:report)
14
+ # Log in production, raise locally (dev/test)
15
+ LogProduction = new(:log_production)
16
+ # Report in production, raise locally (dev/test)
17
+ ReportProduction = new(:report_production)
18
+ # Always raise regardless of environment
19
+ Raise = new(:raise)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,14 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module LogStruct
5
+ class ErrorReporter < T::Enum
6
+ enums do
7
+ RailsLogger = new(:rails_logger)
8
+ Sentry = new(:sentry)
9
+ Bugsnag = new(:bugsnag)
10
+ Rollbar = new(:rollbar)
11
+ Honeybadger = new(:honeybadger)
12
+ end
13
+ end
14
+ end