> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hyperprobe.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Ruby SDK Setup Guide

> Install, initialize, and optimize the HyperProbe Ruby and JRuby SDK inside in-process Ruby applications.

The HyperProbe Ruby SDK runs as an in-process agent for standard Ruby (CRuby) and JRuby. It captures variable snapshots, stack frames, metrics, and logs without adding logging statements to your application. Capture overhead depends on your probes and workload.

***

## Technical Prerequisites

* **Standard Ruby (CRuby):** Ruby 3.0 and later.
* **JRuby (Ruby on JVM):** JRuby 9.3 and later on Java 11 or later (Java 17, 21, and 25 supported). Requires the JIT-preserving tracing profile in `JRUBY_OPTS`.
* **Metadata:** Access to the active git commit SHA (mandatory for matching local source coordinates to production builds).

***

## Installation

Add the SDK as a dependency using your package manager:

<CodeGroup>
  ```ruby Gemfile theme={null}
  gem 'hyperprobe-agent'
  ```

  ```bash bundle add theme={null}
  bundle add hyperprobe-agent
  ```

  ```bash gem theme={null}
  gem install hyperprobe-agent
  ```
</CodeGroup>

If you added `gem 'hyperprobe-agent'` directly to your `Gemfile`, run:

```bash theme={null}
bundle install
```

***

## Initialization Walkthrough

Follow these steps to initialize the HyperProbe agent inside your application:

