What is Sorbet?

Sorbet Logo

Sorbet is a static type checker for Ruby. Static type-checking has many benefits:

  • Catches errors at development time, not at runtime
  • Ensures consistent log structure
  • Provides better IDE documentation and autocompletion

LogStruct is built with Sorbet and provides full type-checking support. We use it to catch errors during development and test and keep the code bug-free.

Adding Sorbet to Your Application

To fully utilize LogStruct's type safety features, you can add Sorbet to your application:

# In your Gemfile
gem "sorbet", group: :development
gem "sorbet-runtime"

Then run:

bundle install
bundle exec srb init

See the Sorbet docs for more details.

Using LogStruct with Sorbet

LogStruct uses predefined log classes with strict typing. This ensures that your logs have a consistent format and that required fields are present and have the right type.

# Create a typed request log entry
request_log = LogStruct::Log::Request.new(
  http_method: "GET",
  path: "/users",
  status: 200,
  duration_ms: 45.2,
  source: LogStruct::Source::Rails
)

# Log the typed struct at info level
LogStruct.info(request_log)

# Create a typed error log entry
error_log = LogStruct::Log::Error.new(
  source: LogStruct::Source::App,
  error_class: StandardError,
  message: "An error occurred during processing"
)

# Log the error at error level
LogStruct.error(error_log)

Error Handling for Type Errors

LogStruct configures Sorbet error handlers to log and report type-checking errors. If you already use Sorbet and you want to keep using your own error handlers, set enable_sorbet_error_handlers to false. This will prevent LogStruct from overriding your handlers.

LogStruct.configure do |config|
  config.integrations.enable_sorbet_error_handlers = false
end

Custom Typed Logs

Define your own typed logs by composing LogStruct interfaces and helpers. Include LogStruct::Log::Interfaces::CommonFields, LogStruct::Log::Interfaces::AdditionalDataField, and the serialization helpers SerializeCommon + MergeAdditionalDataFields to get consistent JSON keys and behavior. Use the existing LogStruct::Source and LogStruct::Event enums in your struct.

# Define a custom typed log using LogStruct interfaces
module TestApp
  module Log
    class Payments < T::Struct
      extend T::Sig

      include ::LogStruct::Log::Interfaces::PublicCommonFields
      include ::LogStruct::Log::Interfaces::AdditionalDataField
      include ::LogStruct::Log::SerializeCommonPublic
      include ::LogStruct::Log::Shared::MergeAdditionalDataFields

      # Event restricted to a specific set for type safety (T::Enum)
      class Event < T::Enum
        enums do
          Processed = new(:processed)
          Failed = new(:failed)
          Refunded = new(:refunded)
        end
      end

      # Fixed source: not overridable by callers
      sig { returns(String) }
      def source = "payments"

      const :event, Event
      const :level, ::LogStruct::Level, default: T.let(::LogStruct::Level::Info, ::LogStruct::Level)
      const :timestamp, Time, factory: -> { Time.now }

      # Domain fields
      const :payment_id, String
      const :amount_cents, Integer
      const :currency, String
      const :status, String
      const :user_id, T.nilable(Integer), default: nil

      # Optional extra data merged at top-level
      const :additional_data, T::Hash[Symbol, T.untyped], default: {}

      sig { override.params(strict: T::Boolean).returns(T::Hash[Symbol, T.untyped]) }
      def serialize(strict = true)
        h = serialize_common_public(strict)
        merge_additional_data_fields(h)
        h[:payment_id] = payment_id
        h[:amount_cents] = amount_cents
        h[:currency] = currency
        h[:status] = status
        h[:user_id] = user_id if user_id
        h
      end
    end
  end
end
Custom types are for your application logs and won't be exported to the Terraform provider catalog or docs generator. Use the built-in LogStruct types when you need provider support (patterns/validation), and use custom types for app-specific events.

Built-In Log Classes

Log classes are typed structs under the LogStruct:: module.

Log::ActionMailer

  • Delivered - ActionMailer callback emitted after a message is delivered
  • Delivery - ActionMailer event capturing when a mailer sends a message
  • Error - For exception details with stack traces

Log::ActiveJob

  • Enqueue - Background job enqueued event (ActiveJob or GoodJob scheduling a job for execution)
  • Finish - Background job completion event indicating success (ActiveJob/GoodJob)
  • Schedule - Deferred background job scheduling event (ActiveJob or GoodJob scheduling with a run_at time)
  • Start - Lifecycle start event for jobs or services (ActiveJob, GoodJob, or Puma boot)

Log::ActiveModelSerializers

  • For render events produced by ActiveModelSerializers (serializer, adapter, resource, duration)

Log::ActiveStorage

  • Delete - Deletion of a persisted attachment (ActiveStorage, CarrierWave, or Shrine)
  • Download - File download event (ActiveStorage, CarrierWave, or Shrine)
  • Exist - Existence check for a stored file (ActiveStorage or Shrine)
  • Metadata - Metadata read or write against a stored file (ActiveStorage or Shrine)
  • Stream - Streaming read of stored file contents (ActiveStorage)
  • Upload - File upload event (ActiveStorage, CarrierWave, or Shrine)
  • Url - URL generation event for a stored file (ActiveStorage)

