Skip to content
27 changes: 25 additions & 2 deletions mint.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,21 +53,44 @@
"kubernetes"
]
},
"benchmarks"
"benchmarks",
{
"group": "Troubleshooting",
"icon": "hammer",
"pages": [
"troubleshooting-guide"
]
}
]
},
{
"group": "Tutorials",
"pages": [
{
"group": "Using the dashboard",
"group": "Use the dashboard",
"icon": "chart-column",
"pages": [
"request-graph",
"adding-filter-clauses"
]
},
{
"group": "Filter traffic to Subtrace",
"icon": "filter",
"pages": [
"proxy-rules-guide"
]
}
]
},
{
"group": "References",
"pages": [
"references/subtrace-run",
"references/subtrace-proxy",
"references/subtrace-worker",
"references/subtrace-version"
]
}
],
"footerSocials": {
Expand Down
165 changes: 165 additions & 0 deletions proxy-rules-guide.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
---
title: "Writing Rules for Subtrace Proxy"
description: "Learn how to use the subtrace proxy command to control which HTTP traffic is traced"
lastUpdated: "2024-12-17"
---
# Writing Rules for Subtrace Proxy: A Beginner's Guide

## Introduction

When running subtrace proxy to monitor your HTTP traffic, you may not want to trace every single request - some might be too noisy (like health checks), while others may contain sensitive data. Subtrace lets you control this using JavaScript rules.

## Basic Setup

First, let's set up a basic proxy that forwards traffic from port 8080 to our API running on port 3000:

```bash
# Create a rules file
touch rules.js

# Start the proxy
subtrace proxy \
-listen localhost:8080 \
-remote localhost:3000 \
-config rules.js
```

## Writing Your First Rule

Rules are written using the `trace()` function. Let's start with a simple rule that traces all requests:

```javascript
// rules.js
trace("*", "*", function() {
return true;
});
```

The `trace()` function takes three arguments:
1. HTTP method pattern (like "GET", "POST", "*" for all)
2. Path pattern (like "/api/users", "/health", "*" for all)
3. A function that returns true to trace the request, false to ignore it

## Building More Specific Rules

Let's build rules for our ecommerce API. We want to:
- Trace all product-related requests
- Skip health checks
- Sample only 10% of static asset requests
- Always trace error responses

```javascript
// rules.js

// Trace all product-related endpoints
trace("*", "/api/products/*", function() {
return true;
});

// Skip health checks completely
trace("GET", "/health", function() {
return false;
});

// Sample 10% of static asset requests
trace("GET", "/static/*", {
sample: 0.1
});

// Trace any request that returns an error
trace("*", "*", function(req, resp) {
return resp.statusCode >= 400;
});
```

## Pattern Matching

The method and path patterns support:
- Exact matches: "GET", "/api/users"
- Wildcards: "*" matches anything
- Suffixes: "/api/*" matches any path starting with /api/

## Adding Conditions

You can make more complex decisions in your rule functions. Let's expand our example:

```javascript
// rules.js

// Trace slow requests that take > 500ms
trace("*", "*", function(req, resp) {
return req.duration > 500;
});

// Trace requests with specific header
trace("POST", "/api/*", function(req) {
return req.headers["x-trace-this"] === "true";
});

// Combine multiple conditions
trace("PUT", "/api/orders/*", function(req, resp) {
return resp.statusCode >= 400 || // Error responses
req.duration > 1000 || // Slow requests
req.body.priority === "high"; // High priority orders
});
```

## Rule Evaluation Order

Rules are evaluated in the order they appear in your file. Once a rule matches and returns true, that decision is final. Use this to create precedence:

```javascript
// rules.js

// First, skip health checks unconditionally
trace("GET", "/health", () => false);

// Then apply sampling to everything else
trace("*", "*", { sample: 0.1 });
```

## Reference

Common patterns:

```javascript
// Match specific HTTP methods
trace("GET", "...")
trace("POST", "...")
trace("PUT", "...")
trace("DELETE", "...")

// Match paths
trace("*", "/exact/path")
trace("*", "/api/*") // Everything under /api
trace("*", "*.jpg") // All jpg files
trace("*", "/users/*/posts") // Match /users/123/posts

// Sampling
trace("*", "*", { sample: 0.5 }) // 50% of requests

// Access request/response info
trace("*", "*", function(req, resp) {
req.method // HTTP method
req.path // Request path
req.headers // Request headers
req.body // Request body
req.duration // Request duration in ms

resp.statusCode // Response status code
resp.headers // Response headers
resp.body // Response body
})
```

## Best Practices

1. Start with broad rules and refine them
2. Use sampling for high-volume endpoints
3. Always skip health check endpoints
4. Put most specific rules first
5. Use meaningful patterns that map to your API structure
6. Don't overload your rules with complex logic
7. Monitor the impact of your rules on system performance

The key is to find the right balance between visibility and performance for your specific use case. Start simple and iterate based on your needs.
121 changes: 108 additions & 13 deletions quickstart.mdx
Original file line number Diff line number Diff line change
@@ -1,37 +1,132 @@
---
title: "Subtrace Quickstart"
sidebarTitle: "Quickstart"
description: "Welcome! Follow the steps below to get started with Subtrace."
description: "Welcome! Follow the steps below to get started tracing your HTTP/HTTPS requests and service calls."
icon: "rocket"
---

**Step 1**: Go to [https://subtrace.dev/login](https://subtrace.dev/login) and log in with your single sign-on (SSO) identity provider.

**Step 2**: On the **Let's set up your database** page, follow the onboarding instructions to start the database worker service where your backend requests will be stored.
**Step 2**: Visit the [Let's set up your database](https://subtrace.dev/onboarding) onboarding page and start the database worker service where your backend requests will be stored.


<img className="rounded-xl" src="/quickstart-1-onboarding.png" />

**Step 3**: Go to the **Tokens** page on the dashboard and click **Create tracer token**.
<Accordion title="What is the highlighted install command?">
```bash
docker run -d \
-e SUBTRACE_TOKEN=subt_REDACTED_WORKER_TOKEN \
-v subtrace:/var/lib/clickhouse \
subtrace.dev/worker:latest
```

Run this command with the **worker token** from the [Tokens](https://subtrace.dev/dashboard/workspace/tokens) page.

<Info>
This is required to authenticate your cloud and self-hosted deployments of Subtrace.
</Info>

</Accordion>

**Step 3**: Go to the [Tokens](https://subtrace.dev/dashboard/workspace/tokens) page on the dashboard and click **Create tracer token**.

<img className="rounded-xl" src="/quickstart-2-token.png" />

**Step 4**: Install the latest version of Subtrace, set the `SUBTRACE_TOKEN` environment variable to the token you generated in the previous step, and use `subtrace run` to start your app.
**Step 4**: Install the latest version of Subtrace, set the `SUBTRACE_TOKEN` environment variable to the **tracer token** you generated in step 3, and use `subtrace run` to start your app.
<CodeGroup>
```bash bash
# replace amd64 with arm64 if applicable
curl -fsSLO https://subtrace.dev/download/latest/linux/amd64/subtrace && chmod +x ./subtrace

# this is just an example, use the token you generated in Step 3
export SUBTRACE_TOKEN=subt_REDACTED_TRACER_TOKEN

# start your app like you normally do, but using Subtrace
./subtrace run -- node ./app.js
```
```javascript app.js
try {
// Successful request
console.log("Making successful request...");
const successResponse = await fetch('http://jsonplaceholder.typicode.com/posts/1');
console.log(`Success! Status code: ${successResponse.status}`);
const successData = await successResponse.json();
console.log(`Response:`, successData);
console.log('');

// Failed request (intentionally wrong URL)
console.log("Making request that will fail...");
try {
const failedResponse = await fetch('http://jsonplaceholder.typicode.com/nonexistent', { method: 'POST' });
console.log(`Status code: ${failedResponse.status}`);
} catch (error) {
console.log('Request failed:', error.message);
}
} catch (error) {
console.error('Unexpected error:', error.message);
}
```

```python main.py
import requests

# Successful request
print("Making successful request...")
response = requests.get('https://jsonplaceholder.typicode.com/posts/1')
print(f"Success! Status code: {response.status_code}")
print(f"Response: {response.json()}\n")

# Failed request (intentionally wrong URL)
print("Making request that will fail...")
try:
response = requests.post('https://jsonplaceholder.typicode.com/nonexistent')
print(f"Status code: {response.status_code}")
except requests.exceptions.RequestException as e:
print(f"Request failed as expected: {e}")
```
</CodeGroup>
The double dash (`--`) is required to separate subtrace flags from the command you want to run (read more in the [subtrace run reference](/references/subtrace-run-doc#usage)).

**Step 5** *(optional)*: Add the Subtrace executable to your `$PATH` so you can run `subtrace` from anywhere.
- Validate that `/usr/local/bin` exists in your `$PATH`.
<CodeGroup>
```bash bash
echo $PATH
```
```bash output
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
```
</CodeGroup>

```bash
# replace amd64 with arm64 if applicable
curl -fsSLO https://subtrace.dev/download/latest/linux/amd64/subtrace && chmod +x ./subtrace
- Move the `subtrace` executable to `/usr/local/bin`.

# this is just an example, use the token you generated in Step 3
export SUBTRACE_TOKEN=subt_CbBZqZousFZ2IBIATEgKCNPvAtZuaRxbtdlzlzmUqNg
```bash
sudo mv ./subtrace /usr/local/bin/subtrace
```
- Test that subtrace still works.

# start your app like you normally do, but using Subtrace
./subtrace run -- node ./app.js
```
<CodeGroup>
```bash bash
subtrace version
```
```bash output
b149
commit 989a856 at 2024-12-13T19:19:15Z
built with go1.23.4 linux/amd64 at 2024-12-13T19:19:30Z hash 63ec488edc27699bf65d31a26698d5d7b175afa39ac91554b81acc83d01c999e
kernel Linux 6.11.0-13-generic on x86_64
running on linux/amd64 with uid 1000 gid 1000
effective caps 0x0000000000000000 -chown -dac_override -dac_read_search -fowner -fsetid -kill -setgid -setuid -setpcap -linux_immutable -net_bind_service -net_broadcast -net_admin -net_raw -ipc_lock -ipc_owner -sys_module -sys_rawio -sys_chroot -sys_ptrace -sys_pacct -sys_admin -sys_boot -sys_nice -sys_resource -sys_time -sys_tty_config -mknod -lease -audit_write -audit_control -setfcap -mac_override -mac_admin -syslog -wake_alarm -block_suspend -audit_read -perfmon -bpf -checkpoint_restore
```
</CodeGroup>

Congratulations! Your app is now running under Subtrace. Your requests should automatically appear in the [Subtrace dashboard](https://subtrace.dev/dashboard/).

While this is sufficient to get started with Subtrace, you should install Subtrace everywhere in your infrastructure to get the most out of it. Pick the one that matches your situation best to learn more:

- [Installing on Kubernetes](/kubernetes)
<CardGroup>
<Card title="Installing on Kubernetes" href="/kubernetes" icon="fa-solid fa-cloud" iconType="regular">
Install Subtrace on Kubernetes to observe all your service calls.
</Card>
</CardGroup>

If your infra uses something that's not listed, we'd love to understand your usecase and help you get started with Subtrace. Join our [discord server](https://subtrace.dev/discord) or email us at [[email protected]]([email protected]) to get in touch.
Loading