Skip to content

Commit db2ae2a

Browse files
committed
v1.0.2: Rename TIMETRACE_ to TIMETRACER_, add auto_setup(), improve docs
1 parent 0698fd7 commit db2ae2a

28 files changed

Lines changed: 785 additions & 681 deletions

README.md

Lines changed: 98 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Timetracer
22

3-
**Time-travel debugging for FastAPI and Flask** - Record API requests, replay with mocked dependencies.
3+
**Time-travel debugging for FastAPI and Flask** Record API requests, replay with mocked dependencies.
44

55
[![CI](https://github.com/usv240/timetracer/actions/workflows/ci.yml/badge.svg)](https://github.com/usv240/timetracer/actions)
66
[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
@@ -9,195 +9,166 @@
99

1010
---
1111

12-
## What is it?
12+
## What is Timetracer?
1313

14-
Timetracer records real API request executions into portable **cassettes** and replays them locally by mocking dependency calls (HTTP, database, Redis).
14+
Timetracer captures real API requests into portable **cassettes** and replays them with mocked dependencies (HTTP calls, database queries, Redis commands).
1515

16-
*Record once. Replay anywhere. Debug faster.*
16+
> Record once. Replay anywhere. Debug faster.
1717
18-
**Use cases:**
19-
- Reproduce production/staging bugs quickly
20-
- Build regression tests from real traffic
21-
- Run offline demos
22-
- Detect performance regressions
23-
- Diff behavior between runs
18+
**Common use cases:**
19+
20+
- Reproduce production bugs locally without access to external services
21+
- Build regression tests from real traffic patterns
22+
- Run demos offline with pre-recorded data
23+
- Detect performance regressions between releases
24+
- Compare behavior between different code versions
25+
26+
---
2427

2528
## Installation
2629

2730
```bash
28-
# Core + all plugins
2931
pip install timetracer[all]
30-
31-
# Or just what you need
32-
pip install timetracer[fastapi,httpx] # FastAPI + HTTP
33-
pip install timetracer[flask,httpx] # Flask + HTTP
34-
pip install timetracer[sqlalchemy] # Database
35-
pip install timetracer[redis] # Redis
36-
pip install timetracer[s3] # S3 storage
3732
```
3833

39-
## Quickstart (3 Steps)
40-
41-
### Step 1: Install
34+
Or install only what you need:
4235

4336
```bash
44-
pip install timetracer[fastapi,httpx]
37+
pip install timetracer[fastapi,httpx] # FastAPI + HTTP
38+
pip install timetracer[flask,requests] # Flask + HTTP
4539
```
4640

47-
### Step 2: Add 4 Lines to Your App
41+
---
42+
43+
## Quick Start
44+
45+
### FastAPI
4846

4947
```python
5048
from fastapi import FastAPI
51-
from timetracer.config import TraceConfig
52-
from timetracer.integrations.fastapi import TimeTraceMiddleware
53-
from timetracer.plugins import enable_httpx
49+
from timetracer.integrations.fastapi import auto_setup
5450

55-
app = FastAPI()
51+
app = auto_setup(FastAPI())
5652

57-
# Add these 2 lines to enable Timetracer
58-
config = TraceConfig.from_env()
59-
app.add_middleware(TimeTraceMiddleware, config=config)
53+
@app.get("/users/{user_id}")
54+
async def get_user(user_id: int):
55+
async with httpx.AsyncClient() as client:
56+
return (await client.get(f"https://api.example.com/users/{user_id}")).json()
57+
```
6058

61-
# Optional: Enable httpx tracking
62-
enable_httpx()
59+
### Flask
6360

64-
@app.post("/checkout")
65-
async def checkout():
66-
async with httpx.AsyncClient() as client:
67-
response = await client.get("https://api.example.com/data")
68-
return {"status": "ok"}
61+
```python
62+
from flask import Flask
63+
from timetracer.integrations.flask import auto_setup
64+
65+
app = auto_setup(Flask(__name__))
6966
```
7067

71-
### Step 3: Record and Replay
68+
### Record and Replay
7269

7370
```bash
74-
# Record requests
71+
# Record mode - captures all external calls
7572
TIMETRACER_MODE=record uvicorn app:app
76-
curl -X POST http://localhost:8000/checkout
77-
78-
# Check cassettes
79-
ls ./cassettes/
80-
# Output: 2026-01-16/POST__checkout__abc123.json
73+
curl http://localhost:8000/users/123
8174

82-
# Replay (mocked HTTP calls)
75+
# Replay mode - mocks external calls from cassette
8376
TIMETRACER_MODE=replay \
84-
TIMETRACER_CASSETTE=./cassettes/2026-01-16/POST__checkout__abc123.json \
77+
TIMETRACER_CASSETTE=./cassettes/2026-01-16/GET__users_{user_id}__abc.json \
8578
uvicorn app:app
8679
```
8780

88-
**Example Output:**
89-
90-
```
91-
# Recording
92-
TIMETRACER [OK] recorded POST /checkout id=abc123 status=200 total=523ms deps=http.client:1
93-
cassette: ./cassettes/2026-01-16/POST__checkout__abc123.json
94-
95-
# Replaying
96-
TIMETRACER replay POST /checkout mocked=1 matched=OK runtime=45ms recorded=523ms
97-
```
98-
99-
That's it! External HTTP calls are now mocked from the recorded cassette.
100-
10181
---
10282

103-
## Flask Integration
104-
105-
```python
106-
from flask import Flask
107-
from timetracer.integrations.flask import init_app
108-
from timetracer.config import TraceConfig
83+
## Manual Setup
10984

110-
app = Flask(__name__)
111-
init_app(app, TraceConfig.from_env())
112-
```
85+
For more control over configuration:
11386

114-
## Features
87+
```python
88+
import httpx
89+
from fastapi import FastAPI
90+
from timetracer import TraceConfig
91+
from timetracer.integrations.fastapi import TimeTraceMiddleware
92+
from timetracer.plugins import enable_httpx
11593

116-
### Frameworks
117-
- **FastAPI** - Full middleware support
118-
- **Flask** - WSGI middleware support
94+
app = FastAPI()
11995

120-
### Plugins
121-
- **httpx** - Async/sync HTTP client
122-
- **requests** - requests library
123-
- **SQLAlchemy** - Database queries
124-
- **Redis** - Redis commands
96+
config = TraceConfig(
97+
mode="record",
98+
cassette_dir="./my-cassettes",
99+
errors_only=True,
100+
)
101+
app.add_middleware(TimeTraceMiddleware, config=config)
125102

126-
### Storage
127-
- **Local filesystem** - Default
128-
- **S3** - AWS S3 and S3-compatible (MinIO)
103+
enable_httpx()
104+
```
129105

130-
### Analysis and Tools
131-
- **Diff engine** - Compare cassettes
132-
- **HTML timeline** - Visualize execution
133-
- **Hybrid replay** - Mock some deps, keep others live
134-
- **Search and Index** - Find cassettes by endpoint, status, date
106+
---
135107

136108
## Configuration
137109

110+
All settings are controlled via environment variables:
111+
138112
| Variable | Description | Default |
139113
|----------|-------------|---------|
140114
| `TIMETRACER_MODE` | `off`, `record`, `replay` | `off` |
141-
| `TIMETRACER_DIR` | Cassette directory | `./cassettes` |
142-
| `TIMETRACER_CASSETTE` | Replay cassette path | - |
143-
| `TIMETRACER_SAMPLE_RATE` | Record fraction (0-1) | `1.0` |
144-
| `TIMETRACER_ERRORS_ONLY` | Only record errors | `false` |
145-
| `TIMETRACER_MOCK_PLUGINS` | Plugins to mock | all |
146-
| `TIMETRACER_LIVE_PLUGINS` | Plugins to keep live | none |
147-
148-
## CLI
115+
| `TIMETRACER_DIR` | Cassette storage directory | `./cassettes` |
116+
| `TIMETRACER_CASSETTE` | Path to cassette file (replay mode) ||
117+
| `TIMETRACER_SAMPLE_RATE` | Fraction of requests to record (0-1) | `1.0` |
118+
| `TIMETRACER_ERRORS_ONLY` | Only record error responses | `false` |
119+
| `TIMETRACER_MOCK_PLUGINS` | Plugins to mock during replay | all |
120+
| `TIMETRACER_LIVE_PLUGINS` | Plugins to keep live during replay | none |
149121

150-
```bash
151-
# List cassettes
152-
timetracer list --dir ./cassettes
122+
---
153123

154-
# Show cassette details
155-
timetracer show ./cassettes/.../POST__checkout.json --events
124+
## Features
156125

157-
# Diff two cassettes
158-
timetracer diff --a cassette1.json --b cassette2.json
126+
| Category | Supported |
127+
|----------|-----------|
128+
| **Frameworks** | FastAPI, Flask |
129+
| **HTTP Clients** | httpx, requests |
130+
| **Databases** | SQLAlchemy |
131+
| **Cache** | Redis |
132+
| **Storage** | Local filesystem, AWS S3 |
133+
| **Tools** | CLI, diff engine, HTML timeline |
159134

160-
# Generate timeline
161-
timetracer timeline ./cassettes/POST__checkout.json --open
135+
---
162136

163-
# Search cassettes
164-
timetracer search --endpoint /checkout --method POST --errors
165-
timetracer index --dir ./cassettes
137+
## CLI
166138

167-
# S3 operations
168-
timetracer s3 upload ./cassettes/ -b my-bucket
169-
timetracer s3 sync up -d ./cassettes -b my-bucket
139+
```bash
140+
timetracer list --dir ./cassettes # List all cassettes
141+
timetracer show ./cassettes/GET__users.json # Show cassette details
142+
timetracer diff --a old.json --b new.json # Compare two cassettes
143+
timetracer timeline ./cassettes/GET__users.json --open # Generate timeline
170144
```
171145

146+
---
147+
172148
## Security
173149

174-
By default, Timetracer:
175-
- Removes `Authorization`, `Cookie`, `Set-Cookie` headers
176-
- Masks sensitive body keys (`password`, `token`, etc.)
177-
- Captures bodies only on errors by default
178-
- Enforces size limits (64KB default)
150+
Timetracer automatically protects sensitive data:
151+
152+
- Removes `Authorization`, `Cookie`, and `Set-Cookie` headers
153+
- Masks sensitive fields like `password`, `token`, `api_key` in request/response bodies
154+
- Enforces a 64KB body size limit to prevent large data captures
155+
156+
---
179157

180158
## Documentation
181159

182-
- [Quickstart](docs/quickstart.md)
183-
- [Configuration](docs/configuration.md)
184-
- [Plugins](docs/plugins.md)
160+
- [Quick Start Guide](docs/quickstart.md)
161+
- [Configuration Reference](docs/configuration.md)
162+
- [Plugin Guide](docs/plugins.md)
185163
- [Flask Integration](docs/flask.md)
186-
- [SQLAlchemy Plugin](docs/sqlalchemy.md)
187-
- [S3 Storage](docs/s3-storage.md)
188-
- [Security](docs/security.md)
189-
190-
## Roadmap
164+
- [Security Best Practices](docs/security.md)
191165

192-
- [x] v0.1-v0.3: Core, FastAPI, httpx, requests, diff, timeline
193-
- [x] v1.0: Hybrid replay, schema v1.0, CI/CD, docs
194-
- [x] v2.0: SQLAlchemy, Redis, Flask, S3 store
195-
- [x] v2.1: Cassette search/index
166+
---
196167

197168
## Contributing
198169

199-
Contributions welcome! See [CONTRIBUTING.md](CONTRIBUTING.md).
170+
Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
200171

201172
## License
202173

203-
MIT - see [LICENSE](LICENSE).
174+
MIT License. See [LICENSE](LICENSE) for details.

docs/configuration.md

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -57,26 +57,26 @@ Complete reference for all Timetrace configuration options.
5757

5858
## Environment Variables
5959

60-
All options can be set via environment variables with the `TIMETRACE_` prefix:
60+
All options can be set via environment variables with the `TIMETRACER_` prefix:
6161

6262
| Environment Variable | Config Option |
6363
|---------------------|---------------|
64-
| `TIMETRACE_MODE` | `mode` |
65-
| `TIMETRACE_SERVICE` | `service_name` |
66-
| `TIMETRACE_ENV` | `env` |
67-
| `TIMETRACE_DIR` | `cassette_dir` |
68-
| `TIMETRACE_CASSETTE` | `cassette_path` |
69-
| `TIMETRACE_CAPTURE` | `capture` (comma-separated) |
70-
| `TIMETRACE_SAMPLE_RATE` | `sample_rate` |
71-
| `TIMETRACE_ERRORS_ONLY` | `errors_only` |
72-
| `TIMETRACE_EXCLUDE_PATHS` | `exclude_paths` (comma-separated) |
73-
| `TIMETRACE_MAX_BODY_KB` | `max_body_kb` |
74-
| `TIMETRACE_STORE_REQ_BODY` | `store_request_body` |
75-
| `TIMETRACE_STORE_RES_BODY` | `store_response_body` |
76-
| `TIMETRACE_STRICT_REPLAY` | `strict_replay` |
77-
| `TIMETRACE_MOCK_PLUGINS` | `mock_plugins` (comma-separated) |
78-
| `TIMETRACE_LIVE_PLUGINS` | `live_plugins` (comma-separated) |
79-
| `TIMETRACE_LOG_LEVEL` | `log_level` |
64+
| `TIMETRACER_MODE` | `mode` |
65+
| `TIMETRACER_SERVICE` | `service_name` |
66+
| `TIMETRACER_ENV` | `env` |
67+
| `TIMETRACER_DIR` | `cassette_dir` |
68+
| `TIMETRACER_CASSETTE` | `cassette_path` |
69+
| `TIMETRACER_CAPTURE` | `capture` (comma-separated) |
70+
| `TIMETRACER_SAMPLE_RATE` | `sample_rate` |
71+
| `TIMETRACER_ERRORS_ONLY` | `errors_only` |
72+
| `TIMETRACER_EXCLUDE_PATHS` | `exclude_paths` (comma-separated) |
73+
| `TIMETRACER_MAX_BODY_KB` | `max_body_kb` |
74+
| `TIMETRACER_STORE_REQ_BODY` | `store_request_body` |
75+
| `TIMETRACER_STORE_RES_BODY` | `store_response_body` |
76+
| `TIMETRACER_STRICT_REPLAY` | `strict_replay` |
77+
| `TIMETRACER_MOCK_PLUGINS` | `mock_plugins` (comma-separated) |
78+
| `TIMETRACER_LIVE_PLUGINS` | `live_plugins` (comma-separated) |
79+
| `TIMETRACER_LOG_LEVEL` | `log_level` |
8080

8181
## Configuration Priority
8282

@@ -106,10 +106,10 @@ config = TraceConfig(
106106
### Environment-Only Configuration
107107

108108
```bash
109-
export TIMETRACE_MODE=record
110-
export TIMETRACE_DIR=./cassettes
111-
export TIMETRACE_SAMPLE_RATE=0.5
112-
export TIMETRACE_ERRORS_ONLY=true
109+
export TIMETRACER_MODE=record
110+
export TIMETRACER_DIR=./cassettes
111+
export TIMETRACER_SAMPLE_RATE=0.5
112+
export TIMETRACER_ERRORS_ONLY=true
113113
```
114114

115115
```python
@@ -126,7 +126,7 @@ from timetrace.config import TraceConfig
126126
config = TraceConfig(
127127
service_name="my-api",
128128
cassette_dir="./cassettes",
129-
).with_env_overrides() # TIMETRACE_MODE env var will override mode
129+
).with_env_overrides() # TIMETRACER_MODE env var will override mode
130130
```
131131

132132
### Hybrid Replay Mode
@@ -144,7 +144,7 @@ config = TraceConfig(
144144

145145
Or via environment:
146146
```bash
147-
TIMETRACE_MODE=replay
148-
TIMETRACE_CASSETTE=./cassettes/checkout.json
149-
TIMETRACE_LIVE_PLUGINS=db,redis # Keep DB and Redis live
147+
TIMETRACER_MODE=replay
148+
TIMETRACER_CASSETTE=./cassettes/checkout.json
149+
TIMETRACER_LIVE_PLUGINS=db,redis # Keep DB and Redis live
150150
```

docs/flask.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,10 @@ init_app(app, config)
5555

5656
```bash
5757
# Record mode
58-
TIMETRACE_MODE=record python app.py
58+
TIMETRACER_MODE=record python app.py
5959

6060
# Replay mode
61-
TIMETRACE_MODE=replay TIMETRACE_CASSETTE=./cassettes/POST__checkout__a91c.json python app.py
61+
TIMETRACER_MODE=replay TIMETRACER_CASSETTE=./cassettes/POST__checkout__a91c.json python app.py
6262
```
6363

6464
## Features

0 commit comments

Comments
 (0)