Production-oriented Ruby client for FlameOn with low-overhead profiling defaults and opt-in higher-detail modes.
- Default to production-safe statistical profiling.
- Keep reporting asynchronous so requests and jobs do not wait on encoding or network I/O.
- Allow more detail when needed, with an explicit runtime overhead tradeoff.
- Keep mode and detail controls vendor-neutral in the code and configuration surface.
require "flame_on/client"
FlameOn::Client.configure do |config|
config.capture = true
config.mode = :sampling
config.detail_level = :standard
config.sample_rate_hz = 100
config.max_queue_size = 1_000
config.drop_policy = :drop_oldest
config.profile_allocations = false
config.service_name = 'billing-api'
config.environment = ENV.fetch('APP_ENV', 'production')
config.release = ENV.fetch('APP_RELEASE', 'dev')
config.adapter = FlameOn::Client::Adapters::GrpcAdapter.new(
endpoint: 'localhost:50051',
token: ENV.fetch('FLAME_ON_INGEST_TOKEN')
)
end
result = FlameOn::Client.capture("web.request", "GET /users/:id", threshold_ms: 500) do
"ok"
end
FlameOn::Client.flush
FlameOn::Client.stopThe client can also ship handled or unhandled exceptions to the flame_on.FlameOnErrorIngest/IngestErrors RPC over the same asynchronous background path.
begin
raise 'checkout failed'
rescue => error
FlameOn::Client.report_error(
error,
handled: true,
route: '/checkout',
trace_id: 'trace-123',
request: {
method: 'POST',
url: 'https://app.example.test/checkout',
headers: { 'x-request-id' => 'req-1' }
},
tags: { region: 'iad' },
contexts: { tenant: 'acme' }
)
endreport_errorbuilds theErrorEventpayload from the Ruby exception and backtrace.- request headers, breadcrumbs, tags, and contexts are encoded as repeated key/value pairs to match the server contract.
platform,environment,service_name, andreleasedefault from configuration and can be overridden per call.- error delivery failures are isolated from application code and tracked via
FlameOn::Client.error_stats.
Default mode. Intended for continuous production use with low overhead.
- runs a scoped sampling loop only while the capture block is executing
- samples the current thread stack at
sample_rate_hz - aggregates repeated stack paths into collapsed-stack samples for background encoding and shipping
Adds more metadata and deeper capture settings while staying sampling-based.
Higher-detail mode intended for selectively traced paths, not broad continuous use.
Highest-detail mode for temporary diagnostics.
Smaller payloads and lower overhead.
Default detail level. Good balance for continuous production profiling.
More frames and metadata.
Largest payloads and highest runtime cost.
Completed traces are handed to a bounded in-memory queue. A background reporter thread batches, processes, and ships them asynchronously.
- The caller thread only performs capture and queue handoff.
- Queue overflow never blocks the caller.
- Overflow uses a configurable drop policy.
- Adapter failures are recorded in stats and never raised into application code.
The current sampler is a scoped thread-stack sampler.
- sampling starts when
FlameOn::Client.captureenters the block - sampling stops when the block exits
- stack snapshots are aggregated into collapsed stack paths
- if a capture finishes before any sample is observed, the client falls back to a synthetic event-level sample so the trace can still be reported
This keeps the default model lightweight and avoids deterministic per-call tracing on the hot path.
- internal client frames are filtered out of sampled stacks so profiles stay focused on application code
The client includes a Rack middleware wrapper for automatic request capture.
use FlameOn::Client::Integrations::RackMiddlewareFor uncaught exceptions, add the error middleware too:
use FlameOn::Client::Integrations::RackErrorMiddleware
use FlameOn::Client::Integrations::RackMiddlewareOr build the full stack in one step:
app = FlameOn::Client::Integrations.build_rack_stack(app)For Rails, use the installer in an initializer:
FlameOn::Client::Integrations::Rails.install!(Rails.application)The Rails helper installs both middlewares, uses rails.request as the event name, derives request identifiers from controller#action when available, and tags error events with controller, action, and request_id.
By default it emits:
- event name:
rack.request - event identifier:
METHOD /path - metadata: request method, path, and query string
You can also customize it:
use FlameOn::Client::Integrations::RackMiddleware,
event_name: 'web.request',
threshold_ms: 250,
identifier: ->(env) { "#{env['REQUEST_METHOD']} #{env['PATH_INFO']}" },
metadata: ->(env) { { 'host' => env['HTTP_HOST'] } }RackErrorMiddleware reports the exception, includes request URL, method, path, headers, and remote address, then re-raises so your normal Rack error handling still applies.
| Setting | Default | Description |
|---|---|---|
capture |
false |
Enables or disables capture entirely |
mode |
:sampling |
Profiling strategy |
detail_level |
:standard |
Payload fidelity |
sample_rate_hz |
100 |
Sampling frequency hint |
max_frames |
400 |
Maximum frame depth |
profile_cpu |
true |
Capture CPU-oriented profiles |
profile_wall |
true |
Capture wall-clock-oriented profiles |
profile_allocations |
false |
Capture allocation profiling |
max_queue_size |
1_000 |
Reporter queue capacity |
max_batch_size |
50 |
Reporter batch size |
flush_interval_ms |
5_000 |
Background flush interval |
drop_policy |
:drop_oldest |
Queue overflow behavior |
deep_trace_enabled |
false |
Allows tracing-oriented engines |
deep_trace_sample_rate |
0.0 |
Fraction of captures eligible for deep tracing |
default_threshold_ms |
0 |
Drop traces below this duration |
platform |
"ruby" |
Default error-reporting platform |
environment |
detected or "production" |
Default error-reporting environment |
service_name |
ENV['FLAME_ON_SERVICE_NAME'] |
Default error-reporting service |
release |
ENV['FLAME_ON_RELEASE'] |
Default error-reporting release |
adapter |
FlameOn::Client::Adapters::NullAdapter.new |
Async delivery adapter |
processor |
FlameOn::Client::Processors::ProfileProcessor.new |
Background trace processor |
The client includes an opt-in gRPC adapter for FlameOn ingestion. Completed traces are encoded into pprof Profile payloads and sent to the flame_on.FlameOnIngest/Ingest RPC with bearer-token metadata. Error events are sent to flame_on.FlameOnErrorIngest/IngestErrors with the same bearer-token metadata.
FlameOn::Client.configure do |config|
config.capture = true
config.adapter = FlameOn::Client::Adapters::GrpcAdapter.new(
endpoint: 'flameon.example.com:443',
token: ENV.fetch('FLAME_ON_INGEST_TOKEN'),
channel_credentials: :this_channel_is_insecure
)
end- pprof encoding runs on the background reporter thread
- error event encoding runs on a separate background reporter thread
- the caller thread still only does capture and queue handoff
- transport failures stay isolated from application code
This initial implementation provides:
- configuration and policy modeling
- mode selection
- manual capture API
- asynchronous bounded reporter
- non-blocking queue overflow handling
- adapter and processor interfaces
- real scoped stack sampling for
:samplingand:enhanced_sampling - pprof encoding and gRPC delivery support
- error event encoding and gRPC delivery support
- Rack middleware integration for automatic request capture
It does not yet include framework integrations, allocation sampling, or a native VM sampling extension.
Run the tests with:
ruby -Ilib:test -e 'Dir["test/**/*_test.rb"].sort.each { |file| require File.expand_path(file) }'MIT. See LICENSE.