Integração com Sinatra
Integre o ImmutableLog em qualquer aplicação Sinatra com os filtros `before`/`after` e o bloco `error`. Reutiliza o cliente `ImmutableLog` (Net::HTTP) e envia o evento em uma Thread fire-and-forget.
Reaproveite o cliente
O Sinatra reutiliza a classe `ImmutableLog` (Net::HTTP) da página principal de Ruby — incluindo `sanitize_trail`, headers de timezone e a Idempotency-Key. Copie-a de lá; aqui mostramos apenas os filtros.
Filtros before / after / error
Registre os filtros na sua classe Sinatra. `before` captura o início; `after` classifica e envia o evento; `error` captura exceções não tratadas.
# app.rb
require "sinatra/base"
require "securerandom"
require_relative "immutable_log" # a classe ImmutableLog da página Ruby
class App < Sinatra::Base
SKIP = ["/health", "/healthz"].freeze
configure do
set :imtbl, ImmutableLog.new(
api_key: ENV["IMTBL_API_KEY"],
service: "sinatra-service",
env: ENV.fetch("RACK_ENV", "production"),
)
end
before do
@imtbl_started = Process.clock_gettime(Process::CLOCK_MONOTONIC)
@imtbl_request_id = request.env["HTTP_X_REQUEST_ID"] || SecureRandom.uuid
end
after do
next if SKIP.include?(request.path_info)
latency_ms = ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - @imtbl_started) * 1000).to_i
status = response.status
kind = if status >= 400 then "error"
elsif status >= 300 then "info"
elsif status >= 200 then "success"
else "info" end
event_name = @imtbl_event_name || "http.#{request.request_method}.#{request.path_info}"
trail = @imtbl_trail || request.env["HTTP_X_IMTBL_TRAIL"]
payload = {
"id" => SecureRandom.uuid,
"kind" => kind,
"message" => "#{request.request_method} #{request.path_info} -> #{status}",
"context" => { "ip" => request.ip, "user_agent" => request.user_agent || "unknown" },
"request" => { "request_id" => @imtbl_request_id,
"method" => request.request_method, "path" => request.path_info },
"metrics" => { "latency_ms" => latency_ms, "status_code" => status },
"severity" => kind == "error" ? "high" : "low",
}
# fire-and-forget — nao bloqueia a resposta.
Thread.new do
settings.imtbl.send_event(
event_name: event_name, kind: kind, payload: payload, immutable_trail: trail,
)
rescue StandardError
# Never let audit logging break the application.
end
end
error do
err = env["sinatra.error"]
Thread.new do
settings.imtbl.send_event(
event_name: @imtbl_event_name || "http.#{request.request_method}.#{request.path_info}",
kind: "error",
payload: {
"id" => SecureRandom.uuid, "kind" => "error",
"message" => "#{request.request_method} #{request.path_info} failed: #{err&.class}",
"error" => { "status_code" => 500, "retryable" => true,
"exception" => err&.class&.name,
"exception_message" => err&.message.to_s[0, 500] },
},
immutable_trail: @imtbl_trail,
)
rescue StandardError
end
"Internal Server Error"
end
endComo funciona
before
Registra request_id e timestamp de início
after
Classifica o status e envia o evento em uma Thread
error
Captura exceções não tratadas como evento de erro
Evento e trilha customizados
Dentro de uma rota, defina as variáveis de instância `@imtbl_event_name` e `@imtbl_trail`. O filtro `after` roda no mesmo escopo da requisição e lê esses valores.
class App < Sinatra::Base
post "/payments" do
# Sobrescreve o nome do evento e agrupa numa trilha auditavel.
@imtbl_event_name = "payment.created"
@imtbl_trail = "order-7782"
# ... lógica de negócio / business logic ...
json ok: true
end
post "/flows/:id/run" do
@imtbl_trail = "flow-#{params[:id]}"
json status: "ok"
end
endPadrão automático: http.METHOD.path.
Trilha imutável (immutable_trail)
A trilha agrupa eventos relacionados em uma mesma linha do tempo auditável. Defina `@imtbl_trail` em uma rota, ou propague entre serviços com o header `X-Imtbl-Trail`. O `send_event` normaliza o valor com `sanitize_trail` antes do envio.
A trilha não pode ser vazia, exceder 256 caracteres ou conter `:` — violações retornam `400 invalid_immutable_trail`. O `sanitize_trail` corrige o valor antes do envio.
Resposta e códigos de status
A API de ingestão é assíncrona. Sucesso retorna 202 (novo) ou 200 (duplicata idempotente). Como o envio roda em uma Thread, esses códigos importam principalmente se você enviar eventos manualmente.
| Status | Significado |
|---|---|
| 202 | Evento aceito e enfileirado (novo) |
| 200 | Idempotency-Key já existente — duplicate: true |
| 400 | Idempotency-Key ausente/vazia ou invalid_immutable_trail |
| 403 | Assinatura inativa/expirada, escopo ou retenção |
| 413 | payload_too_large (limite do servidor: 16KB) |
| 429 | monthly_limit_exceeded — não fazer retry |
| 503 | mempool_full — transitório, pode dar retry |
Esta documentação reflete o comportamento atual da integração. Para dúvidas ou integrações avançadas, entre em contato com o time de suporte.
