# Ruby Integration Guide

> Add TraceKit to your Ruby applications for automatic distributed tracing. Debug production Ruby services with dynamic logs and Rails/Sinatra support.

- Canonical: https://tracekit.dev/docs/languages/ruby

Learn how to instrument your Ruby applications with the TraceKit Ruby SDK for distributed tracing, metrics, and code monitoring.

**Let AI set up TraceKit for you** -- AI assistants can guide you through the entire setup process. [Try AI Setup](/docs/ai)

## Prerequisites

- Ruby 2.7 or higher (Ruby 3.0+ recommended)
- A TraceKit account ([create one free](https://app.tracekit.dev/register))
- A generated API key from the [API Keys](https://app.tracekit.dev/api-keys) page

## What Gets Traced Automatically?

With proper setup, these operations are traced automatically with zero manual instrumentation:

| Component | Span Type | Captured Attributes | Auto-Traced? |
|-----------|-----------|-------------------|-------------|
| HTTP Endpoints | SERVER | method, route, status_code, duration, client_ip | Yes |
| ActiveRecord Queries | DB | db.system, db.statement, db.name, duration | Yes |
| HTTP Client Calls | CLIENT | method, url, status_code, duration, peer.service | Yes |
| Redis Operations | DB | db.system (redis), db.statement, duration | Yes |
| Sidekiq Jobs | Custom | job.class, job.id, queue, duration | Yes |
| Custom Business Logic | Custom | user-defined attributes | Manual |

## Installation

Add the TraceKit Ruby SDK to your Gemfile:

```ruby
# Gemfile
gem 'tracekit'

# Then run:
bundle install
```

## Basic Setup

### Rails Applications (Auto-Configuration via .env)

For Rails applications, TraceKit automatically configures itself using environment variables:

```bash
# .env file
TRACEKIT_API_KEY=ctxio_abc123...
TRACEKIT_ENDPOINT=https://app.tracekit.dev
TRACEKIT_SERVICE_NAME=my-rails-app
TRACEKIT_ENVIRONMENT=production
TRACEKIT_CODE_MONITORING=true

# That's it! The TraceKit Railtie automatically:
# - Loads configuration from ENV variables
# - Initializes OpenTelemetry with OTLP exporters
# - Adds Rack middleware for request instrumentation
# - Sets up graceful shutdown
```

### Non-Rails Applications (Manual Configuration)

For non-Rails applications, configure the SDK manually:

```ruby
require 'tracekit'

# Configure the SDK
Tracekit.configure do |config|
  config.api_key = ENV['TRACEKIT_API_KEY']
  config.service_name = 'my-service'
  config.endpoint = 'https://app.tracekit.dev'
  config.environment = 'production'
  config.enable_code_monitoring = true
end

# For Rack applications, add middleware
use Tracekit::Middleware

# At application shutdown
at_exit { Tracekit.shutdown }
```

**Verify It Works** -- Start your application and make a few requests. Then open the [Traces page](https://app.tracekit.dev/traces) in your TraceKit dashboard. You should see:

- SERVER spans for each incoming request to Rails routes
- CLIENT spans for outgoing HTTP calls (if using Net::HTTP/Faraday instrumentation)
- DB spans for ActiveRecord queries (if instrumented)

Traces typically appear within 30 seconds. If you don't see them, check the [Troubleshooting](#troubleshooting) section.

## Framework Integration

TraceKit SDK provides first-class support for popular Ruby frameworks with automatic instrumentation.

### Ruby on Rails

```ruby
# Your controllers are automatically traced!
class UsersController < ApplicationController
  def index
    # This action is automatically traced!
    @users = User.all
    render json: @users
  end

  def create
    sdk = Tracekit.sdk

    # Track metrics
    sdk.counter("user.created").add(1)

    # Capture snapshot with context
    sdk.capture_snapshot("user-create", {
      email: params[:email],
      name: params[:name]
    })

    @user = User.create!(user_params)
    render json: @user, status: :created
  end

  private

  def user_params
    params.require(:user).permit(:name, :email)
  end
end
```

### Sinatra

```ruby
# app.rb
require 'sinatra'
require 'tracekit'

# Configure TraceKit
Tracekit.configure do |config|
  config.api_key = ENV['TRACEKIT_API_KEY']
  config.service_name = 'my-sinatra-app'
  config.endpoint = 'https://app.tracekit.dev'
end

# Add TraceKit middleware
use Tracekit::Middleware

# Routes are automatically traced!
get '/api/users' do
  sdk = Tracekit.sdk

  # Track metrics
  sdk.counter("api.users.requests").add(1)

  content_type :json
  User.all.to_json
end
```

## Automatic Instrumentation Libraries

These libraries automatically create child spans for common operations. Set them up once, and every call is traced automatically.

### ActiveRecord Queries

Automatically trace all database operations:

```ruby
# ActiveRecord is automatically instrumented by TraceKit

# All queries are automatically traced!
User.all                    # Traced!
User.find(1)               # Traced!
User.where(active: true)   # Traced!
User.create(name: 'Alice') # Traced!
```

### HTTP Client Calls

Automatically trace all outgoing HTTP requests:

```ruby
# Net::HTTP is automatically instrumented by TraceKit

require 'net/http'

# All HTTP requests are automatically traced!
uri = URI('https://api.example.com/users')
response = Net::HTTP.get_response(uri)  # Traced!
```

### Redis Operations

Trace Redis commands automatically:

```ruby
# Redis operations are automatically traced by TraceKit
redis = Redis.new(host: 'localhost', port: 6379)

redis.set('key', 'value')  # Traced!
redis.get('key')           # Traced!
```

## Manual Instrumentation (Optional)

For custom business logic that isn't covered by auto-instrumentation libraries, you can manually create spans. **This is optional** and only needed for specific operations you want to measure.

```ruby
def process_order(order_id)
  sdk = Tracekit.sdk

  # Capture snapshot at key moments
  sdk.capture_snapshot("order-processing-start", {
    orderId: order_id,
    status: "processing"
  })

  # Track metrics
  sdk.counter("orders.processed").add(1)
  sdk.gauge("orders.active").inc

  # Validation logic here...

  # Track duration
  start_time = Time.now
  result = charge_payment(order_id)
  duration_ms = ((Time.now - start_time) * 1000).round(2)

  sdk.histogram("order.payment.duration").record(duration_ms)

  # Capture completion snapshot
  sdk.capture_snapshot("order-processing-complete", {
    orderId: order_id,
    status: "completed",
    duration: duration_ms
  })

  sdk.gauge("orders.active").dec
end
```

### SDK.current API

Access the configured SDK singleton from anywhere in your application:

| Method | Parameters | Returns | Description |
|--------|-----------|---------|-------------|
| `SDK.current` | none | SDK | Returns the current SDK singleton instance. Use after SDK.configure(). |

### SDK.current Example

```ruby
# After configuration:
Tracekit::SDK.configure(config)

# Access anywhere in your application:
sdk = Tracekit::SDK.current
sdk.capture_snapshot("checkout", { order_id: order.id, total: total })
sdk.counter("orders.processed").inc
```

### Supporting Types

Internal and advanced types used by the SDK (not intended for direct use):

| Symbol | Type | Description |
|--------|------|-------------|
| `EndpointResolver` | Class (Internal) | Resolves API endpoint URLs. Handles protocol selection and path construction. |
| `LocalUI::Detector` | Class (Internal) | Detects when TraceKit Local UI is running on the configured port. |
| `Security::Detector` | Class (Advanced) | Detects PII and credentials in snapshot variables. Automatically applied during capture. |
| `Snapshots::Client` | Class (Internal) | Used for breakpoint polling and snapshot transmission. Use `capture_snapshot()` instead. |

## Code Monitoring (Dynamic Logs)

**Production-Safe Dynamic Logs** -- Capture variable state, stack traces, and request context at any point in your code without redeployment. Perfect for debugging production issues! [Full Code Monitoring Documentation](/docs/code-monitoring)

### Enable Code Monitoring

Enable code monitoring when initializing TraceKit:

```ruby
# config/initializers/tracekit.rb
Tracekit::SDK.configure do |c|
  c.api_key              = ENV['TRACEKIT_API_KEY']
  c.service_name         = "my-rails-app"
  c.enable_code_monitoring = true  # defaults to true in Ruby SDK
end
```

Code monitoring defaults to `true` in the Ruby SDK. The snippet above is shown for clarity -- you can omit `enable_code_monitoring` and it will be enabled automatically.

### Capture Snapshots

Use `capture_snapshot` to capture variable state at specific points:

```ruby
# In a Rails controller
class OrdersController < ApplicationController
  def create
    order = Order.new(order_params)
    user  = current_user

    # Instance method -- capture via the SDK singleton
    sdk = Tracekit::SDK.current
    sdk.capture_snapshot('order-create', {
      order_id: order.id,
      total:    order.total,
      user_id:  user.id,
      items:    order.line_items.count
    })

    # Module convenience method -- same result, shorter syntax
    Tracekit.capture_snapshot('order-validate', {
      valid:  order.valid?,
      errors: order.errors.full_messages
    })

    if order.save
      redirect_to order_path(order)
    else
      render :new
    end
  end
end
```

### Features

- **Auto-Registration** -- Breakpoints automatically created on first `capture_snapshot` call
- **Variable Capture** -- Deep inspection of hashes, arrays, and Ruby objects
- **Stack Traces** -- Full call stack with file and line numbers via `caller_locations`
- **Request Context** -- HTTP method, route, headers, and query params from Rack env

### Production Safety

The Ruby SDK v6.0 includes multiple layers of production safety built into code monitoring:

- **PII Scrubbing** -- 13 built-in patterns via `Security::Patterns`. Enabled by default with typed `[REDACTED:type]` markers for auditability.
- **Crash Isolation** -- `begin/rescue` on all entry points. Snapshot failures never propagate to application code.
- **Circuit Breaker** -- 3 failures in 60s triggers a 5-minute cooldown. `Mutex`-based thread safety for concurrent environments.
- **Remote Kill Switch** -- Dashboard toggle to disable code monitoring instantly. Propagates to all SDK instances via SSE (`Net::HTTP` streaming in daemon thread).

**Real-Time Updates** -- The Ruby SDK receives configuration changes (kill switch, breakpoint updates) in real time via Server-Sent Events (SSE). The SSE connection uses `Net::HTTP` streaming in a daemon thread, so it does not block your application and is automatically cleaned up when the process exits.

### Code Monitoring API

| Method | Parameters | Returns | Description |
|--------|-----------|---------|-------------|
| `sdk.capture_snapshot(label, vars)` | label: String, vars: Hash | nil | Capture variable state at this point. Only fires when a breakpoint is active. |
| `Tracekit.capture_snapshot(label, vars)` | label: String, vars: Hash | nil | Module-level convenience method. Delegates to `SDK.current.capture_snapshot`. |
| `capture_depth` | Integer | Default: 3 | Maximum depth for nested object inspection. |
| `max_payload` | Integer (bytes) | Default: 65536 | Maximum size of a single snapshot payload. |
| `capture_timeout` | Float (seconds) | Default: 5.0 | Timeout for snapshot capture and transmission. |
| `pii_scrubbing` | Boolean | Default: true | Enable PII scrubbing via `Security::Patterns`. |
| `circuit_breaker` | Hash | Default: `{ threshold: 3, window: 60, cooldown: 300 }` | Circuit breaker configuration. |

### End-to-End Workflow

1. **Enable Code Monitoring** -- Defaults to enabled in the Ruby SDK. Explicitly set for clarity or use `TRACEKIT_CODE_MONITORING=true`.
2. **Add Capture Points** -- Place `capture_snapshot` calls at code paths you want to debug.
3. **Deploy and Verify Traces** -- Deploy and check the [Traces dashboard](https://app.tracekit.dev/traces).
4. **Navigate to Code Monitoring** -- Go to [/snapshots](https://app.tracekit.dev/snapshots) and click "Browse Code".
5. **Set Breakpoints** -- Auto-registered on first `capture_snapshot` call, or manually via the UI.
6. **Trigger a Capture** -- Make a request that hits a code path with `capture_snapshot`.
7. **View Snapshot** -- Inspect variables, call stack, request context, security flags, and trace link.

### v25: Enhanced Code Monitoring

#### Log-Point Mode

When a breakpoint is set to **log-point mode** in the dashboard, the SDK captures only the specified expressions -- no local variables, stack traces, or request context. This dramatically reduces overhead for high-frequency code paths.

No code changes needed. The SDK reads the breakpoint's `mode` field from the server and adjusts capture behavior automatically.

#### SDK-Side Condition Evaluation

Breakpoint conditions (e.g., `status > 200`) are now evaluated **locally in the SDK** without a server round-trip. The server classifies each condition as `sdk-evaluable` or `server-only` at creation time. Simple expressions (comparisons, boolean logic, property access) are evaluated in-process.

No code changes needed. The SDK checks the `condition_eval` field and evaluates locally when possible.

#### Per-Breakpoint Capture Limits

New breakpoints default to:
- **max_depth: 5** -- variables nested deeper than 5 levels are truncated
- **max_payload_bytes: 128KB** -- snapshots larger than 128KB are truncated

These limits are configurable per breakpoint in the dashboard. The SDK respects per-breakpoint overrides automatically.

#### Auto-Expire

New breakpoints **auto-expire after 48 hours of inactivity**. Each capture resets the timer. Pin a breakpoint in the dashboard to prevent auto-expiry.

Existing breakpoints are not affected -- auto-expire only applies to breakpoints created after the v25 update.

## LLM Instrumentation

TraceKit automatically instruments OpenAI and Anthropic API calls when detected. LLM calls appear as spans with [OTel GenAI semantic convention](https://opentelemetry.io/docs/specs/semconv/gen-ai/) attributes.

**Zero-config auto-instrumentation** -- If the `openai` or `anthropic` gem is installed, TraceKit patches them automatically via `Module#prepend` at init. No code changes required.

### Captured Attributes

| Attribute | Description |
|-----------|-------------|
| `gen_ai.system` | Provider name (openai, anthropic) |
| `gen_ai.request.model` | Model name (gpt-4o, claude-sonnet-4-20250514, etc.) |
| `gen_ai.usage.input_tokens` | Prompt token count |
| `gen_ai.usage.output_tokens` | Completion token count |
| `gen_ai.response.finish_reasons` | Finish reason (stop, end_turn, tool_calls) |

### Configuration

```ruby
Tracekit.configure do |c|
  c.api_key = ENV['TRACEKIT_API_KEY']
  c.service_name = 'my-ruby-service'
  c.llm.enabled = true          # Master toggle
  c.llm.openai = true           # OpenAI instrumentation
  c.llm.anthropic = true        # Anthropic instrumentation
  c.llm.capture_content = false # Capture prompts/completions (off by default)
end
```

### Environment Variable Override

Use `TRACEKIT_LLM_CAPTURE_CONTENT=true` to enable prompt/completion capture without code changes. Useful for enabling in staging but not production.

### Streaming Support

Streaming responses produce a single span that covers the entire stream. Token counts are accumulated from the final chunk. No special configuration needed.

### LLM Dashboard

View LLM cost, token usage, and latency metrics on the dedicated **LLM Observability** dashboard at `/ai/llm` in your TraceKit instance.

## Environment Variables

Best practice: Store sensitive configuration in environment variables:

```bash
# .env
TRACEKIT_API_KEY=ctxio_your_generated_api_key_here
TRACEKIT_ENDPOINT=https://app.tracekit.dev
TRACEKIT_SERVICE_NAME=my-rails-app
TRACEKIT_ENVIRONMENT=production
TRACEKIT_CODE_MONITORING=true
```

### Config Fields Reference

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `api_key` | String | *required* | Your TraceKit API key for authentication |
| `service_name` | String | "ruby-app" | Name of your service in the trace dashboard |
| `endpoint` | String | "app.tracekit.dev" | TraceKit collector endpoint URL |
| `enabled` | Boolean | true | Enable or disable tracing globally |
| `sample_rate` | Float | 1.0 | Trace sampling rate (0.0 to 1.0) |
| `enable_code_monitoring` | Boolean | false | Enable live code debugging / snapshot capture |

These fields are set via `Config.build { |c| c.api_key = '...' }` block syntax or through the `Tracekit.configure` block.

### Environment Variable Reference

| Option | Type | Default | Env Variable | Description |
|--------|------|---------|-------------|-------------|
| `api_key` | String | *required* | `TRACEKIT_API_KEY` | Your TraceKit API key for authentication |
| `service_name` | String | *required* | `TRACEKIT_SERVICE_NAME` | Name of your service in the trace dashboard |
| `endpoint` | String | "app.tracekit.dev" | `TRACEKIT_ENDPOINT` | TraceKit collector endpoint URL |
| `use_ssl` | Boolean | true | `TRACEKIT_USE_SSL` | Enable TLS for the exporter connection |
| `environment` | String | "production" | `TRACEKIT_ENVIRONMENT` | Deployment environment |
| `service_version` | String | "1.0.0" | `TRACEKIT_SERVICE_VERSION` | Version of your service |
| `enable_code_monitoring` | Boolean | true | `TRACEKIT_CODE_MONITORING_ENABLED` | Enable live code debugging |
| `code_monitoring_poll_interval` | Integer | 30 | `TRACEKIT_CODE_MONITORING_POLL_INTERVAL` | How often to poll for active breakpoints (seconds) |
| `local_ui_port` | Integer | 9999 | `TRACEKIT_LOCAL_UI_PORT` | Port for the local development UI |
| `sampling_rate` | Float | 1.0 | `TRACEKIT_SAMPLE_RATE` | Trace sampling rate (0.0 to 1.0) |

The Ruby SDK does not auto-read environment variables. Read them with `ENV['TRACEKIT_*']` and pass to the builder.

## Production Configuration

**Production Checklist:**
- Use HTTPS/TLS for the OTLP endpoint
- Store API keys in a secrets manager (AWS Secrets Manager, HashiCorp Vault)
- Set appropriate service names and versions
- Configure resource attributes (deployment.environment, host.name, etc.)
- Adjust sampling rates if needed for high-traffic services

## Troubleshooting

### Traces not appearing?

**Cause:** The SDK is not initialized or required gems are missing.

**Fix:**
- Verify `Tracekit.configure` block is called at application startup (in an initializer for Rails)
- Check that api_key is set
- Look for errors in application logs
- Confirm `sampling_rate` is not 0

### Missing gem errors?

**Cause:** Ruby OTel gems must be explicitly listed in the Gemfile.

**Fix:**
- Add all required gems: `gem 'tracekit'`, `gem 'opentelemetry-api'`, `gem 'opentelemetry-sdk'`, and any instrumentation gems
- Run `bundle install`
- Verify with `bundle list | grep opentelemetry`

### Code monitoring not working?

**Cause:** The `capture_snapshot` method is not being called or permissions are insufficient.

**Fix:**
- Code monitoring defaults to `true` in the Ruby SDK
- Add `Tracekit.capture_snapshot('label')` calls in your code
- Reduce `code_monitoring_poll_interval` to 5 for testing
- Verify API key permissions in the dashboard

### Authentication errors (401/403)?

**Cause:** API key is missing, empty, or invalid.

**Fix:**
- Verify with `puts ENV['TRACEKIT_API_KEY']` in Rails console
- Ensure no extra whitespace: `api_key: ENV['TRACEKIT_API_KEY']&.strip`
- Regenerate key in dashboard if expired

### Connection refused errors?

**Cause:** The TraceKit endpoint is unreachable or SSL configuration is wrong.

**Fix:**
- Test with `curl -X POST https://app.tracekit.dev/v1/traces` (expect 401)
- Verify `use_ssl: true` (default) for production
- For local development without TLS, set `use_ssl: false`
- Check that `endpoint` does not include the protocol prefix if `use_ssl` is being used

## Complete Example

Here's a complete working Rails example:

```ruby
# Complete Rails example with TraceKit SDK

# Gemfile
gem 'tracekit'

# .env
TRACEKIT_API_KEY=ctxio_your_generated_api_key_here
TRACEKIT_ENDPOINT=https://app.tracekit.dev
TRACEKIT_SERVICE_NAME=rails-api
TRACEKIT_ENVIRONMENT=production
TRACEKIT_CODE_MONITORING=true

# app/controllers/users_controller.rb
class UsersController < ApplicationController
  def index
    # Automatically traced - no code changes needed!
    @users = User.all
    render json: @users
  end

  def show
    # Automatically traced - no code changes needed!
    @user = User.find(params[:id])
    render json: @user
  end

  def create
    sdk = Tracekit.sdk

    # Track metrics
    sdk.counter("users.created").add(1)

    # Capture snapshot for debugging
    sdk.capture_snapshot("user-creation", {
      email: params[:email],
      name: params[:name]
    })

    @user = User.create!(user_params)
    render json: @user, status: :created
  end

  private

  def user_params
    params.require(:user).permit(:name, :email)
  end
end

# That's it! Your Rails app now has:
# - Distributed tracing with automatic span creation
# - Metrics collection (counters, gauges, histograms)
# - Code monitoring with non-breaking snapshots
```

**You're all set!** Your Ruby application is now sending traces to TraceKit. Visit the [Dashboard](https://app.tracekit.dev) to see your traces.

## Custom Metrics

The TraceKit Ruby SDK includes a lightweight metrics API for tracking counters, gauges, and histograms.

### Counter

Track monotonically increasing values (requests, events):

```ruby
sdk = Tracekit.sdk

# Create a counter with tags
counter = sdk.counter("http.requests.total", {
  service: "api",
  endpoint: "/users"
})

# Increment the counter
counter.add(1)
counter.add(5)  # Add specific value
```

### Gauge

Track values that can go up or down (queue size, connections):

```ruby
sdk = Tracekit.sdk

# Create a gauge
gauge = sdk.gauge("memory.usage.bytes")

# Set absolute value
gauge.set(1024 * 1024 * 512)  # 512 MB

# Increment/decrement
gauge.inc      # +1
gauge.inc(10)  # +10
gauge.dec      # -1
gauge.dec(5)   # -5
```

### Histogram

Track value distributions (latencies, sizes):

```ruby
sdk = Tracekit.sdk

# Create a histogram with tags
histogram = sdk.histogram("http.request.duration", {
  unit: "ms"
})

# Record values
histogram.record(123.45)
histogram.record(67.89)
```

Metrics are automatically buffered and exported via OTLP. View them in the Metrics Explorer.

[View Custom Metrics Guide](/docs/metrics)

## Migrating from OpenTelemetry

TraceKit wraps OpenTelemetry internally, so you get the same standards-based trace data with significantly less setup code.

### Before vs After

**Before: Raw OpenTelemetry** (~15 lines):

```ruby
require 'opentelemetry/sdk'
require 'opentelemetry-exporter-otlp'

OpenTelemetry::SDK.configure do |c|
  c.service_name = 'my-service'
  c.add_span_processor(
    OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(
      OpenTelemetry::Exporter::OTLP::Exporter.new(
        endpoint: 'https://api.tracekit.io/v1/traces',
        headers: { 'Authorization' => "Bearer #{api_key}" }
      )
    )
  )
  c.use_all # auto-instrumentation
end
```

**After: TraceKit SDK** (4 lines):

```ruby
# Rails: just set .env vars (auto-configured via Railtie)
# TRACEKIT_API_KEY=your-api-key
# TRACEKIT_SERVICE_NAME=my-service

# Non-Rails:
Tracekit.configure do |c|
  c.api_key = ENV['TRACEKIT_API_KEY']
  c.service_name = 'my-service'
end
```

### Migration Steps

1. **Add the gem:** `bundle add tracekit`
2. **Replace init code:** Remove the `OpenTelemetry::SDK.configure` block and replace with `Tracekit.configure`
3. **For Rails:** Set `TRACEKIT_API_KEY` and `TRACEKIT_SERVICE_NAME` in `.env` -- auto-configured via Railtie
4. **Remove OTel gems:** `bundle remove opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp`
5. **Verify:** Start your app and check the [Traces page](https://app.tracekit.dev/traces) for incoming data

**Key Migration Benefits:**
- **15 lines to 4 lines** -- no more boilerplate for exporters, processors, resources
- **No OTel dependency management** -- TraceKit handles version pinning internally
- **Built-in code monitoring** -- not available with raw OpenTelemetry
- **Built-in security scanning** -- automatic variable redaction on snapshots
- **Rails auto-configuration** -- Railtie handles setup from .env vars automatically

## Performance Overhead

TraceKit is built on OpenTelemetry's efficient batch processing pipeline. The SDK adds minimal overhead to your Ruby application.

| Metric | Impact | Details |
|--------|--------|---------|
| Request Tracing | < 2ms per request | Spans are batched and exported asynchronously |
| Code Monitoring (Idle) | Zero overhead | No performance impact when no active breakpoints |
| Code Monitoring (Capture) | < 5ms per snapshot | Includes variable serialization and security scanning |
| Memory Footprint | ~15-25 MB | SDK runtime and span buffer |
| SDK Initialization | < 300ms one-time | Includes OpenTelemetry provider setup and auto-instrumentation |

Performance characteristics are typical for production workloads and may vary with application complexity, request volume, and number of instrumented libraries. Use [sampling configuration](#environment-variables) to reduce overhead in high-traffic services.

## Best Practices

**DO:**
- For Rails, rely on Railtie auto-init -- just add the gem and configure via environment variables
- For non-Rails apps (Sinatra), init in `config.ru` before `run`
- Use environment variables for API keys -- store in `TRACEKIT_API_KEY` rather than hardcoding
- Enable code monitoring in staging first before production
- Use sampling in high-traffic services -- set `TRACEKIT_SAMPLING_RATE` below 1.0
- Set meaningful service names for easy identification in the trace viewer

**DON'T:**
- Call `Tracekit.configure` in Rails apps -- the Railtie handles initialization automatically
- Create spans for every function -- trace boundaries like HTTP handlers, DB calls, and external services
- Add high-cardinality attributes -- avoid user IDs, request IDs, or session tokens as span attributes
- Disable TLS in production -- the `TRACEKIT_INSECURE` flag is for local development only

## Next Steps

- Add auto-instrumentation libraries for components you use (Redis, Sidekiq, MongoDB, etc.)
- Explore your traces on the [Traces page](https://app.tracekit.dev/traces) to identify performance bottlenecks
- Optionally add custom spans for specific business logic you want to measure
- Configure sampling for high-traffic services to reduce overhead
- Set up [alert rules](/docs/alerts) to get notified when issues occur
