Configuration
LogStruct is designed to be highly configurable while working with sensible defaults. You can customize how and where logs are generated, which integrations are enabled, and how errors are handled.
Create a file at config/initializers/logstruct.rb
with your desired configuration.
LogStruct.configure do |config|
# your configuration here
end
Enabling LogStruct
LogStruct follows a simple philosophy: machines get JSON, humans get readable logs. By default:
- Production servers → JSON logs (for parsing and analysis)
- Test runs → JSON logs (to catch production bugs in both local and CI environments)
- Local development → Human-readable logs (disabled by default)
- Rails console → Human-readable logs (always)
- Rake tasks → Human-readable logs
Overriding the Defaults
You can override this behavior in several ways, with the following precedence (highest to lowest):
- Environment variable override
SetLOGSTRUCT_ENABLED=true
to force JSON logs, orLOGSTRUCT_ENABLED=false
to disable completely.# Force JSON logs in console for debugging LOGSTRUCT_ENABLED=true rails console # Disable JSON logs in tests (not recommended) LOGSTRUCT_ENABLED=false rails test
- Initializer configuration
Manually setconfig.enabled = true
in your initializer to enable in all development processes.LogStruct.configure do |c| c.enabled = true end
- Environment list
Modifyconfig.enabled_environments
to change which environments have JSON logs by default (currently[:test, :production]
).
CI
environment variable is automatically detected by most CI systems (GitHub Actions, GitLab CI, CircleCI, Travis, etc.). If your CI doesn't set it, add CI=true
to your CI configuration.Environment Configuration
LogStruct supports different environments and handles them appropriately:
LogStruct.configure do |config|
config.enabled_environments = [:test, :production]
# LogStruct will raise errors in local environments,
# and log or report errors in production.
# (This can be configured with config.error_handling_modes)
config.local_environments = [:development, :test]
end
Preview Production Logs in Development
LogStruct is disabled by default in development. When you explicitly enable it (for example, LOGSTRUCT_ENABLED=true rails s
or setting config.enabled = true
), LogStruct uses the same JSON formatter as production so you can validate structured logs locally. If you prefer the colorful human formatter for day‑to‑day debugging, set:
LogStruct.configure do |c|
c.prefer_json_in_development = false
c.enable_color_output = true
end
ActiveSupport::TaggedLogging
compatibility patch is only applied when LogStruct is enabled. This ensures third‑party gems that write Hashes to Rails.logger
(e.g., dotenv‑rails) do not affect your default development logging when LogStruct is disabled.test
as well as production by default. Keeping test and production behavior as close as possible helps catch logging issues early (for example, unexpected serialization errors, missing fields, or broken integrations) before they reach prod. If you prefer to disable it in test, remove :test
from config.enabled_environments
.LOGSTRUCT_ENABLED=true
when running the command:LOGSTRUCT_ENABLED=true rails console
LOGSTRUCT_ENABLED=true rake db:migrate
Integration Configuration
LogStruct integrates with many popular gems. You can enable or disable specific integrations:
LogStruct.configure do |config|
# Enable/disable specific integrations
config.integrations.enable_actionmailer = true
config.integrations.enable_active_model_serializers = true
config.integrations.enable_activejob = true
config.integrations.enable_activestorage = true
config.integrations.enable_ahoy = true
config.integrations.enable_carrierwave = true
config.integrations.enable_dotenv = true
config.integrations.enable_goodjob = true
config.integrations.enable_host_authorization = true
config.integrations.enable_lograge = true
config.integrations.enable_rack_error_handler = true
config.integrations.enable_semantic_logger = true
config.integrations.enable_shrine = true
config.integrations.enable_sidekiq = true
config.integrations.enable_puma = true
config.integrations.enable_sorbet_error_handlers = true
config.integrations.enable_sql_logging = true
# Configure custom options for Lograge
config.integrations.lograge_custom_options = ->(event, _) {
{
# Add custom fields to your Lograge output
user_id: event.payload[:user_id],
correlation_id: event.payload[:correlation_id]
}
}
end
Filtering Sensitive Data
LogStruct includes robust filtering for sensitive data to ensure privacy and security:
LogStruct.configure do |config|
# Configure which params should be filtered
config.filters.filter_keys = [
:password, :password_confirmation, :token, :secret,
:credit_card, :ssn, :social_security
]
# Configure which params should include hashes for values
config.filters.filter_keys_with_hashes = [
:email, :email_address
]
# Configure sensitive data filtering for all strings
config.filters.credit_card_numbers = true # Filter credit card numbers
config.filters.email_addresses = true # Filter email addresses
config.filters.ip_addresses = false # Filter IP addresses (off by default)
config.filters.mac_addresses = false # Filter MAC addresses (off by default)
config.filters.phone_numbers = true # Filter phone numbers
config.filters.ssns = true # Filter social security numbers
config.filters.url_passwords = true # Filter passwords in URLs
# Configure additional matchers for custom filtering rules
config.filters.filter_matchers = [
LogStruct::ConfigStruct::FilterMatcher.new(
callable: ->(key, _value) { key.start_with?("secret_") },
label: "secret prefix matcher"
)
]
# Configure the salt used for hashing filtered email addresses
config.filters.hash_salt = ENV.fetch("EMAIL_HASH_SALT", "test_salt")
# Configure the length of hash output for filtered emails (default: 12)
config.filters.hash_length = 12
end
Error Handling Configuration
LogStruct provides customizable error handling modes to control how errors are processed. You probably don't want type-checking errors or internal logging-related errors to crash your application, so our default behavior is to log and report those errors without crashing. We automatically detect which error reporting service you use (Sentry, Bugsnag, Rollbar, etc.). If you use a service that we don't support yet, you can configure a custom error handler. (Or you can send a PR!)
LogStruct.configure do |config|
# Configure error handling modes
modes = config.error_handling_modes
modes.type_checking_errors = LogStruct::ErrorHandlingMode::ReportProduction
modes.logstruct_errors = LogStruct::ErrorHandlingMode::ReportProduction
modes.security_errors = LogStruct::ErrorHandlingMode::Report
modes.standard_errors = LogStruct::ErrorHandlingMode::Raise
end
ActionMailer ID Mapping
Configure which instance variables on your mailers should be logged as IDs in additional_data
. This is useful for tracking which account, user, organization, etc. sent an email.
LogStruct.configure do |c|
# Default mapping
c.integrations.actionmailer_id_mapping = {
account: :account_id,
user: :user_id
}
# Custom mapping for your app
c.integrations.actionmailer_id_mapping = {
organization: :org_id,
company: :company_id,
tenant: :tenant_id
}
end
In your mailer, set the instance variables and they'll automatically be logged:
class UserMailer < ApplicationMailer
def welcome_email(user, account)
@user = user # Logs user_id
@account = account # Logs account_id
mail(to: user.email, subject: 'Welcome')
end
end
Custom Lograge Options
You can extend Lograge request logging with custom fields:
# Provide a custom proc to extend Lograge options
LogStruct.configure do |config|
config.integrations.lograge_custom_options = T.let(->(event, options) do
# Add custom fields to the options hash
options[:user_id] = event.payload[:user_id] if event.payload[:user_id]
options[:account_id] = event.payload[:account_id] if event.payload[:account_id]
options
end,
LogStruct::Handlers::LogrageCustomOptions)
end
Custom String Scrubbing
You can implement custom string scrubbers to filter out sensitive data that isn't caught by the built-in filters:
# Set a custom string scrubbing handler that will be called
# after the built-in scrubbers run
LogStruct.configure do |config|
config.string_scrubbing_handler = T.let(->(value) {
# Custom string scrubbing logic here
# Example: Remove all bank account numbers that match the pattern
value.gsub(/\b\d{10,12}\b/, "[BANK_ACCOUNT]")
},
LogStruct::Handlers::StringScrubber)
end
Custom Error Reporting
If LogStruct doesn't support your error reporting service, you can register a custom error reporting handler. (Or submit a PR!)
LogStruct.configure do |config|
config.error_reporting_handler = T.let(->(error, context, source) {
# Custom error reporting logic here
# You could send errors to a custom service, log them specially, etc.
# This is just a simple example:
# Extract info from the error
error_class = error.class.name
error_message = error.message
# Log to a custom target
puts "[CUSTOM ERROR REPORTER] #{error_class}: #{error_message}"
puts "Context: #{context.inspect}"
puts "Backtrace: #{error.backtrace&.first(5)&.join("\n ")}"
},
LogStruct::Handlers::ErrorReporter)
end
Sorbet Integration
LogStruct integrates with Sorbet to handle type checking errors based on the environment. We raise type errors or logging-related errors in test/development so you can catch them early, but we only log or report them in production. You can configure a different error handling mode to change this behavior.
config.integrations.enable_sorbet_error_handlers = true
# This configures the following error handlers for Sorbet:
# - T::Configuration.inline_type_error_handler
# - T::Configuration.call_validation_error_handler
# - T::Configuration.sig_builder_error_handler
# - T::Configuration.sig_validation_error_handler