JSON structured logging for Rails apps (Rails 7.1 or newer, Ruby 3.3 or newer). Add the gem, and in production your app writes one JSON line per log entry to STDOUT: requests, jobs, mail, errors, security events and your own logs. The lines are easy to search, and you can turn them into metrics, alerts and dashboards in CloudWatch, Grafana, Datadog or any other log platform. Sensitive values are filtered and scrubbed before a line is written.
{"src":"rails","evt":"request","lvl":"info","ts":"2026-10-17T03:09:30.839+00:00","path":"/orders","method":"GET","source_ip":"203.0.113.7","user_agent":"Mozilla/5.0","referer":"https://app.example.com/","format":"html","controller":"OrdersController","action":"index","status":200,"duration_ms":42.1,"view":30.2,"db":8.4,"params":{"page":"2"},"host":"app.example.com","accept":"text/html","prog":"Rails","req_id":"6f1c2b7e-0d4a-4c1e-9a55-3b8e2f7d9c10"}- On where it matters. In production LogStruct switches on for the processes it recognizes: Puma, Unicorn,
Thin, Falcon,
rails server, a Sidekiq server andgood_job start. In test it's on for every process except the console. It's off in development, in consoles and in production Rake tasks, unless you setLOGSTRUCT_ENABLED=true. See When LogStruct runs. - Integrations for Lograge (request lines), ActionMailer, ActiveJob, Sidekiq, GoodJob, Puma, ActiveStorage, Shrine, CarrierWave, Ahoy, ActiveModelSerializers, Dotenv, host authorization, CSRF and IP spoofing errors, and Sorbet's runtime type errors. SQL query logging is there too, off by default.
- Filtering by key name. Values under keys like
password,token,api_key,authorizationandcookieare replaced by a summary of the value, in request params, job arguments and anything else you log. Keys are matched by their words, soapiKey,X-Api-KeyandHTTP_AUTHORIZATIONare filtered too. The keys in Rails'config.filter_parametersare filtered the way Rails filters them. - Scrubbing inside strings (inspired by Logstop): email addresses become a
keyed hash (
[EMAIL:5f0c1e2a9b3d4e6f]), so you can follow one person through your logs without logging the address. Card numbers that pass the Luhn check, US phone numbers, SSNs written as 123-45-6789, URL passwords,BearerandBasiccredentials and sensitive URL query params (?token=) are replaced too. IP and MAC address scrubbing are opt-in. - Limits. Huge values are cut down (100 keys per Hash, 10 items per Array, 20 lines per backtrace, 32 KB per String by default), so one large request body can't slow down your logging.
- Error handling. A mode for each kind of error decides whether it's raised, logged or reported, and whether that differs between development and production. Reports go to Sentry, Bugsnag, Rollbar, Honeybadger or your own reporter.
- Sorbet types. Every built-in line is a typed struct, and you can define your own typed log lines.
- STDOUT only in production, with no log file to rotate or fill the disk.
Add this line to your application's Gemfile:
gem "logstruct"And then run:
bundle installThat's all you need: there's nothing to generate. To configure LogStruct, add an initializer
(config/initializers/logstruct.rb). The configuration docs list every
setting.
To see the JSON lines in development, start your server with LOGSTRUCT_ENABLED=true rails server.
When LogStruct is on in a process:
Rails.loggerand the framework loggers (ActiveRecord, ActionController, ActionMailer, ActiveJob, ActionView, ActionCable) are replaced by LogStruct's SemanticLogger logger. A logger you set withconfig.loggeronly applies while LogStruct is off.- Lograge is turned on and writes the request lines. Request lines include
req_id,source_ip,host,user_agent,referer(without its query string),content_type,acceptand the fields yourlograge_custom_optionsproc adds. - Every line logged during a request gets its
req_id. Tags fromlogger.tagged(...)andconfig.log_tagsare written intags. - Rails' own text lines for requests, mail and jobs are replaced by LogStruct's JSON lines. An error your app didn't handle is one error line with the request's fields and the response's status, instead of Rails' block of text.
- Mailers get a
rescue_from StandardErrorthat logs a failed delivery before re-raising it, and thelog_and_ignore_error,log_and_report_errorandlog_and_reraise_errormethods for your ownrescue_fromhandlers (those methods exist where LogStruct is off too). - CSRF and IP spoofing errors are logged as security lines and reported (
error_handling_modes.security_errors), and Rails still responds to them as usual. Blocked hosts are logged too. - Rails'
filter_parameterslist is left in place, sorequest.filtered_parameters,ActiveRecord::Base.filter_attributesand other Rails features keep filtering. Values Rails has already replaced are logged as[FILTERED]. - Loggers you build yourself with
ActiveSupport::TaggedLogging.new(...)write LogStruct's JSON lines too. - In production LogStruct logs to STDOUT only. In development it logs to STDOUT and Rails' log file, and in test to
the log file only. With
RAILS_LOG_TO_STDOUTset, both log to STDOUT only.
The full documentation is at logstruct.com/docs. Its Ruby examples are tested in this repository's test suite.
- Getting started
- Configuration
- Filtering sensitive data
- Log fields
- Custom typed logs
- Upgrading to 0.2.0 (many breaking changes)
- Troubleshooting
- Changelog
To report a vulnerability, see SECURITY.md.
This project is licensed under the MIT License. See the LICENSE file for details.