Integrations

Each integration turns the lines a Rails component or gem writes into LogStruct lines, or adds lines of its own. An integration is set up only when its gem is loaded, and each one can be turned off with its config.integrations.enable_* setting (see Integration Configuration). All of them are on by default except SQL logging.

The example lines below are generated in your browser to show each line's shape. Tick "Apply filtering" to see what LogStruct's filters do to them. The pages for ActiveJob, ActionMailer, Sidekiq, GoodJob, SQL and Security show lines written by the real code, and every field is described in Log Fields.

ActionMailer

Logs each mail before it's sent (delivery) and after (delivered), with the mailer, the action and the record IDs you choose with actionmailer_id_mapping. A delivery error is an error line, and what happens next (raise, report, retry) follows error_handling_modes.

The ActionMailer integration in detail

Example Logs

{
  "src": "mailer",
  "evt": "delivery",
  "lvl": "info",
  "ts": "2026-10-18T03:40:36.339+00:00",
  "to": [
    "[EMAIL:fae45b3934ec5cdd]"
  ],
  "from": "[EMAIL:9cb141590821dfcd]",
  "subject": "Your October invoice",
  "mailer": "AdminMailer",
  "mailer_action": "notification",
  "attachments": 2,
  "account_id": 8,
  "user_id": 7068,
  "prog": "Rails"
}

ActiveJob

Logs a line when a job is enqueued, scheduled, started, finished, retried or discarded, and when it fails, with the job class, ID, queue and its filtered arguments. It works with any queue backend.

The ActiveJob integration in detail

Example Logs

{
  "src": "job",
  "evt": "enqueue",
  "lvl": "info",
  "ts": "2026-10-18T03:40:36.339+00:00",
  "job_id": "6a7df1ad-7b4f-4d36-b950-ac1c49e5fe85",
  "job_class": "ImageProcessingJob",
  "queue_name": "low",
  "arguments": [
    "gid://my-app/Customer/2927",
    {
      "month": "2026-09",
      "email": {
        "_filtered": {
          "_class": "String",
          "_hash": "2ba74b7eb71dbd8c"
        }
      }
    }
  ],
  "executions": 0,
  "provider_job_id": "8468a135900bff921180a6d2",
  "prog": "Rails",
  "req_id": "10cbf712-f948-4719-9e95-fbf2f4c6c931"
}

ActiveModelSerializers

Logs each ActiveModelSerializers render with the serializer, adapter, resource class and duration (msg "ams.render").

Example Logs

{
  "src": "rails",
  "evt": "generate",
  "lvl": "info",
  "ts": "2026-10-18T03:40:36.339+00:00",
  "msg": "ams.render",
  "serializer": "ProjectSerializer",
  "adapter": "ActiveModelSerializers::Adapter::Attributes",
  "resource_class": "User",
  "duration_ms": 9.905,
  "prog": "Rails",
  "req_id": "df1ad7b4-fd36-4950-9ac1-c49e5fe853e3"
}

ActiveStorage

Logs uploads, downloads, deletes and metadata updates with the service and the blob's key (not its filename), in place of Rails' own ActiveStorage lines. Existence checks and URLs are debug lines, as Rails logs them, and URL lines leave out the signed URL.

Example Logs

{
  "src": "storage",
  "evt": "upload",
  "lvl": "info",
  "ts": "2026-10-18T03:40:36.339+00:00",
  "storage": "GCS",
  "file_id": "oxq47cy4rzk94hpulby2d2jv6n97",
  "duration_ms": 364.36,
  "checksum": "853e3de98468a135900bff==",
  "prog": "Rails",
  "req_id": "1180a6d2-610c-4bf7-812f-948719e95fbf"
}

Ahoy

