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 initSee 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
endCustom 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
endBuilt-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)