Sentry

If you already use Sentry, you can send Packrat a copy of the same data with a few lines of configuration. Sentry keeps receiving everything, and Packrat gets a copy. This is called dual-shipping.

You can dual-ship from two places:

For a server in another language, use OpenTelemetry instead.

Before you begin

  1. Sign up for Packrat. It's free.

  2. Copy your ingest key from the setup page. It starts with packrat_ingest_.

  3. Install the Packrat CLI and sign in, so you can check what Packrat receives:

    curl -fsSL https://packrat.sh/cli | sh
    packrat login
    

On your Rails server

If your app runs sentry-ruby and sentry-rails, add a transport to your Sentry initializer. The transport sends each event to Sentry, then sends a copy to Packrat. Packrat receives your exceptions and your request and job traces.

If your app doesn't use Sentry yet, don't install it for Packrat. Follow the OpenTelemetry guide for Ruby on Rails instead.

Dual-ship from sentry-ruby

  1. Set PACKRAT_SENTRY_DSN where your app runs. It's made from your ingest key and your app's name in Packrat:

    PACKRAT_SENTRY_DSN=https://<your ingest key>@ingest.packrat.sh/<your app>
    
  2. Add the transport to config/initializers/sentry.rb, and set it in Sentry.init:

    # config/initializers/sentry.rb
    
    # Sends Packrat a copy of each envelope.
    module PackratSentry
      def self.transport
        @transport ||= begin
          config = Sentry.configuration.dup
          config.dsn = ENV["PACKRAT_SENTRY_DSN"]
          Sentry::HTTPTransport.new(config)
        end
      end
    end
    
    class PackratDualTransport < Sentry::HTTPTransport
      def send_data(data)
        super
      ensure
        begin
          PackratSentry.transport.send_data(data)
        rescue => e
          Sentry.sdk_logger.warn("[packrat] copy failed: #{e.class}: #{e.message}")
        end
      end
    end
    
    Sentry.init do |config|
      config.dsn = ENV["SENTRY_DSN"]
      config.release = ENV["GIT_COMMIT"] # the commit you deployed
      config.environment = Rails.env
      config.transport.transport_class = PackratDualTransport if ENV["PACKRAT_SENTRY_DSN"].present?
    end
    
  3. Deploy, or restart your app.

Sentry still receives each event first. If Packrat is unreachable, the copy fails and Sentry logs a warning.

Send to Packrat only

If you don't use Sentry, set Packrat's DSN as the only DSN in config/initializers/sentry.rb:

# config/initializers/sentry.rb
Sentry.init do |config|
  config.dsn = ENV["PACKRAT_SENTRY_DSN"]
  config.release = ENV["GIT_COMMIT"] # the commit you deployed
  config.environment = Rails.env
  config.traces_sample_rate = 1.0
end

Verify your server

Make a request to your app and wait about a minute. Then list the server's latest spans:

SELECT name, kind, json_extract_string(span_attributes, '$."sentry.op"') AS op, duration_ms
FROM packrat_spans(since := now()::TIMESTAMP - INTERVAL 10 MINUTE)
WHERE scope_name LIKE 'sentry.ruby%'
ORDER BY start_time DESC LIMIT 20

A request's first span has a kind of 2, and a job's has 5. Once the hour closes, packrat_traces lists the requests and jobs themselves.

In the browser

Sentry's browser SDK can send Packrat your page loads, Web Vitals, JavaScript errors and session replays. Packrat stores them in the same app as your server's data.

If your pages don't run the SDK yet, install it with Sentry's JavaScript guide, then follow Send to Packrat only.

Create a browser ingest key

The key goes in your page's source, where anyone can read it. On your org's Keys page, create an ingest key for the browser only. You can then revoke it without affecting your servers.

Dual-ship from the browser SDK

Give Sentry.init a transport that sends each envelope to Sentry and a copy to Packrat. Replace <your app> with the name your server's app has in Packrat, so the browser's data lands in the same app, and set environment to the app's environment, such as production or staging.

const PACKRAT =
  "https://ingest.packrat.sh/api/<your app>/envelope/?sentry_version=7&sentry_key=<browser ingest key>&environment=production";

Sentry.init({
  dsn: "<your Sentry DSN>",
  release: "<your deploy's commit SHA>",
  integrations: [Sentry.browserTracingIntegration()],
  tracesSampleRate: 1.0,
  transport: (options) => {
    const sentry = Sentry.makeFetchTransport(options);
    const packrat = Sentry.makeFetchTransport({ ...options, url: PACKRAT });
    return {
      send: (envelope) => {
        packrat.send(envelope);
        return sentry.send(envelope);
      },
      flush: (timeout) =>
        Promise.all([sentry.flush(timeout), packrat.flush(timeout)]).then(
          (done) => done.every(Boolean),
        ),
    };
  },
});

Send to Packrat only

If you don't use Sentry, or no longer want the browser to report to it, use Packrat's DSN and send every envelope to Packrat:

const PACKRAT =
  "https://ingest.packrat.sh/api/<your app>/envelope/?sentry_version=7&sentry_key=<browser ingest key>&environment=production";

Sentry.init({
  dsn: "https://<browser ingest key>@ingest.packrat.sh/<your app>",
  release: "<your deploy's commit SHA>",
  integrations: [Sentry.browserTracingIntegration()],
  tracesSampleRate: 1.0,
  transport: (options) =>
    Sentry.makeFetchTransport({ ...options, url: PACKRAT }),
});

Turn on session replays

To record sessions, add Sentry.replayIntegration() and set how many sessions to record. With either transport above, Packrat receives the replays too:

Sentry.init({
  // ...as above
  integrations: [Sentry.browserTracingIntegration(), Sentry.replayIntegration()],
  replaysSessionSampleRate: 0.1, // record 10% of sessions
  replaysOnErrorSampleRate: 1.0, // and every session with an error
});

Each app's Replays page lists the sessions, and you can query them with packrat_replays and packrat_replay_events. The API reference lists the columns.

Verify the browser SDK

Load a page, then check what Packrat receives. The browser shows up as the source Sentry browser under traces, and under replays and exceptions once it sends them.

Run packrat status with your app's name, as <service>/<environment>:

packrat status --app shop/production

The output lists each signal (exceptions, traces, logs, metrics and replays), the sources that send it, when each source last sent, and whether Packrat keeps it. A signal with no source hasn't arrived yet. To see the names your apps report under, run packrat apps.

After about a minute, you can query the browser's spans:

SELECT name, json_extract_string(span_attributes, '$."sentry.op"') AS op, duration_ms
FROM packrat_spans(since := now()::TIMESTAMP - INTERVAL 10 MINUTE)
WHERE scope_name LIKE 'sentry.javascript.%'
ORDER BY start_time DESC LIMIT 20