Skip to content

Commit 8283591

Browse files
authored
feat: add adaptive sampling to python sdk (#90)
1 parent befb085 commit 8283591

37 files changed

+1273
-158
lines changed

docs/environment-variables.md

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -110,24 +110,29 @@ Your Tusk Drift API key, required when using Tusk Cloud for storing and managing
110110

111111
This will securely store your auth key for future replay sessions.
112112

113-
## TUSK_SAMPLING_RATE
113+
## TUSK_RECORDING_SAMPLING_RATE
114114

115-
Controls what percentage of requests are recorded during trace collection.
115+
Controls the base recording rate used during trace collection.
116116

117117
- **Type:** Number between 0.0 and 1.0
118-
- **Default:** 1.0 (100% of requests)
119-
- **Precedence:** This environment variable is overridden by the `sampling_rate` parameter in `TuskDrift.initialize()`, but takes precedence over the `sampling_rate` setting in `.tusk/config.yaml`
118+
- **If unset:** Falls back to `.tusk/config.yaml` and then the default base rate of `1.0`
119+
- **Precedence:** This environment variable is overridden by the `sampling_rate` parameter in `TuskDrift.initialize()`, but takes precedence over `recording.sampling.base_rate` and the legacy `recording.sampling_rate` setting in `.tusk/config.yaml`
120+
- **Scope:** This only overrides the base rate. It does not change `recording.sampling.mode` or `recording.sampling.min_rate`
120121

121122
**Examples:**
122123

123124
```bash
124125
# Record all requests (100%)
125-
TUSK_SAMPLING_RATE=1.0 python app.py
126+
TUSK_RECORDING_SAMPLING_RATE=1.0 python app.py
126127

127128
# Record 10% of requests
128-
TUSK_SAMPLING_RATE=0.1 python app.py
129+
TUSK_RECORDING_SAMPLING_RATE=0.1 python app.py
129130
```
130131

132+
If `recording.sampling.mode: adaptive` is enabled in `.tusk/config.yaml`, this environment variable still only changes the base rate; adaptive load shedding remains active.
133+
134+
`TUSK_RECORDING_SAMPLING_RATE` is the canonical variable, but `TUSK_SAMPLING_RATE` is still accepted as a backward-compatible alias.
135+
131136
For more details on sampling rate configuration methods and precedence, see the [Initialization Guide](./initialization.md#configure-sampling-rate).
132137

133138
## Rust Core Flags

docs/initialization.md

Lines changed: 76 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ Create an initialization file or add the SDK initialization to your application
7373
<tr>
7474
<td><code>sampling_rate</code></td>
7575
<td><code>float</code></td>
76-
<td><code>1.0</code></td>
77-
<td>Override sampling rate (0.0 - 1.0) for recording. Takes precedence over <code>TUSK_SAMPLING_RATE</code> env var and config file.</td>
76+
<td><code>None</code></td>
77+
<td>Override the base sampling rate (0.0 - 1.0) for recording. Takes precedence over <code>TUSK_RECORDING_SAMPLING_RATE</code> and config file base-rate settings. Does not change <code>recording.sampling.mode</code>.</td>
7878
</tr>
7979
</tbody>
8080
</table>
@@ -172,50 +172,91 @@ if __name__ == "__main__":
172172

173173
## Configure Sampling Rate
174174

175-
The sampling rate determines what percentage of requests are recorded during replay tests. Tusk Drift supports three ways to configure the sampling rate, with the following precedence (highest to lowest):
175+
Sampling controls what percentage of inbound requests are recorded in `RECORD` mode.
176+
177+
Tusk Drift supports two sampling modes in `.tusk/config.yaml`:
178+
179+
- `fixed`: record requests at a constant base rate.
180+
- `adaptive`: start from a base rate and automatically shed load when queue pressure, export failures, or memory pressure indicate the SDK should back off. In severe conditions the SDK can temporarily pause recording entirely.
181+
182+
Sampling configuration is resolved in two layers:
176183

177-
1. **Init Parameter**
178-
2. **Environment Variable** (`TUSK_SAMPLING_RATE`)
179-
3. **Configuration File** (`.tusk/config.yaml`)
184+
1. **Base rate precedence** (highest to lowest):
185+
- `TuskDrift.initialize(sampling_rate=...)`
186+
- `TUSK_RECORDING_SAMPLING_RATE`
187+
- legacy alias `TUSK_SAMPLING_RATE`
188+
- `.tusk/config.yaml` `recording.sampling.base_rate`
189+
- `.tusk/config.yaml` legacy `recording.sampling_rate`
190+
- default base rate `1.0`
191+
2. **Mode and minimum rate**:
192+
- `recording.sampling.mode` comes from `.tusk/config.yaml` and defaults to `fixed`
193+
- `recording.sampling.min_rate` is only used in `adaptive` mode and defaults to `0.001` when omitted
180194

181-
If not specified, the default sampling rate is `1.0` (100%).
195+
> [!NOTE]
196+
> Requests before `sdk.mark_app_as_ready()` are always recorded. Sampling applies to normal inbound traffic after startup.
182197
183-
### Method 1: Init Parameter (Programmatic Override)
198+
### Method 1: Init Parameter (Programmatic Base-Rate Override)
184199

185-
Set the sampling rate directly in your initialization code:
200+
Set the base sampling rate directly in your initialization code:
186201

187202
```python
188203
sdk = TuskDrift.initialize(
189204
api_key=os.environ.get("TUSK_API_KEY"),
190-
sampling_rate=0.1, # 10% of requests
205+
sampling_rate=0.1, # Base rate: 10% of requests
191206
)
192207
```
193208

194209
### Method 2: Environment Variable
195210

196-
Set the `TUSK_SAMPLING_RATE` environment variable:
211+
Set the `TUSK_RECORDING_SAMPLING_RATE` environment variable to override the base sampling rate:
197212

198213
```bash
199214
# Development - record everything
200-
TUSK_SAMPLING_RATE=1.0 python app.py
215+
TUSK_RECORDING_SAMPLING_RATE=1.0 python app.py
201216

202217
# Production - sample 10% of requests
203-
TUSK_SAMPLING_RATE=0.1 python app.py
218+
TUSK_RECORDING_SAMPLING_RATE=0.1 python app.py
204219
```
205220

221+
`TUSK_SAMPLING_RATE` is still supported as a backward-compatible alias, but new setups should prefer `TUSK_RECORDING_SAMPLING_RATE`.
222+
206223
### Method 3: Configuration File
207224

208-
Update the configuration file `.tusk/config.yaml` to include a `recording` section:
225+
Use the nested `recording.sampling` config to choose `fixed` vs `adaptive` mode and set the base/minimum rates.
226+
227+
**Fixed sampling example:**
209228

210229
```yaml
211230
# ... existing configuration ...
212231

213232
recording:
214-
sampling_rate: 0.1
233+
sampling:
234+
mode: fixed
235+
base_rate: 0.1
215236
export_spans: true
216237
enable_env_var_recording: true
217238
```
218239
240+
**Adaptive sampling example:**
241+
242+
```yaml
243+
# ... existing configuration ...
244+
245+
recording:
246+
sampling:
247+
mode: adaptive
248+
base_rate: 0.25
249+
min_rate: 0.01
250+
export_spans: true
251+
```
252+
253+
**Legacy config still supported:**
254+
255+
```yaml
256+
recording:
257+
sampling_rate: 0.1
258+
```
259+
219260
### Recording Configuration Options
220261
221262
<table>
@@ -229,10 +270,28 @@ recording:
229270
</thead>
230271
<tbody>
231272
<tr>
232-
<td><code>sampling_rate</code></td>
273+
<td><code>sampling.mode</code></td>
274+
<td><code>"fixed" | "adaptive"</code></td>
275+
<td><code>"fixed"</code></td>
276+
<td>Selects constant sampling or adaptive load shedding.</td>
277+
</tr>
278+
<tr>
279+
<td><code>sampling.base_rate</code></td>
233280
<td><code>float</code></td>
234281
<td><code>1.0</code></td>
235-
<td>The sampling rate (0.0 - 1.0). 1.0 means 100% of requests are recorded, 0.0 means 0% of requests are recorded.</td>
282+
<td>The base sampling rate (0.0 - 1.0). This is the preferred config key and can be overridden by <code>TUSK_RECORDING_SAMPLING_RATE</code> or the <code>sampling_rate</code> init parameter.</td>
283+
</tr>
284+
<tr>
285+
<td><code>sampling.min_rate</code></td>
286+
<td><code>float</code></td>
287+
<td><code>0.001</code> in <code>adaptive</code> mode</td>
288+
<td>The minimum steady-state sampling rate for adaptive mode. In critical conditions the SDK can still temporarily pause recording.</td>
289+
</tr>
290+
<tr>
291+
<td><code>sampling_rate</code></td>
292+
<td><code>float</code></td>
293+
<td><code>None</code></td>
294+
<td>Legacy fallback for the base sampling rate. Still supported for backward compatibility, but <code>recording.sampling.base_rate</code> is preferred.</td>
236295
</tr>
237296
<tr>
238297
<td><code>export_spans</code></td>

docs/quickstart.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,18 @@
22

33
Let's walk through recording and replaying your first trace:
44

5-
## Step 1: Set sampling rate to 1.0
5+
## Step 1: Set fixed sampling to 1.0
66

7-
Set the `sampling_rate` in `.tusk/config.yaml` to 1.0 to ensure that all requests are recorded.
7+
Update `.tusk/config.yaml` so your first recording captures every request:
8+
9+
```yaml
10+
recording:
11+
sampling:
12+
mode: fixed
13+
base_rate: 1.0
14+
```
15+
16+
Legacy `recording.sampling_rate: 1.0` still works, but `recording.sampling` is the preferred config shape.
817

918
## Step 2: Start server in record mode
1019

0 commit comments

Comments
 (0)