What is Sorbet?
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
Built-In Log Classes
Log classes are typed structs under the LogStruct::
module.
Log::ActionMailer
Delivered
- ActionMailer callback emitted after a message is deliveredDelivery
- ActionMailer event capturing when a mailer sends a messageError
- 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 diskRestore
- dotenv-rails restore event rolling back to the last saved stateSave
- dotenv-rails save event persisting environment variablesUpdate
- 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 tracesFinish
- Background job completion event indicating success (ActiveJob/GoodJob)Log
- Structured GoodJob log output captured from the worker processSchedule
- 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 eventStart
- 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 violationIPSpoof
- 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 informationInfo
- General informational messagesWarn
- Warning conditions that should be notedError
- Error conditions that affect operationFatal
- Severe error conditions that cause the application to terminateUnknown
- 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 checksInternal
- Errors from LogStruct itselfRails
- Core Rails framework componentsJob
- Background job processingStorage
- ActiveStorage logs and errorsMailer
- Email delivery and processingApp
- Application-specific codeShrine
- Shrine file upload logs and errorsCarrierWave
- CarrierWave file upload logs and errorsSidekiq
- Sidekiq background job logs and errorsDotenv
- 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 messageRequest
- HTTP requestEnqueue
- Job added to queueSchedule
- Job scheduled for future processingStart
- Job processing started, or server startedFinish
- Job processing completedUpload
- File upload operationDownload
- File download operationDelete
- File deletion operationMetadata
- File metadata operationExist
- File existence check operationStream
- File streaming operationUrl
- File URL generation operationGenerate
- Serialization/render event (ActiveModelSerializers)Delivery
- Email preparation for deliveryDelivered
- Email successfully deliveredLoad
- 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 downIPSpoof
- IP spoofing attack attemptCSRFViolation
- Cross-Site Request Forgery violationBlockedHost
- Access attempt from blocked hostDatabase
- Database query event and metricsError
- Error occurrenceUnknown
- Unclassified event type
ErrorHandlingMode
Error handling strategies for different types of errors
Ignore
- Completely ignore errorsLog
- Log errors but don't report themReport
- Log and report errors to error serviceLogProduction
- Log in production, raise in developmentReportProduction
- Report in production without crashing, raise during dev/testRaise
- Always raise the error (reported by tracking service)