<Steps>
  <Step title="Create your initialization file">
    Create a dedicated file named `hyperprobe.rb` in your project root:

    ```ruby hyperprobe.rb theme={null}
    require 'hyperprobe'

    HyperProbe.start(
      service_id: '<service-uuid-from-dashboard>',
      environment: ENV['HYPERPROBE_ENVIRONMENT'] || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'production',
      broker_url: 'https://logger.app.hyperprobe.co',
      commit_sha: ENV['GIT_COMMIT'] || ENV['HYPERPROBE_COMMIT_SHA']
    )
    ```
  </Step>

  <Step title="Import it in your entrypoint">
    In your main application entrypoint (such as `config/environment.rb` for Rails, or `app.rb` / `server.rb` for Sinatra / Rack), require `hyperprobe` **as early as possible** before starting your application:

    <CodeGroup>
      ```ruby Rails (config/environment.rb) theme={null}
      require_relative '../hyperprobe' # Require as early as possible
      require_relative 'application'

      Rails.application.initialize!
      ```

      ```ruby Sinatra / Rack / Web Server (app.rb) theme={null}
      require_relative 'hyperprobe' # Require as early as possible
      require 'sinatra'

      get '/' do
        'Hello World'
      end
      ```
    </CodeGroup>

    <Warning>
      **Environment Variables Loading Order:** If `hyperprobe.rb` reads variables loaded by a library such as `dotenv`, load those variables before requiring `hyperprobe.rb`.
    </Warning>
  </Step>

  <Step title="Configure multi-worker servers (Puma / Unicorn)">
    If you run a multi-process web server like Puma or Unicorn in clustered mode (with forked workers) on standard Ruby (CRuby), add `defer_start: true` to your initializer and call `HyperProbe.after_fork` in your worker boot configuration:

    ```ruby config/puma.rb theme={null}
    on_worker_boot do
      HyperProbe.after_fork
    end
    ```

    <Tip>
      **JRuby on JVM:** On JRuby, Puma runs in multi-threaded mode on the JVM without process forking, so `HyperProbe.after_fork` and `defer_start` are not required.
    </Tip>
  </Step>

  <Step title="Configure your Dockerfile">
    To enable Docker-based deployments, define a `GIT_COMMIT` build argument inside your `Dockerfile` with a default value of `unknown`.

    If you are running JRuby, also set the `JRUBY_OPTS` environment variable to preserve variable scopes with JIT enabled:

    <Tabs>
      <Tab title="Standard Ruby (CRuby)">
        ```dockerfile Dockerfile theme={null}
        # Define build argument with 'unknown' fallback to protect non-CI builds
        ARG GIT_COMMIT=unknown
        ENV GIT_COMMIT=${GIT_COMMIT}
        ```
      </Tab>

      <Tab title="JRuby (Ruby on JVM)">
        ```dockerfile Dockerfile theme={null}
        # Set required JRuby flags to preserve line boundaries and variables with JIT enabled
        ENV JRUBY_OPTS="--debug -J-Djruby.ir.passes=AddCallProtocolInstructions,AddMissingInitsPass -J-Djruby.ir.jit.passes=AddCallProtocolInstructions,AddMissingInitsPass"

        # Define build argument with 'unknown' fallback to protect non-CI builds
        ARG GIT_COMMIT=unknown
        ENV GIT_COMMIT=${GIT_COMMIT}
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Run local Docker builds">
    For building and testing Docker containers locally, inject your active git commit:

    ```bash theme={null}
    docker build --build-arg GIT_COMMIT=$(git rev-parse HEAD) -t api:latest .
    ```
  </Step>

  <Step title="Inject correct SHA in CI/CD (The PR Merge Trap)">
    To protect source alignment, HyperProbe refuses to start if `commit_sha` resolves to `unknown`. Pass the real commit SHA to `GIT_COMMIT` during deployment.

    Always use your CI/CD platform's native commit SHA variable:

    | Platform / Engine         | Configuration Option             | Build Argument Syntax                                                              |
    | :------------------------ | :------------------------------- | :--------------------------------------------------------------------------------- |
    | **GitHub Actions**        | PR-Safe HEAD Check (Recommended) | `--build-arg GIT_COMMIT=${{ github.event.pull_request.head.sha \|\| github.sha }}` |
    | **GitHub Actions (Push)** | Standard Branch Push             | `--build-arg GIT_COMMIT=${{ github.sha }}`                                         |
    | **GitLab CI/CD**          | GitLab Variable                  | `--build-arg GIT_COMMIT=$CI_COMMIT_SHA`                                            |
    | **CircleCI**              | CircleCI Variable                | `--build-arg GIT_COMMIT=$CIRCLE_SHA1`                                              |

    <Warning>
      **Beware of the PR Merge Commit Trap:** By default, GitHub Actions checks out a virtual merge commit for a `pull_request` trigger instead of the commit from your branch.

      If you use `git rev-parse HEAD` or `${{ github.sha }}` in a pull request workflow, source mapping can fail. Use `${{ github.event.pull_request.head.sha || github.sha }}` for pull request builds.
    </Warning>
  </Step>
</Steps>

***

## ☕ JRuby Support (Ruby on the JVM)

HyperProbe provides native, first-class support for JRuby applications running on the JVM.

### Prerequisites for JRuby

1. **JRuby Version:** JRuby **9.3 and later** (Java 8 is not supported; JRuby 10.1 requires Java 21+).
2. **Java Runtime:** Java 11, 17, 21, or 25.
3. **Launch Profile:** JRuby must be launched with the required JIT-preserving tracing profile:
   ```bash theme={null}
   --debug -J-Djruby.ir.passes=AddCallProtocolInstructions,AddMissingInitsPass -J-Djruby.ir.jit.passes=AddCallProtocolInstructions,AddMissingInitsPass
   ```

### Why the Launch Profile is Required on JRuby

JRuby's JIT compiler optimizes hot methods into raw JVM bytecode, stripping out line-level checkpoints and local variable names by default. Passing this profile instructs JRuby to retain line checkpoints and local variable scopes without disabling JIT compilation, so probes trigger reliably on compiled methods.

### How to Launch JRuby with HyperProbe

<Tabs>
  <Tab title="Docker / Kubernetes">
    Add the environment variable inside your `Dockerfile` or Deployment manifest:

    ```dockerfile Dockerfile theme={null}
    ENV JRUBY_OPTS="--debug -J-Djruby.ir.passes=AddCallProtocolInstructions,AddMissingInitsPass -J-Djruby.ir.jit.passes=AddCallProtocolInstructions,AddMissingInitsPass"
    ```
  </Tab>

  <Tab title="CLI / Local Server">
    Set the `JRUBY_OPTS` variable before starting your application:

    ```bash theme={null}
    export JRUBY_OPTS="--debug -J-Djruby.ir.passes=AddCallProtocolInstructions,AddMissingInitsPass -J-Djruby.ir.jit.passes=AddCallProtocolInstructions,AddMissingInitsPass"
    bundle exec jruby app.rb
    # Or with Puma:
    bundle exec puma -C config/puma.rb
    ```

    *(Note: If running JRuby 9.3 on Java 17, also include `-J--add-opens=java.base/sun.nio.ch=ALL-UNNAMED -J--add-opens=java.base/java.io=ALL-UNNAMED` for JRuby's native I/O access).*
  </Tab>
</Tabs>

<Tip>
  **Zero C-Extensions & Zero Runtime Downloads:** On JRuby, Bundler automatically installs the Java gem artifact (`hyperprobe-agent-<version>-java.gem`). It bundles an internal, shaded Netty gRPC transport and patched protobuf codec. No C compiler, Maven, or runtime downloads are required on the client machine.
</Tip>

***

## Configuration & Environment Variables Reference

You can configure the agent by passing properties inside your `HyperProbe.start()` options hash, or by using **environment variables**.

The following example includes the available programmatic options and their corresponding environment variables:

```ruby hyperprobe.rb theme={null}
require 'hyperprobe'

