💎 ChatSDK Ruby

Instrumentation

Subscribe to internal SDK events for monitoring, logging, and metrics collection.

ChatSDK emits instrumentation events at key points in the dispatch pipeline and outbound API calls. Subscribe to these events to collect metrics, log activity, or integrate with observability tools — with zero external dependencies.

Subscribing to Events

ChatSDK::Instrumentation.subscribe("handler.chat_sdk") do |event_name, payload|
  puts "#{event_name}: #{payload[:handler_type]} took #{payload[:duration]}s"
end

The block receives:

  • event_name — the event string (e.g. "handler.chat_sdk")
  • payload — a hash with event-specific data plus :duration (seconds as Float)

Available Events

dispatch.chat_sdk

Fired for every inbound event entering the dispatch pipeline.

KeyTypeDescription
adapterSymbolAdapter name (e.g. :slack)
event_typeSymbolEvent type (:mention, :action, etc.)
durationFloatTotal dispatch time in seconds
errorExceptionPresent only if dispatch raised

dedupe.chat_sdk

Fired after each deduplication check.

KeyTypeDescription
adapterSymbolAdapter name
event_idStringThe event/message ID checked
duplicateBooleantrue if this event was already processed

lock.chat_sdk

Fired after each lock acquisition attempt.

KeyTypeDescription
keyStringThread lock key
acquiredBooleanWhether the lock was obtained
policySymbolConflict policy applied (:drop, :force, or nil)

handler.chat_sdk

Fired for each handler invocation.

KeyTypeDescription
handler_typeSymbolEvent type the handler processes
durationFloatHandler execution time in seconds
errorExceptionPresent only if the handler raised

api_request.chat_sdk

Fired for every outbound API call through ChatSDK::ApiClient::Base.

KeyTypeDescription
adapterSymbolAdapter name
methodSymbolHTTP method (:get, :post, etc.)
pathStringAPI endpoint path
durationFloatRequest time in seconds
errorExceptionPresent only if the request raised

rate_limited.chat_sdk

Fired when an API call receives a 429 response (before retry).

KeyTypeDescription
adapterSymbolAdapter name
retry_afterIntegerSeconds to wait (from API response, or nil)
attemptIntegerRetry attempt number (1-based)

Examples

StatsD Metrics

ChatSDK::Instrumentation.subscribe("handler.chat_sdk") do |_, payload|
  StatsD.timing("chat_sdk.handler.#{payload[:handler_type]}", payload[:duration] * 1000)
end

ChatSDK::Instrumentation.subscribe("api_request.chat_sdk") do |_, payload|
  StatsD.timing("chat_sdk.api.#{payload[:adapter]}.#{payload[:method]}", payload[:duration] * 1000)
end

ChatSDK::Instrumentation.subscribe("rate_limited.chat_sdk") do |_, payload|
  StatsD.increment("chat_sdk.rate_limited.#{payload[:adapter]}")
end

Structured Logging

ChatSDK::Instrumentation.subscribe("dispatch.chat_sdk") do |_, payload|
  Rails.logger.info({
    event: "chat_sdk.dispatch",
    adapter: payload[:adapter],
    type: payload[:event_type],
    duration_ms: (payload[:duration] * 1000).round(1)
  }.to_json)
end

ActiveSupport::Notifications Bridge

ChatSDK::Instrumentation.subscribe("handler.chat_sdk") do |name, payload|
  ActiveSupport::Notifications.instrument(name, payload)
end

Unsubscribing

block = ChatSDK::Instrumentation.subscribe("handler.chat_sdk") { |_, p| ... }

# Later:
ChatSDK::Instrumentation.unsubscribe("handler.chat_sdk", block)

Testing

Use ChatSDK::Instrumentation.reset! in test teardown to clear all subscribers:

RSpec.configure do |config|
  config.after { ChatSDK::Instrumentation.reset! }
end

On this page