Set Up Logs
Structured logs allow you to send, view and query logs sent from your Rails applications within Sentry.
With Sentry Structured Logs, you can send text-based log information from your Rails applications to Sentry. Once in Sentry, these logs can be viewed alongside relevant errors, searched by text-string, or searched using their individual attributes.
Logs for Rails are supported in Sentry Rails SDK version 5.27.0
and above.
gem install sentry-rails
Or add it to your Gemfile:
gem "sentry-rails"
To enable logging, you need to initialize the SDK with the enable_logs
option set to true
.
Sentry.init do |config|
config.dsn = "https://examplePublicKey@o0.ingest.sentry.io/0example-org / example-project"
config.enable_logs = true
end
Note on structured logging
Structured logging with Log Subscribers provides rich context and metadata compared to plain logger messages. This enables better filtering, searching, and analysis of your application's behavior in Sentry.
Rails applications can benefit from structured logging using ActiveSupport's Log Subscribers. This feature captures Rails instrumentation events and sends them as structured logs to Sentry with relevant context and metadata.
To enable structured logging with default subscribers:
Sentry.init do |config|
config.dsn = "https://examplePublicKey@o0.ingest.sentry.io/0example-org / example-project"
config.enable_logs = true
config.rails.structured_logging.enabled = true
end
By default, this enables structured logging for:
- ActiveRecord: Database queries with SQL, duration, connection info, and caching status
- ActionController: HTTP requests with controller, action, parameters, response status, and timing
Additional subscribers are available but not enabled by default:
- ActiveJob: Background job execution (
perform
), enqueueing (enqueue
), retry failures (retry_stopped
), and job discarding (discard
) - ActionMailer: Email delivery (
deliver
) and processing (process
) events
See the Options section for information on how to enable additional subscribers.
If you enable :logger
patch, this will affect Rails' built-in logger. This means that anything that Rails logs, and any custom usage of the Rails logger, will result in sending log entries to Sentry:
Sentry.init do |config|
config.dsn = "https://examplePublicKey@o0.ingest.sentry.io/0example-org / example-project"
config.enable_logs = true
config.enabled_patches = [:logger]
end
Then all logs from Rails logger will be sent to Sentry, for example:
# All these calls will result in log entries in Sentry
# if :logger patch is enabled
Rails.logger.debug("Hello from Rails logger")
Rails.logger.info("Hello from Rails logger")
Rails.logger.error("Hello from Rails logger")
Note on logger patch
Enabling :logger
patch will send all logs from Rails logger to Sentry. This includes logs from Rails framework itself, which might not be desired. In that case we recommend using Sentry logger or structured logging with log subscribers.
Once the feature is enabled on the SDK, you can send logs using the Sentry.logger
API.
The logger
namespace exposes common logging methods that you can use to log messages at different log levels: trace
, debug
, info
, warning
, error
, and fatal
.
You can pass additional attributes directly to the logging functions. These properties will be sent to Sentry, and can be searched from within the Logs UI, and even added to the Logs views as a dedicated column.
Sentry.logger.info("Updated global cache")
Sentry.logger.debug("Cache miss for user %{user_id}", user_id: 123)
Sentry.logger.trace(
"Starting database connection %{database}",
database: "users"
)
Sentry.logger.warn(
"Rate limit reached for endpoint %{endpoint}",
endpoint: "/api/results/"
)
Sentry.logger.error(
"Failed to process payment. Order: %{order_id}. Amount: %{amount}",
order_id: "or_2342", amount: 99.99
)
Sentry.logger.fatal(
"Database %{database} connection pool exhausted",
database: "users"
)
You can use message templates with positional or hash parameters:
# Using named parameters
Sentry.logger.info("User %{name} logged in", name: "Jane Doe")
# Using positional parameters
Sentry.logger.info("User %s logged in", ["Jane Doe"])
Any other arbitrary attributes will be sent as part of the log event payload:
# Here `user_id` and `action` will be sent as extra attributes that
# Sentry Logs UI displays
Sentry.logger.info(
"User %{user} logged in",
user: "Jane", user_id: 123, action: "create"
)
The Rails SDK includes several built-in log subscribers that you can enable:
- ActiveRecord: Database queries with SQL, duration, connection info, and caching status
- ActionController: HTTP requests with controller, action, parameters, response status, and timing
- ActiveJob: Background job execution (
perform
), enqueueing (enqueue
), retry failures (retry_stopped
), and job discarding (discard
) - ActionMailer: Email delivery (
deliver
) and processing (process
) events
You can customize which subscribers are active:
Sentry.init do |config|
config.dsn = "https://examplePublicKey@o0.ingest.sentry.io/0example-org / example-project"
config.enable_logs = true
config.rails.structured_logging.enabled = true
config.rails.structured_logging.subscribers = {
active_record: Sentry::Rails::LogSubscribers::ActiveRecordSubscriber,
action_controller: Sentry::Rails::LogSubscribers::ActionControllerSubscriber
}
end
To enable additional subscribers, add them to the configuration:
Sentry.init do |config|
config.dsn = "https://examplePublicKey@o0.ingest.sentry.io/0example-org / example-project"
config.enable_logs = true
config.rails.structured_logging.enabled = true
config.rails.structured_logging.subscribers = {
active_record: Sentry::Rails::LogSubscribers::ActiveRecordSubscriber,
action_controller: Sentry::Rails::LogSubscribers::ActionControllerSubscriber,
active_job: Sentry::Rails::LogSubscribers::ActiveJobSubscriber,
action_mailer: Sentry::Rails::LogSubscribers::ActionMailerSubscriber
}
end
To disable specific subscribers:
Sentry.init do |config|
config.dsn = "https://examplePublicKey@o0.ingest.sentry.io/0example-org / example-project"
config.enable_logs = true
config.rails.structured_logging.enabled = true
config.rails.structured_logging.subscribers = {
active_record: Sentry::Rails::LogSubscribers::ActiveRecordSubscriber
# ActionController subscriber disabled
}
end
You can create custom log subscribers by extending the base class:
class MyCustomSubscriber < Sentry::Rails::LogSubscriber
# Attach to your component's instrumentation events
attach_to :my_component
def my_event(event)
log_structured_event(
message: "Custom event occurred",
level: :info,
attributes: {
duration_ms: event.duration,
custom_data: event.payload[:custom_data],
user_id: event.payload[:user_id]
}
)
end
def another_event(event)
log_structured_event(
message: "Another custom event",
level: :warn,
attributes: {
event_type: event.payload[:type],
metadata: event.payload[:metadata]
}
)
end
end
Then register your custom subscriber:
Sentry.init do |config|
config.dsn = "https://examplePublicKey@o0.ingest.sentry.io/0example-org / example-project"
config.enable_logs = true
config.rails.structured_logging.enabled = true
config.rails.structured_logging.subscribers = {
active_record: Sentry::Rails::LogSubscribers::ActiveRecordSubscriber,
action_controller: Sentry::Rails::LogSubscribers::ActionControllerSubscriber,
my_component: MyCustomSubscriber
}
end
Log subscribers automatically respect Rails' parameter filtering configuration. Sensitive parameters defined in config.filter_parameters
will be filtered from structured logs:
# config/application.rb
config.filter_parameters += [:password, :credit_card, :ssn]
The Rails SDK automatically sets several default attributes on all log entries to provide context and improve debugging:
environment
: The environment set in the SDK if defined. This is sent from the SDK assentry.environment
.release
: The release set in the SDK if defined. This is sent from the SDK assentry.release
.trace.parent_span_id
: The span ID of the span that was active when the log was collected (only set if there was an active span). This is sent from the SDK assentry.trace.parent_span_id
.sdk.name
: The name of the SDK that sent the log. This is sent from the SDK assentry.sdk.name
. This is sent from the SDK assentry.sdk.name
.sdk.version
: The version of the SDK that sent the log. This is sent from the SDK assentry.sdk.version
. This is sent from the SDK assentry.sdk.version
.
If the log was paramaterized, Sentry adds the message template and parameters as log attributes.
message.template
: The parameterized template string. This is sent from the SDK assentry.message.template
.message.parameter.X
: The parameters to fill the template string. X can either be the number that represent the parameter's position in the template string (sentry.message.parameter.0
,sentry.message.parameter.1
, etc) or the parameter's name (sentry.message.parameter.item_id
,sentry.message.parameter.user_id
, etc). This is sent from the SDK assentry.message.parameter.X
.
server.address
: The address of the server that sent the log. Equivalent toserver_name
that gets attached to Sentry errors.
If user information is available in the current scope, the following attributes are added to the log:
user.id
: The user ID.user.name
: The username.user.email
: The email address.
If a log is generated by an SDK integration, the SDK will set additional attributes to help you identify the source of the log.
origin
: The origin of the log. This is sent from the SDK assentry.origin
.
When using structured logging with Log Subscribers, additional Rails-specific attributes are automatically included:
sql
- The SQL query executedduration_ms
- Query execution time in millisecondscached
- Whether the query result was cachedstatement_name
- SQL statement name (when available and not "SQL")connection_id
- Database connection identifier (when available)db_system
- Database adapter (e.g., "postgresql", "mysql2", "sqlite3")db_name
- Database name (sanitized for SQLite file paths)server_address
- Database host (when available)server_port
- Database port (when available)server_socket_address
- Database socket path (when available)
controller
- Controller class nameaction
- Action method nameduration_ms
- Request processing time in millisecondsmethod
- HTTP request methodpath
- Request pathformat
- Response format (html, json, etc.)status
- HTTP response status code (when available)view_runtime_ms
- View rendering time in milliseconds (when available)db_runtime_ms
- Database query time in milliseconds (when available)params
- Filtered request parameters (only whensend_default_pii
is enabled)
Common attributes for all ActiveJob events:
job_class
- Job class namejob_id
- Unique job identifierqueue_name
- Queue name where job is processedexecutions
- Number of execution attemptspriority
- Job priority
For perform
events:
duration_ms
- Job execution time in millisecondsadapter
- Queue adapter class namescheduled_at
- When job was scheduled in ISO8601 format (for delayed jobs)delay_ms
- Delay between scheduling and execution in milliseconds (for delayed jobs)arguments
- Job arguments (only whensend_default_pii
is enabled, filtered for sensitive data)
For enqueue
events:
adapter
- Queue adapter class name (when available)scheduled_at
- When job was scheduled in ISO8601 format (for delayed jobs)delay_seconds
- Delay between current time and scheduled time in seconds (for delayed jobs)
For retry_stopped
and discard
events:
error_class
- Error class name (when error is present)error_message
- Error message (when error is present)
For deliver
events:
mailer
- Mailer class nameduration_ms
- Email delivery time in millisecondsperform_deliveries
- Whether deliveries are enableddelivery_method
- Email delivery method used (when available)date
- Email date header as string (when available)message_id
- Email message ID (only whensend_default_pii
is enabled)
For process
events:
mailer
- Mailer class nameaction
- Mailer action method nameduration_ms
- Email processing time in millisecondsparams
- Mailer parameters (only whensend_default_pii
is enabled, filtered for sensitive data)
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").