Logging & Log Management
High-quality logs accelerate debugging, observability, and incident response. Ruby's standard Logger paired with Rails tagged logging and JSON formatters delivers structured, queryable telemetry.
Logger basics
logger = Logger.new($stdout)
logger.progname = 'RubyDev'
logger.formatter = proc do |severity, timestamp, progname, msg|
"\#{timestamp.utc.iso8601} \#{severity} \#{progname}: \#{msg}\n"
end
logger.info('user_signup', user_id: user.id)
logger.warn('rate_limit_exceeded', path: request.path)
In Rails, use `Rails.logger` (backed by ActiveSupport::Logger). Configure level per environment (`config.log_level = :info`).
Structured & tagged logging
# config/environments/production.rb
config.log_tags = [:request_id, ->(req) { "tenant:\#{req.headers['X-Tenant'] || 'default'}" }]
config.logger = ActiveSupport::TaggedLogging.new(Logger.new($stdout))
# app/services/logging/json_formatter.rb
class Logging::JSONFormatter < Logger::Formatter
def call(severity, timestamp, progname, msg)
payload = msg.is_a?(Hash) ? msg : { message: msg }
payload.merge!(severity:, progname:, timestamp: timestamp.utc.iso8601)
"\#{payload.to_json}\n"
end
end
Export JSON logs to Logstash, Datadog, or CloudWatch for structured queries. Include request IDs, user IDs, and feature flags in payloads.
HTTP & domain-specific logging
- Lograge: condense Rails request logs into one line. Add custom payloads (`config.lograge.custom_options`) for user ID, params, runtime.
- Custom logger channels: `PaymentsLogger = Logger.new(Rails.root.join('log/payments.log'))` for domain-specific output.
- ActiveSupport::Notifications: instrument events and use subscribers to emit logs with correlation IDs.
Retention strategy
- Rotate local logs with `config.logger = ActiveSupport::Logger.new(config.paths['log'].first, 5, 50.megabytes)`.
- Ship production logs to a central store (Vector, Fluentd) with retention policies per compliance requirements.
- Mask secrets (`config.filter_parameters += %i[password token api_key]`) to avoid leaking credentials.
Operational checklist
- Ensure each request log line includes request ID, user ID (if authenticated), controller, action, status, and runtime.
- Log errors with `logger.error(exception, backtrace:`) to capture structured context and the stack trace for observability tools.
- During incidents, raise log levels from `:info` to `:debug` temporarily to capture additional detail, then revert to reduce noise.