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

# Configuration

> Options for the Go SDK clients, client-side pacing, and instrumentation hooks.

Every option works with both `perps.NewClient` and `options.NewClient`:

| Option | Sets |
| - | - |
| `rails.WithEnvironment(env)` | The hosts: `rails.Production()`, `rails.Sandbox()`, or a `rails.Environment` naming each one. |
| `rails.WithHTTPClient(c)` | The `*http.Client` behind HTTP calls and the WebSocket upgrade, for a proxy, your own TLS setup, or a tracing transport. |
| `rails.WithLogger(l)` | A `*slog.Logger` for the SDK's own diagnostics, such as reconnects. By default they are discarded. |
| `rails.WithTokenSource(ts)` | Where access tokens come from, in place of the built-in cache: for pre-minted tokens, or one cache shared across processes. |
| `rails.WithPacer(p)` | Client-side pacing, [Pacing](#pacing). |
| `rails.WithHooks(h)` | Your own instrumentation, [Instrumentation](#instrumentation). |
| `rails.WithTelemetry(false)` | Turns off the latency reports the SDK sends to Rails; on by default. `RAILS_SDK_TELEMETRY=off` in the environment does the same. |

## Pacing

Rate limits ([Perpetuals](/latest/perps/guides/rate-limits), [Options](/latest/options/guides/rate-limits)) are per account, and shared with everything else using it. A pacer keeps the metered calls under the account's budgets from the client's side, so they wait a little instead of coming back as `429`s. It is off unless installed with `rails.WithPacer`. Each product has a pacer preset to its published budgets, and `WithLimitsFromToken` picks those of your account's type (`creds` is your `rails.Credentials`):

<CodeGroup>
  ```go Perpetuals theme={null}
  client, err := perps.NewClient(creds,
  	rails.WithPacer(perps.NewPacer(perps.WithLimitsFromToken())),
  )
  ```

  ```go Options theme={null}
  client, err := options.NewClient(creds,
  	rails.WithPacer(options.NewPacer(options.WithLimitsFromToken())),
  )
  ```
</CodeGroup>

`WithLimits` sets your own ceilings per class of operation; the classes and preset budgets are on pkg.go.dev ([perps](https://pkg.go.dev/github.com/rails-xyz/exchange-go-sdk/perps), [options](https://pkg.go.dev/github.com/rails-xyz/exchange-go-sdk/options)).

A call that would exceed a ceiling waits until it fits, within its context; if the context ends first, nothing was sent. When the exchange rate-limits a call anyway, the pacer holds that class back for the wait it named. With `WithFailFast`, a call that would have to wait is refused instead, with `rails.ErrNotSent` wrapping `rails.ErrPaced`.

<Note>
  The budgets are per account, and the built-in pacer counts only its own client's calls. It keeps you under the limits only while one process is the only thing using the account. With several processes, or anything else on the account, give each a share of the budget with `WithLimits`, or implement the `rails.Pacer` interface over a store they share; otherwise the exchange still refuses calls over its limits.
</Note>

## Instrumentation

`rails.Hooks` is a struct of optional functions, called as the SDK observes each thing. Set the ones you want:

```go theme={null}
client, err := perps.NewClient(creds, rails.WithHooks(rails.Hooks{
	PingRTT: func(info rails.ConnInfo, rtt time.Duration) {
		// the round trip of each keepalive ping
	},
	RequestDone: func(info rails.ReqInfo, took time.Duration, err error) {
		// an order command, from send to answer
	},
}))
```

| Hook | Called |
| - | - |
| `ConnectStarted`, `ConnectFinished` | Around every dial, reconnects included, with the DNS, TCP, TLS and upgrade phases. |
| `Disconnected` | When a socket is lost, before the reconnect that follows. |
| `PingRTT` | With the round trip of each keepalive ping. |
| `RequestAcked`, `RequestDone` | When an order command is acknowledged, and when it is answered or fails. |
| `HTTPDone` | After every HTTP attempt, retries included. |
| `Paced`, `Throttled` | When the pacer delays or refuses a call, and when it holds a class back after a rate limit. |

`ConnInfo.ConnID` stays the same across the reconnects of one connection, and `ReqInfo` names the command, its market and its `clientRequestId`. Hooks run on the goroutine that made the observation and must not block.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.