Log::Ahoy

  • For analytics tracking events emitted by Ahoy (event name and properties)

Log::CarrierWave

  • Delete - Deletion of a persisted attachment (ActiveStorage, CarrierWave, or Shrine)
  • Download - File download event (ActiveStorage, CarrierWave, or Shrine)
  • Upload - File upload event (ActiveStorage, CarrierWave, or Shrine)

Log::Dotenv

  • Load - dotenv-rails load event when environment variables are read from disk
  • Restore - dotenv-rails restore event rolling back to the last saved state
  • Save - dotenv-rails save event persisting environment variables
  • Update - dotenv-rails update event after manipulating environment values

Log::Error

  • For exception details with stack traces

Log::GoodJob

  • Enqueue - Background job enqueued event (ActiveJob or GoodJob scheduling a job for execution)
  • Error - For exception details with stack traces
  • Finish - Background job completion event indicating success (ActiveJob/GoodJob)
  • Log - Structured GoodJob log output captured from the worker process
  • Schedule - Deferred background job scheduling event (ActiveJob or GoodJob scheduling with a run_at time)
  • Start - Lifecycle start event for jobs or services (ActiveJob, GoodJob, or Puma boot)

Log::Plain

  • For general purpose logging

Log::Puma

  • Shutdown - Puma server shutdown event
  • Start - Lifecycle start event for jobs or services (ActiveJob, GoodJob, or Puma boot)

Log::Request

  • For HTTP request details

Log::Security

  • BlockedHost - Request blocked by ActionDispatch::HostAuthorization (host not on the allowed list)
  • CSRFViolation - Request rejected due to a CSRF token violation
  • IPSpoof - Request rejected because the IP address spoofing check failed

Log::Shrine

  • Delete - Deletion of a persisted attachment (ActiveStorage, CarrierWave, or Shrine)
  • Download - File download event (ActiveStorage, CarrierWave, or Shrine)
  • Exist - Existence check for a stored file (ActiveStorage or Shrine)
  • Metadata - Metadata read or write against a stored file (ActiveStorage or Shrine)
  • Upload - File upload event (ActiveStorage, CarrierWave, or Shrine)

Log::Sidekiq

  • For Sidekiq job processing

Log::SQL

  • For ActiveRecord SQL query events and performance metrics

Built-In Enums

Common values are defined as Typed Enums under the LogStruct:: module.

Level

Log severity levels for different types of log messages

  • Debug - Detailed debugging information
  • Info - General informational messages
  • Warn - Warning conditions that should be noted
  • Error - Error conditions that affect operation
  • Fatal - Severe error conditions that cause the application to terminate
  • Unknown - Used when a log level cannot be determined

Source

Sources of log messages to identify which part of the system generated them

  • TypeChecking - Type checking errors (Sorbet)
  • Security - Security-related events and checks
  • Internal - Errors from LogStruct itself
  • Rails - Core Rails framework components
  • Job - Background job processing
  • Storage - ActiveStorage logs and errors
  • Mailer - Email delivery and processing
  • App - Application-specific code
  • Shrine - Shrine file upload logs and errors
  • CarrierWave - CarrierWave file upload logs and errors
  • Sidekiq - Sidekiq background job logs and errors
  • Dotenv - Dotenv-rails configuration events (env file load/update/save/restore)
  • Puma - Puma server lifecycle events

Event

Event types for different kinds of operations and activities

  • Log - Standard log message
  • Request - HTTP request
  • Enqueue - Job added to queue
  • Schedule - Job scheduled for future processing
  • Start - Job processing started, or server started
  • Finish - Job processing completed
  • Upload - File upload operation
  • Download - File download operation
  • Delete - File deletion operation
  • Metadata - File metadata operation
  • Exist - File existence check operation
  • Stream - File streaming operation
  • Url - File URL generation operation
  • Generate - Serialization/render event (ActiveModelSerializers)
  • Delivery - Email preparation for delivery
  • Delivered - Email successfully delivered
  • Load - Configuration load operation (e.g., dotenv file loaded)
  • Update - Configuration update operation (e.g., env var set)
  • Save - Configuration state saved (e.g., snapshot)
  • Restore - Configuration state restored (e.g., snapshot restored)
  • Shutdown - Server shutting down
  • IPSpoof - IP spoofing attack attempt
  • CSRFViolation - Cross-Site Request Forgery violation
  • BlockedHost - Access attempt from blocked host
  • Database - Database query event and metrics
  • Error - Error occurrence
  • Unknown - Unclassified event type

ErrorHandlingMode

Error handling strategies for different types of errors

  • Ignore - Completely ignore errors
  • Log - Log errors but don't report them
  • Report - Log and report errors to error service
  • LogProduction - Log in production, raise in development
  • ReportProduction - Report in production without crashing, raise during dev/test
  • Raise - Always raise the error (reported by tracking service)