Logs each event Ahoy tracks (Ahoy::Tracker#track) with its name and properties, as an app line whose msg is "ahoy.track".

Example Logs

{
  "src": "app",
  "evt": "log",
  "lvl": "info",
  "ts": "2026-10-18T03:40:36.339+00:00",
  "msg": "ahoy.track",
  "ahoy_event": "Clicked upgrade",
  "properties": {
    "invoice_id": 455
  },
  "prog": "Rails",
  "req_id": "7df1ad7b-4fd3-4695-a0ac-1c49e5fe853e"
}

CarrierWave

Logs a line when an uploader stores a file (upload), fetches a remote file (download) or removes one (delete), with the uploader, model, mount point, version and file details. Loading a stored file reads no data, and logs nothing.

Example Logs

{
  "src": "carrierwave",
  "evt": "upload",
  "lvl": "info",
  "ts": "2026-10-18T03:40:36.339+00:00",
  "storage": "file",
  "file_id": "avatar.png",
  "uploader": "AvatarUploader",
  "model": "User",
  "mount_point": "avatar",
  "version": "",
  "store_path": "uploads/user/avatar/7992/avatar.png",
  "ext": "png",
  "filename": "avatar.png",
  "mime_type": "image/png",
  "size": 356260,
  "duration_ms": 131.84,
  "prog": "Rails",
  "req_id": "df1ad7b4-fd36-4950-9ac1-c49e5fe853e3"
}

Dotenv

Turns dotenv-rails' load, update, save and restore messages into structured lines, with the names of the variables but not their values. Lines from before the logger is ready are kept and written once it is.

Example Logs

{
  "src": "dotenv",
  "evt": "update",
  "lvl": "debug",
  "ts": "2026-10-18T03:40:36.339+00:00",
  "vars": [
    "DATABASE_URL",
    "SMTP_HOST"
  ],
  "prog": "Rails"
}

Error Handling

An exception logged with Rails.logger.error(exception) or LogStruct.error, or handled by LogStruct, is an error line with its class, message and backtrace (up to max_backtrace_lines, default 20), and the request it happened in.

Error handling settings

Example Logs

{
  "src": "type_checking",
  "evt": "error",
  "lvl": "error",
  "ts": "2026-10-18T03:40:36.339+00:00",
  "error_class": "TypeError",
  "msg": "Parameter 'user_id': Expected type Integer, got type String with value \"1873\"",
  "backtrace": [
    "app/services/search_service.rb:112:in 'execute_query'",
    "app/services/authentication_service.rb:32:in 'authenticate'",
    "app/controllers/api/v1/sessions_controller.rb:41:in 'create'"
  ],
  "prog": "Rails",
  "req_id": "50ac1c49-e5fe-4853-ae3d-e98468a13590"
}

GoodJob

Logs GoodJob's own messages and its thread errors as structured lines (GoodJob 3.0 or later). GoodJob's jobs are logged by the ActiveJob integration.

The GoodJob integration in detail

Example Logs

{
  "src": "job",
  "evt": "error",
  "lvl": "error",
  "ts": "2026-10-18T03:40:36.339+00:00",
  "error_class": "ActiveRecord::ConnectionNotEstablished",
  "error_message": "connection to server at \"10.0.3.12\", port 5432 failed: Connection refused",
  "pid": 77916,
  "tid": "etx1",
  "backtrace": [
    "good_job/notifier.rb:225:in 'GoodJob::Notifier#with_connection'"
  ],
  "prog": "GoodJob"
}

Puma (Server)

Replaces Puma's boot and shutdown text with a start line (mode, Puma and Ruby versions, threads, environment and the addresses it listens on) and a shutdown line. An error Puma catches while handling a request (an exception the app didn't rescue, a malformed request, an SSL error) is an error line with the method and path, without the query string.

Example Logs

{
  "src": "puma",
  "evt": "start",
  "lvl": "info",
  "ts": "2026-10-18T03:40:36.339+00:00",
  "mode": "single",
  "puma_version": "6.6.1",
  "puma_codename": "Return to Forever",
  "ruby_version": "ruby 3.4.5 (2025-07-16 revision 20cda200d3) +PRISM [x86_64-linux]",
  "min_threads": 5,
  "max_threads": 5,
  "environment": "production",
  "pid": 1,
  "listening_addresses": [
    "http://0.0.0.0:3000"
  ],
  "prog": "Rails"
}

Request Logs (via Lograge)

Configures Lograge to write one line per request: the method, path, status, duration, controller and action, the filtered params, the client's IP and the host. Add fields of your own with lograge_custom_options.

Configuration

