-
Notifications
You must be signed in to change notification settings - Fork 0
Add Cloudflare D1 (local) adapter for wrangler dev tracing #22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
9713228
Add Cloudflare D1 (local) adapter for tracing queries during wrangler…
claude 39e946d
Show source database (D1 / MariaDB) for each query in IDE plugins
claude 2eeff24
Address review: request-scoped tags, safe send, CI hardening
claude baf2160
Fix stale jsonl field-order comment in collector
claude File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,138 @@ | ||
| # Cloudflare D1 (local) Adapter | ||
|
|
||
| Trace Cloudflare D1 queries during local development (`wrangler dev`) with the | ||
| same job logs, CLI tool, and IDE plugins as the PHP extension. | ||
|
|
||
| D1 runs inside workerd, so the PHP extension cannot hook it directly. Instead | ||
| this adapter has two small parts: | ||
|
|
||
| ```text | ||
| ┌─────────────────────────────┐ ┌─────────────────────────┐ | ||
| │ wrangler dev (workerd) │ │ collector.js (Node) │ | ||
| │ │ HTTP │ │ | ||
| │ traceD1(env.DB) ──────────────────▶ writes jobs logs: │ | ||
| │ intercepts prepare/bind/ │ POST │ {key}.jsonl │ | ||
| │ run/all/first/raw/batch/ │ │ {key}.raw.log │ | ||
| │ exec/withSession │ │ (same format as the │ | ||
| └─────────────────────────────┘ │ PHP extension) │ | ||
| └─────────────────────────┘ | ||
| ``` | ||
|
|
||
| Queries are recorded only while a profiling job is active (started via the | ||
| CLI tool or the VSCode / JetBrains plugins), exactly like the extension. | ||
| When no collector is running or no job is active, queries are dropped | ||
| silently with no impact on your Worker. | ||
|
|
||
| ## Setup | ||
|
|
||
| ### 1. Start the collector | ||
|
|
||
| ```bash | ||
| node d1-adapter/collector.js | ||
| # [mariadb-profiler-d1] collector listening on http://127.0.0.1:8786/ | ||
| # [mariadb-profiler-d1] log dir: /tmp/mariadb_profiler | ||
| ``` | ||
|
|
||
| Options: | ||
|
|
||
| | Option | Default | Description | | ||
| |---|---|---| | ||
| | `--port <n>` | `8786` | Listen port (also `MARIADB_PROFILER_COLLECTOR_PORT`) | | ||
| | `--host <h>` | `127.0.0.1` | Listen host | | ||
| | `--log-dir <dir>` | `/tmp/mariadb_profiler` | Profiler log directory (also `MARIADB_PROFILER_LOG_DIR`); must match the CLI / IDE plugin setting | | ||
| | `--no-raw` | raw enabled | Disable `.raw.log` output (like `mariadb_profiler.raw_log=0`) | | ||
| | `--job-check-interval <ms>` | `1000` | How often `jobs.json` is re-read | | ||
|
|
||
| ### 2. Wrap your D1 binding | ||
|
|
||
| Copy `index.js` into your Worker project (or vendor this directory and import | ||
| it). Then wrap the binding in your fetch handler: | ||
|
|
||
| ```ts | ||
| import { traceD1 } from './mariadb-profiler-d1'; | ||
|
|
||
| export default { | ||
| async fetch(request, env, ctx) { | ||
| // Only trace in local dev: gate with a wrangler dev var. | ||
| const db = traceD1(env.DB, { ctx, enabled: env.D1_TRACE === '1' }); | ||
|
|
||
| db.profilerTag('user_lookup'); | ||
| const user = await db.prepare('SELECT * FROM users WHERE id = ?') | ||
| .bind(42) | ||
| .first(); | ||
| db.profilerUntag(); | ||
|
|
||
| return Response.json(user); | ||
| }, | ||
| }; | ||
| ``` | ||
|
|
||
| `wrangler.toml`: | ||
|
|
||
| ```toml | ||
| [vars] | ||
| D1_TRACE = "1" # set to "0" / omit in production environments | ||
| ``` | ||
|
|
||
| When `enabled` is `false`, `traceD1` returns the original binding untouched, | ||
| so the call is safe to keep in production code paths. Passing `ctx` is | ||
| strongly recommended — log delivery is registered with `ctx.waitUntil()` so | ||
| it is not cancelled when the response returns. | ||
|
|
||
| ### 3. Start a job and run queries | ||
|
|
||
| ```bash | ||
| php cli/mariadb_profiler.php job start d1job | ||
| # ... exercise your Worker with wrangler dev ... | ||
| php cli/mariadb_profiler.php job end d1job | ||
| php cli/mariadb_profiler.php job show d1job | ||
| ``` | ||
|
|
||
| Or start/stop jobs from the VSCode / JetBrains plugin — D1 queries appear in | ||
| the same query list and live tail as mysqlnd queries. | ||
|
|
||
| D1 entries carry a `"db":"d1"` marker in the `.jsonl` log (entries written by | ||
| the PHP extension have no `db` field and are treated as MariaDB). The VSCode | ||
| extension shows the source (`D1` / `MariaDB`) next to each query and as a | ||
| `Source:` row in the expanded details; the JetBrains plugin shows it in the | ||
| `DB` column of the query table and in the detail panel. `php cli/... job show` | ||
| passes the `db` field through as well. | ||
|
|
||
| ## API | ||
|
|
||
| | Function | Description | | ||
| |---|---| | ||
| | `traceD1(db, options?)` | Wrap a `D1Database` (or `D1DatabaseSession`); intercepts `prepare/bind/first/run/all/raw/batch/exec/withSession` | | ||
| | `db.profilerTag(tag)` | Push a tag onto the wrapper's request-scoped stack (recommended) | | ||
| | `db.profilerUntag(tag?)` | Pop a tag from the wrapper's stack; returns the popped tag or `null` | | ||
| | `db.profilerGetTag()` | Current tag (wrapper stack first, then the shared stack), or `null` | | ||
| | `d1ProfilerTag(tag)` | Push a tag onto the **shared** stack (isolate-wide) | | ||
| | `d1ProfilerUntag(tag?)` | Pop a tag from the shared stack; returns the popped tag or `null` | | ||
| | `d1ProfilerGetTag()` | Get the current shared tag, or `null` | | ||
|
|
||
| Create the wrapper inside your fetch handler and use the `db.profilerTag()` | ||
| methods: each wrapper has its own tag stack, so tags never interleave across | ||
| concurrent requests. The module-level `d1ProfilerTag()` functions operate on | ||
| a single stack shared by the whole isolate — fine for simple sequential local | ||
| testing, but concurrent requests will see each other's tags. | ||
|
|
||
| ### `traceD1` options | ||
|
|
||
| | Option | Default | Description | | ||
| |---|---|---| | ||
| | `enabled` | `true` | `false` returns the original binding untouched | | ||
| | `ctx` | — | Request `ExecutionContext`; used for `waitUntil()` (recommended) | | ||
| | `collectorUrl` | `http://127.0.0.1:8786/` | Collector endpoint | | ||
| | `traceDepth` | `0` | JS backtrace frames to record per query (like `mariadb_profiler.trace_depth`; `0` = disabled) | | ||
| | `fetch` | global `fetch` | Custom fetch implementation (for tests) | | ||
|
|
||
| Failed queries are logged with status `err` (the error is re-thrown), bound | ||
| parameters are recorded like prepared statements in the extension, and | ||
| `batch()` logs each statement individually. | ||
|
|
||
| ## Tests | ||
|
|
||
| ```bash | ||
| cd d1-adapter | ||
| npm test | ||
| ``` |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.