e-volv
Docs menu

Ruby

e-volv-logs is the e-volv Launch SDK for Ruby 2.6 and later — standard library only, no runtime dependencies. It is a server SDK: with a server key (evk_…) it receives the environment’s full ruleset and evaluates flags locally, so a flag check never performs I/O, never blocks and never raises. Delivery is a stream of change notifications (SSE) with a polling fallback, run on its own e-volv-flags thread so a held-open stream never stalls log flushing; a last-known cache on disk and exposure tracking ride the same key and transport as your logs. The behaviour is pinned by the Launch SDK contract, and both conformance suites — the kernel fixture and the delivery driver — run in CI.

Install

shell
gem install e-volv-logs
# or in a Gemfile:
gem "e-volv-logs"

Native API

ruby
require "evolve_logs"

EvolveLogs.init(
  key: ENV["EVOLVE_KEY"], # a server key (evk_…), from the environment
  url: "https://api.e-volv.io/api/public/v1/logs",
  service: "orders-api",
  flags: { mode: "stream" } # optional; see the options table
)

EvolveLogs.flags.ready(timeout: 5) # optional: true once the first ruleset arrived

if EvolveLogs.flags.bool("checkout.new", false, { "targetingKey" => user.id, "plan" => user.plan })
  render_new_checkout
end

# The full detail when you need the variant and the reason:
d = EvolveLogs.flags.detail("checkout.banner", "default", { "targetingKey" => user.id })
# d.value, d.variant ("on" | "off" | "control" | …), d.reason
# ("RULE:0" | "ROLLOUT" | "TARGET_MATCH" | "DEFAULT" | "FLAG_NOT_FOUND" | …)

Evaluation methods: bool, string, number, json and detail — all synchronous, all safe. detail returns an Evaluation struct with value, variant and reason readers. A flag whose served value is not of the requested type returns your default with reason TYPE_MISMATCH; a flag absent from the ruleset returns your default with FLAG_NOT_FOUND. The handle is EvolveLogs.flags on the default client, or client.flags on an EvolveLogs::Client.new instance.

Options

Flags are configured under the flags keyword of the existing EvolveLogs.init — a Hash (string or symbol keys) or an EvolveLogs::Flags::Options:

OptionDefaultMeaning
enabledtrueStart the flags client. False gives a defaults-only stub with no threads.
mode'stream'stream | poll | offline. Offline never contacts the control plane (bootstrap snapshot or defaults only).
poll_interval_seconds30 (min 15)Poll period once streaming has fallen back.
urlderivedBase URL ending in /api/public/v1/flags; defaults to the origin of the Observer url option, else the e-volv cloud.
cacheplatform tmp dirWhere the last-known ruleset is kept (one file per key, sha1-hashed name, atomic write). False disables.
bootstrapnoneA bundled ruleset served before the first fetch completes.
stale_after_seconds300Log a one-line staleness warning after this long without a confirmation from the control plane.
exposures.enabledtrueRecord an exposure on each evaluation of a flag present in the ruleset.
exposures.sample_rate1.0Probability an evaluation is recorded; sent as sampleRate.
exposures.dedupe_window_seconds60Suppress repeats of the same (flag, variant, kind, subject) within the window; suppressed counts ride the next exposure.
exposures.send_attributesfalseSend context attributes with exposures (private attributes are always removed).
private_attributes[]Attribute names never sent anywhere.

Install check and lifecycle

ruby
# Install check: is this key bound, and to which environment?
ping = EvolveLogs.flags.verify
# { "environment" => "production", "keyKind" => "server", "flags" => 42, "etag" => "3f2a…" }
# nil when the control plane did not answer.

flags.ready(timeout: 5) waits for the first ruleset (only if you choose to), flags.last_updated_at reports the last confirmed update in epoch seconds, and flags.on_change { |keys| } notifies with the keys whose values changed, returning an unsubscribe proc. flags.flush_exposures drains the exposure buffer; it also runs from EvolveLogs.flush.

ruby
# On shutdown (e.g. before a deploy, or in a Rake task's ensure block):
client = EvolveLogs.init(key: ENV["EVOLVE_KEY"], url: "https://api.e-volv.io/api/public/v1/logs")
# …
client.close # stops the e-volv-flags threads, then flushes pending exposures

Troubleshooting by status code

Evaluation never breaks because of the control plane — it degrades. Conditions are logged once on stderr, not once per evaluation. What each response means for the SDK (contract §2.6):

ResponseSDK behaviour
401Key invalid or revoked. The SDK keeps serving held values or defaults, logs once on stderr, and retries bootstrap every 5 minutes.
403 — lacks the scope flags:readFlags are disabled for this key with one warning; telemetry is unaffected. No retry until re-init.
404Launch is not enabled for the workspace, or the key is not bound to an environment. Same handling as 401.
429Honours Retry-After (seconds, minimum 1 s); a stream 429 falls back to polling. The delivery rate limit is 3,000 requests/min per key.
5xx, timeout, network errorRetries with full-jitter exponential backoff — random(0, min(60, 2^attempt)) seconds — while serving the last held values.

Guarantees

  • A flag check is local and synchronous — bounded by CPU, not the network; ready(timeout:) is the only call that waits, and only when you ask it to.
  • An unreachable or slow control plane never changes an answer mid-flag: the last held ruleset (or a valid cache, or your defaults) keeps serving while the SDK backs off and reconnects.
  • Cold start reads the on-disk cache instantly and swaps to a fresh ruleset without a flicker for unchanged flags; corrupt, oversized or other-environment caches are ignored and overwritten.
  • Delivery threads survive fork — they relaunch on the first evaluation in a forked child (Puma, Unicorn, Resque, Sidekiq), and a held-open stream never stalls log flushing.
  • Exposures are sampled, de-duplicated, capped (a 10,000-row buffer drops oldest first) and retried with the same policy as your logs — telemetry you can trust as much as the flag answers themselves.
  • Evaluation is byte-for-byte identical to every other e-volv SDK: the Ruby kernel is a port held to packages/flags-kernel/fixture.json.

Back to e-volv Launch, the HTTP API page documents the wire format the SDK speaks, and the SDKs index lists every platform.