LogStruct.configure do |config|
  # Add fields to every request line: return a Hash of fields, or change options in place.
  # Fields that are nil are left out.
  config.integrations.lograge_custom_options = ->(event, _options) {
    {user_id: event.payload[:user_id], account_id: event.payload[:account_id]}
  }
end

Example Logs

{
  "src": "rails",
  "evt": "request",
  "lvl": "info",
  "ts": "2026-10-18T03:40:36.339+00:00",
  "path": "/invoices",
  "method": "GET",
  "source_ip": "198.51.100.23",
  "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Safari/605.1.15",
  "format": "html",
  "controller": "InvoicesController",
  "action": "index",
  "status": 200,
  "duration_ms": 265.06,
  "view": 90.91,
  "db": 124.71,
  "params": {
    "q": "october",
    "page": "2"
  },
  "host": "app.example.com",
  "accept": "text/html,application/xhtml+xml",
  "prog": "Rails",
  "req_id": "d7b4fd36-950a-4c1c-a49e-5fe853e3de98"
}

Security Logging

Logs requests that HostAuthorization blocked, failed CSRF checks and IP spoofing attempts as security lines, and reports them according to error_handling_modes.security_errors.

The Security Logging integration in detail

Example Logs

{
  "src": "security",
  "evt": "blocked_host",
  "lvl": "warn",
  "ts": "2026-10-18T03:40:36.339+00:00",
  "path": "/",
  "method": "GET",
  "source_ip": "198.51.100.23",
  "user_agent": "curl/8.7.1",
  "msg": "Blocked host detected: 203.0.113.50",
  "blocked_host": "203.0.113.50",
  "blocked_hosts": [
    "203.0.113.50"
  ],
  "prog": "Rails"
}

Shrine

Loads Shrine's instrumentation plugin and logs its upload, download, delete, metadata and exists operations with the storage, location and duration, and an upload's MIME type and size (not the file's original name), in place of Shrine's own text lines.

Example Logs

{
  "src": "shrine",
  "evt": "upload",
  "lvl": "info",
  "ts": "2026-10-18T03:40:36.339+00:00",
  "storage": "store",
  "location": "invoice/799/original-6a7df1.pdf",
  "mime_type": "application/pdf",
  "size": 613366,
  "upload_opts": {},
  "opts": {},
  "uploader": "DocumentUploader",
  "duration_ms": 343.08,
  "prog": "Rails",
  "req_id": "b4fd3695-0ac1-4c49-9e5f-e853e3de9846"
}

Sidekiq

Replaces Sidekiq's logger, so Sidekiq's lines are JSON too. Every line logged while a job runs has the job's jid and class in ctx, and a failed job is one warn line without its arguments.

The Sidekiq integration in detail

Example Logs

{
  "src": "sidekiq",
  "evt": "log",
  "lvl": "info",
  "ts": "2026-10-18T03:40:36.339+00:00",
  "msg": "Starting processing, hit Ctrl-C to stop",
  "pid": 90467,
  "tid": "e2qs",
  "prog": "Sidekiq-Server"
}

SQL (ActiveRecord) Logging

Off by default. When on, logs each query that takes at least sql_slow_query_threshold, with the SQL, duration, row count, operation and tables, and the filtered bind values. Schema, cache and migration bookkeeping queries are skipped, and Rails' own SQL lines are turned off.

The SQL (ActiveRecord) Logging integration in detail

Example Logs

{
  "src": "app",
  "evt": "database",
  "lvl": "info",
  "ts": "2026-10-18T03:40:36.339+00:00",
  "msg": "Project Load executed",
  "sql": "SELECT \"projects\".* FROM \"projects\" WHERE \"projects\".\"account_id\" = $1",
  "name": "Project Load",
  "duration_ms": 416.14,
  "row_count": 328,
  "adapter": "PostgreSQLAdapter",
  "db_name": "app_production",
  "pool_size": 5,
  "active_count": 3,
  "op_type": "SELECT",
  "table_names": [
    "projects"
  ],
  "prog": "Rails",
  "req_id": "f1ad7b4f-d369-450a-bc1c-49e5fe853e3d"
}

Sorbet Integration

LogStruct sets Sorbet's runtime error handlers: type errors are raised in development and test, and logged and reported in production so they don't crash your app.

Configuration

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