e-volv
Docs menu

Ruby

e-volv-logs is the SDK for Ruby 2.6 or later. Standard library only — no runtime dependencies — with rack and faraday as soft, duck-typed integrations and nothing monkeypatched. It speaks the same wire contract as the Node.js, Python, Go and Java SDKs.

Install and initialise

text
gem install e-volv-logs
# or in a Gemfile:
gem "e-volv-logs"
ruby
require "evolve_logs"

EvolveLogs.init(
  key: ENV["EVOLVE_LOGS_KEY"], # project ingest key — a server key, from the environment
  url: "https://api.e-volv.io/api/public/v1/logs",
  service: "orders-api",
  environment: ENV["RACK_ENV"],
  release: ENV["GIT_SHA"]
)

EvolveLogs.info("order created", { "orderId" => "o_1", "total" => 42.5 })
EvolveLogs.error("payment failed", { "orderId" => "o_1" })

begin
  charge
rescue StandardError => err
  EvolveLogs.exception(err, { "orderId" => "o_1" }) # exception.type/message/stack
end

If key or url is empty, init returns a no-op client and warns once on stderr — the SDK never raises into your code. EvolveLogs::Client.new(...) builds a non-default client; the module-level helpers delegate to the client installed by EvolveLogs.init.

Traces and spans

Trace context lives in Thread.current (fiber-local): it flows into fibers under the current thread and never leaks across threads.

ruby
EvolveLogs.span("db.query", { "table" => "orders" }) do
  db.query("SELECT …")
end # an exception inside ends the span as failed and is re-raised

The span end is recorded as an event with span.name and durationMs, carrying the span’s trace and span ids. EvolveLogs.traceparent returns the W3C 00-<traceId>-<spanId>-01 header, or nil outside a trace.

Rack and Rails

ruby
# config.ru — one root span per request; an inbound traceparent is continued
use EvolveLogs::RackMiddleware
ruby
# config/application.rb — every Rails.logger line also ships to Observer;
# Rails.logger.error(err) carries exception.*
config.logger = EvolveLogs::Logger.new($stdout)

An app that raises ends the http.request span as failed and is re-raised, so the server crashes exactly as it would without the SDK.

Queue hops: ActiveJob and Sidekiq

ruby
# producer
MyJob.perform_later(args, traceparent: EvolveLogs.traceparent)

# consumer
EvolveLogs::ActiveJob.perform(
  EvolveLogs::ActiveJob.traceparent_in(arguments),
  self.class.name
) do
  # one trace with the producer
end

EvolveLogs::Sidekiq.perform(traceparent, worker, attrs) { … } is the Sidekiq shape; EvolveLogs::Carriers.wrap(header, span_name, attrs){ … } covers anything else. For raw headers, EvolveLogs.run_with_traceparent(header) { … } runs the block with the next hop of that trace — an absent or malformed header starts a fresh trace.

Outbound HTTP: Net::HTTP and Faraday

Monkeypatch-free — opt in per call site:

ruby
request = Net::HTTP::Post.new(uri)
EvolveLogs::HTTP.inject_traceparent(request) # never overwrites an existing header
http.request(request)
ruby
conn = Faraday.new(url: "https://internal") do |builder|
  builder.use EvolveLogs::FaradayMiddleware
  builder.adapter Faraday.default_adapter
end

Delivery

The shared numbers: flush at 200 events, every 2 seconds or at 512 KB, always gzipped. A 429 honours Retry-After, otherwise exponential backoff from 500 ms (doubling, capped at 10 s), up to three attempts; a 413 halves the batch and counts the excess half. Past twice the batch size the oldest events drop, visible on client.dropped. The SDK installs an at_exit hook and EvolveLogs.flush is safe to call repeatedly.

Already emit OpenTelemetry? The Ruby preset in packages/logs-otel-presets remains a valid route — point the OTel Ruby SDK at the ingest with one file. See OpenTelemetry presets.

Package reference: packages/logs-ruby. Back to SDK overview.