HyperProbe.start(
  # --- CORE OPTIONS ---
  service_id: '<service-uuid-from-dashboard>',   # Env: HYPERPROBE_SERVICE_ID
  environment: ENV['HYPERPROBE_ENVIRONMENT'],    # Env: HYPERPROBE_ENVIRONMENT (e.g. 'production', 'staging')
  broker_url: 'https://logger.app.hyperprobe.co',# Env: HYPERPROBE_BROKER_URL
  commit_sha: ENV['GIT_COMMIT'],                 # Env: GIT_COMMIT or HYPERPROBE_COMMIT_SHA (Mandatory)

  # --- BUFFERING & PERFORMANCE ---
  max_queue_size: 100,       # Env: HYPERPROBE_MAX_QUEUE_SIZE      - Cap on telemetry stored in memory
  flush_interval_ms: 1000,   # Env: HYPERPROBE_FLUSH_INTERVAL_MS   - Milliseconds before draining the queue
  sync_interval_ms: 60000,   # Env: HYPERPROBE_SYNC_INTERVAL_MS    - Sync cycle to fetch new active probes

  # --- SAFETY GUARDRAILS ---
  hits_per_sec: 10,          # Env: HYPERPROBE_HITS_PER_SEC         - Global limit on triggers per second
  bandwidth_kb_per_sec: 1024,# Env: HYPERPROBE_BANDWIDTH_KB_PER_SEC - Throughput cap in Kilobytes/sec
  max_lag_ms: 50,            # Env: HYPERPROBE_MAX_LAG_MS          - Thread-lag threshold in ms (CRuby only)
  pause_budget_ms: 15,       # Env: HYPERPROBE_PAUSE_BUDGET_MS     - Probe-handler time budget in ms/sec (CRuby only)
  cooldown_sec: 10,          # Env: HYPERPROBE_COOLDOWN_SEC        - Duration (in seconds) the agent remains dormant in cooldown
  rpc_timeout_sec: 10,       # Env: HYPERPROBE_RPC_TIMEOUT_SEC     - gRPC request timeout in seconds

  # --- DATA & REDACTION CONTROLS ---
  redact_keys: [             # Env: HYPERPROBE_REDACT_KEYS (comma-separated list)
    'password', 'secret', 'token', 'authorization', 'cookie', 'key', 'signature'
  ],                         # Blacklisted keys are stripped and replaced with [REDACTED] in-process
  redact_values: [],         # Env: HYPERPROBE_REDACT_VALUES (comma-separated list of regex patterns)
  max_object_depth: 3,       # Env: HYPERPROBE_MAX_OBJECT_DEPTH     - Max nested properties serialized
  max_array_length: 3,       # Env: HYPERPROBE_MAX_ARRAY_LENGTH     - Max elements serialized per array
  max_object_properties: 50, # Env: HYPERPROBE_MAX_OBJECT_PROPERTIES - Max key-value parameters recorded per object
  max_string_length: 1024,   # Env: HYPERPROBE_MAX_STRING_LENGTH    - Max character count before string truncation
  stack_frame_depth: 3       # Env: HYPERPROBE_STACK_FRAME_DEPTH    - Number of call stack frames captured per snapshot
)
```

<Tip>
  * **Option Precedence:** Explicit options passed to `HyperProbe.start()` take precedence over environment variables.
  * **Disabling the Agent:** Set `HYPERPROBE_DISABLED=YES` in your environment to completely disable the agent at startup.
  * **Option Naming:** Both `snake_case` (e.g., `service_id`, `commit_sha`) and `camelCase` (e.g., `serviceId`, `commitSha`) parameter keys are accepted.
</Tip>

On CRuby, snapshots include locals from the hit frame and available caller frames, including blocks, up to `stack_frame_depth`. On JRuby, only the hit frame has locals; caller frames show `{}`.

***

## Safe evaluation

Safe evaluation is enabled by default on Ruby and JRuby. To allow custom method calls in probe expressions, opt in before starting your application:

```bash theme={null}
export HYPERPROBE_DISABLE_SAFE_EVALUATION=true
```

Alternatively, add `disable_safe_evaluation: true` to your existing `HyperProbe.start` options. An explicit `false` keeps safe evaluation enabled, even if the environment variable is `true`.

<Warning>
  Disabling safe evaluation lets conditions, watches, log placeholders, metrics, and duration correlations execute Ruby code with your application's permissions. This code can change state, block, or terminate the process. Only enable it for trusted probes. The SDK logs a warning once at startup when enabled.
</Warning>

***

## Safety shields

The SDK automatically suspends probes when its safety limits are exceeded:

* **CRuby:** Uses repeated thread-lag readings and a probe-handler time budget (default 15 ms per second).
* **JRuby:** Checks JVM heap headroom every 5 seconds. Below 15% of maximum heap triggers a warning; below 5% suspends probes. Timing-budget breaches do not log warnings or suspend probes.
* **Auto-recovery:** Resumes probes after the cooldown period (default 10 seconds), once health returns to GREEN.
