autotel-drizzle 0.0.32 → 0.0.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -2
- package/skills/autotel-drizzle/SKILL.md +185 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "autotel-drizzle",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.33",
|
|
4
4
|
"description": "OpenTelemetry instrumentation for Drizzle ORM",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/drizzle.js",
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
"files": [
|
|
17
17
|
"dist",
|
|
18
18
|
"src",
|
|
19
|
-
"README.md"
|
|
19
|
+
"README.md",
|
|
20
|
+
"skills"
|
|
20
21
|
],
|
|
21
22
|
"keywords": [
|
|
22
23
|
"opentelemetry",
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: autotel-drizzle
|
|
3
|
+
description: >
|
|
4
|
+
Use this skill when adding OpenTelemetry tracing to a Drizzle ORM database instance — the only autotel instrumentation package needed for Drizzle, since no official OTel package exists for it.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# autotel-drizzle
|
|
8
|
+
|
|
9
|
+
OpenTelemetry instrumentation for Drizzle ORM. Drizzle has no official OTel package, so this package fills that gap by patching the Drizzle session and client at runtime to create spans for every query, prepared statement, and transaction.
|
|
10
|
+
|
|
11
|
+
**Only use this package for Drizzle.** For databases with working official instrumentation (PostgreSQL via `pg`, MySQL via `mysql2`, SQLite, Redis, MongoDB, Kafka), use the official `@opentelemetry/instrumentation-*` packages directly with the `--import` pattern instead.
|
|
12
|
+
|
|
13
|
+
## Setup
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install autotel autotel-drizzle
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
// src/instrumentation.mts
|
|
21
|
+
import 'autotel/register';
|
|
22
|
+
import { init } from 'autotel';
|
|
23
|
+
|
|
24
|
+
init({ service: 'my-app' });
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
node --import ./src/instrumentation.mts dist/index.js
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Core Patterns
|
|
32
|
+
|
|
33
|
+
### Instrument a Drizzle database instance (recommended)
|
|
34
|
+
|
|
35
|
+
`instrumentDrizzleClient` patches the Drizzle `db` object returned by `drizzle()`. This is the primary API for most use cases.
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
import { drizzle } from 'drizzle-orm/postgres-js';
|
|
39
|
+
import postgres from 'postgres';
|
|
40
|
+
import { instrumentDrizzleClient } from 'autotel-drizzle';
|
|
41
|
+
|
|
42
|
+
const queryClient = postgres(process.env.DATABASE_URL!);
|
|
43
|
+
const db = drizzle({ client: queryClient });
|
|
44
|
+
|
|
45
|
+
instrumentDrizzleClient(db, {
|
|
46
|
+
dbSystem: 'postgresql',
|
|
47
|
+
dbName: 'myapp',
|
|
48
|
+
peerName: 'db.example.com',
|
|
49
|
+
peerPort: 5432,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// All queries, prepared statements, and transactions are now traced
|
|
53
|
+
await db.select().from(users).where(eq(users.id, 123));
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Instrument a raw database client/pool
|
|
57
|
+
|
|
58
|
+
`instrumentDrizzle` patches a lower-level client object (e.g., a `pg.Pool`). Use this when you have the raw client but not a Drizzle instance.
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
import { Pool } from 'pg';
|
|
62
|
+
import { instrumentDrizzle } from 'autotel-drizzle';
|
|
63
|
+
|
|
64
|
+
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
|
|
65
|
+
instrumentDrizzle(pool, { dbSystem: 'postgresql', dbName: 'myapp' });
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Configuration reference (`InstrumentDrizzleConfig`)
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
interface InstrumentDrizzleConfig {
|
|
72
|
+
tracerName?: string; // Default: 'autotel-plugins/drizzle'
|
|
73
|
+
dbSystem?: string; // Default: 'postgresql'. Also: 'mysql', 'sqlite'
|
|
74
|
+
dbName?: string; // Sets db.name on every span
|
|
75
|
+
captureQueryText?: boolean; // Capture SQL text in db.statement (default: true)
|
|
76
|
+
maxQueryTextLength?: number; // Truncate SQL at this length (default: 1000)
|
|
77
|
+
peerName?: string; // Sets net.peer.name
|
|
78
|
+
peerPort?: number; // Sets net.peer.port
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Span attributes set on every span
|
|
83
|
+
|
|
84
|
+
| Attribute | Source |
|
|
85
|
+
| --------------- | ---------------------------------------------------------------- |
|
|
86
|
+
| `db.system` | `config.dbSystem` (default: `'postgresql'`) |
|
|
87
|
+
| `db.operation` | SQL keyword extracted from query text (e.g., `SELECT`, `INSERT`) |
|
|
88
|
+
| `db.name` | `config.dbName` (if set) |
|
|
89
|
+
| `db.statement` | Truncated SQL text (if `captureQueryText: true`) |
|
|
90
|
+
| `net.peer.name` | `config.peerName` (if set) |
|
|
91
|
+
| `net.peer.port` | `config.peerPort` (if set) |
|
|
92
|
+
|
|
93
|
+
Span names follow the pattern `drizzle.<operation>` (e.g., `drizzle.select`, `drizzle.insert`) or `drizzle.query` when the operation cannot be determined.
|
|
94
|
+
|
|
95
|
+
### Disabling SQL capture (PII safety)
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
instrumentDrizzleClient(db, {
|
|
99
|
+
captureQueryText: false,
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
SQL text may contain user-supplied values. Disable capture or truncate aggressively when PII is a concern.
|
|
104
|
+
|
|
105
|
+
### Supported databases
|
|
106
|
+
|
|
107
|
+
- PostgreSQL (`drizzle-orm/node-postgres`, `drizzle-orm/postgres-js`)
|
|
108
|
+
- MySQL (`drizzle-orm/mysql2`)
|
|
109
|
+
- SQLite (`drizzle-orm/better-sqlite3`, `drizzle-orm/libsql`)
|
|
110
|
+
|
|
111
|
+
### What is instrumented
|
|
112
|
+
|
|
113
|
+
- Session `query()` and `execute()` methods
|
|
114
|
+
- Prepared queries (`prepareQuery`) — all execution methods: `all`, `execute`, `get`, `run`, `values`
|
|
115
|
+
- Transactions — the callback receives an already-instrumented transaction object, spans carry `db.transaction: true`
|
|
116
|
+
|
|
117
|
+
### Idempotency
|
|
118
|
+
|
|
119
|
+
Both functions are idempotent. Calling them more than once on the same instance is safe; the `__autotelDrizzleInstrumented` flag prevents double-wrapping.
|
|
120
|
+
|
|
121
|
+
### Using semantic convention exports
|
|
122
|
+
|
|
123
|
+
The package re-exports OTel semconv constants for use in custom instrumentation:
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
import {
|
|
127
|
+
SEMATTRS_DB_SYSTEM,
|
|
128
|
+
SEMATTRS_DB_STATEMENT,
|
|
129
|
+
SEMATTRS_DB_OPERATION,
|
|
130
|
+
} from 'autotel-drizzle';
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Common Mistakes
|
|
134
|
+
|
|
135
|
+
### HIGH — Calling `instrumentDrizzleClient` after queries have already run
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
// Wrong: some early queries miss instrumentation
|
|
139
|
+
const db = drizzle({ client });
|
|
140
|
+
await db.select().from(users); // not instrumented
|
|
141
|
+
|
|
142
|
+
instrumentDrizzleClient(db);
|
|
143
|
+
|
|
144
|
+
// Correct: instrument immediately after creating the db instance
|
|
145
|
+
const db = drizzle({ client });
|
|
146
|
+
instrumentDrizzleClient(db, { dbSystem: 'postgresql' });
|
|
147
|
+
|
|
148
|
+
await db.select().from(users); // instrumented
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Patching works by mutating method references on the live object. Any query that ran before patching has no span.
|
|
152
|
+
|
|
153
|
+
### HIGH — Using autotel-drizzle for databases that have official OTel packages
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
// Wrong: autotel-drizzle is for Drizzle, not for pg directly
|
|
157
|
+
import { instrumentDrizzle } from 'autotel-drizzle';
|
|
158
|
+
instrumentDrizzle(pgPool); // unnecessary if you're not using Drizzle
|
|
159
|
+
|
|
160
|
+
// Correct: use the official package for pg
|
|
161
|
+
import { PgInstrumentation } from '@opentelemetry/instrumentation-pg';
|
|
162
|
+
init({ instrumentations: [new PgInstrumentation()] });
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
For PostgreSQL (`pg`/`postgres`), MySQL (`mysql2`), SQLite, MongoDB, and Redis, official OTel instrumentation packages exist and should be preferred.
|
|
166
|
+
|
|
167
|
+
### MEDIUM — Not setting `dbSystem` for non-PostgreSQL databases
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
// Wrong: dbSystem defaults to 'postgresql' even for SQLite
|
|
171
|
+
instrumentDrizzleClient(sqliteDb);
|
|
172
|
+
|
|
173
|
+
// Correct: set dbSystem to match the actual database
|
|
174
|
+
instrumentDrizzleClient(sqliteDb, { dbSystem: 'sqlite' });
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
The `db.system` span attribute will be wrong if the default is not overridden.
|
|
178
|
+
|
|
179
|
+
### MEDIUM — Passing `captureQueryText: true` without reviewing SQL for PII
|
|
180
|
+
|
|
181
|
+
SQL statements built by Drizzle may embed user-supplied values (e.g., email addresses in `WHERE` clauses). Either disable capture or review what Drizzle sends before enabling in production.
|
|
182
|
+
|
|
183
|
+
## Version
|
|
184
|
+
|
|
185
|
+
Targets autotel-drizzle v0.0.3 with drizzle-orm >= 0.45.1 (peer dep). Requires autotel as a dependency.
|