{"_id":"@8monkey/opentelemetry-instrumentation-bun-sql","_rev":"2-9e903352ef9048b2e41e111ba8bfebc3","name":"@8monkey/opentelemetry-instrumentation-bun-sql","dist-tags":{"rc":"0.1.0-rc0","latest":"0.2.0"},"versions":{"0.1.0-rc0":{"name":"@8monkey/opentelemetry-instrumentation-bun-sql","version":"0.1.0-rc0","keywords":["bun","mysql","opentelemetry","otel","postgresql","sqlite"],"license":"Apache-2.0","_id":"@8monkey/opentelemetry-instrumentation-bun-sql@0.1.0-rc0","maintainers":[{"name":"heiwen","email":"h@8monkey.ai"},{"name":"turisanapo","email":"selvaggiodavide@hotmail.it"}],"homepage":"https://hebo.ai","bugs":{"url":"https://github.com/8monkey-ai/opentelemetry-instrumentation-bun-sql/issues"},"dist":{"shasum":"e5064a1004d06ae9e6b99939834bcd7ccad9124e","tarball":"https://registry.npmjs.org/@8monkey/opentelemetry-instrumentation-bun-sql/-/opentelemetry-instrumentation-bun-sql-0.1.0-rc0.tgz","fileCount":15,"integrity":"sha512-DCZI6eQj5whHvGSPTvCUnwMvmR5/Rm7L3Z0SfrRezJXESLfxUCJHfbGsAo8XiDMFyBZPVZryySfwg2ZTFBEiJQ==","signatures":[{"sig":"MEQCIHWHeHE7xA6WTYPAetEFblkqs5Pgo1JNeIVkk0kWMUnkAiBnGQfhA8wVcq/g4oV9AUW80F+9JSFR/fF1GuOT5XQmzw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":46420},"type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"876ce0c1fad0a010878df3f35834a99e0186db5c","scripts":{"fix":"bun lint:staged && bun format:staged","lint":"oxlint","test":"bun test","build":"tsc -p tsconfig.build.json","check":"bun lint && bun typecheck","clean":"git clean -fdx -e '.env*' .","format":"oxfmt .","typecheck":"oxlint --type-check","lint:staged":"oxlint --fix","format:staged":"oxfmt --no-error-on-unmatched-pattern"},"_npmUser":{"name":"heiwen","email":"h@8monkey.ai"},"repository":{"url":"git+https://github.com/8monkey-ai/opentelemetry-instrumentation-bun-sql.git","type":"git"},"_npmVersion":"11.10.1","description":"OpenTelemetry instrumentation for `Bun.SQL` database client for PostgreSQL / MySQL / SQLite","directories":{},"sideEffects":false,"_nodeVersion":"25.7.0","dependencies":{"@opentelemetry/sql-common":"^0.41.2","@opentelemetry/instrumentation":"^0.214.0","@opentelemetry/semantic-conventions":"^1.40.0"},"_hasShrinkwrap":false,"devDependencies":{"oxfmt":"^0.44.0","oxlint":"^1.59.0","bun-types":"^1.3.12","typescript":"^6.0.2","oxlint-tsgolint":"^0.20.0","@opentelemetry/api":"^1.9.1","@electric-sql/pglite":"^0.4.4","@opentelemetry/resources":"^2.6.1","@opentelemetry/sdk-trace-base":"^2.6.1","@opentelemetry/sdk-trace-node":"^2.6.1","@opentelemetry/context-async-hooks":"^2.6.1"},"peerDependencies":{"@opentelemetry/api":"^1.3.0"},"peerDependenciesMeta":{},"_npmOperationalInternal":{"tmp":"tmp/opentelemetry-instrumentation-bun-sql_0.1.0-rc0_1775964331161_0.8554725269539627","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@8monkey/opentelemetry-instrumentation-bun-sql","version":"0.2.0","description":"OpenTelemetry instrumentation for `Bun.SQL` database client for PostgreSQL / MySQL / SQLite","keywords":["bun","mysql","opentelemetry","otel","postgresql","sqlite"],"homepage":"https://hebo.ai","bugs":{"url":"https://github.com/8monkey-ai/opentelemetry-instrumentation-bun-sql/issues"},"license":"Apache-2.0","repository":{"type":"git","url":"git+https://github.com/8monkey-ai/opentelemetry-instrumentation-bun-sql.git"},"type":"module","sideEffects":false,"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"build":"tsc -p tsconfig.build.json","clean":"git clean -fdx -e '.env*' .","format":"oxfmt .","format:staged":"oxfmt --no-error-on-unmatched-pattern","lint":"oxlint","lint:staged":"oxlint --fix","typecheck":"oxlint --type-check","test":"bun test","check":"bun lint && bun typecheck","fix":"bun lint:staged && bun format:staged"},"dependencies":{"@opentelemetry/core":"^2.6.1","@opentelemetry/instrumentation":"^0.214.0","@opentelemetry/semantic-conventions":"^1.40.0","@opentelemetry/sql-common":"^0.41.2"},"devDependencies":{"@electric-sql/pglite":"^0.4.4","@opentelemetry/api":"^1.9.1","@opentelemetry/context-async-hooks":"^2.6.1","@opentelemetry/resources":"^2.6.1","@opentelemetry/sdk-metrics":"^2.6.1","@opentelemetry/sdk-trace-base":"^2.6.1","@opentelemetry/sdk-trace-node":"^2.6.1","bun-types":"^1.3.12","oxfmt":"^0.44.0","oxlint":"^1.59.0","oxlint-tsgolint":"^0.20.0","typescript":"^6.0.2"},"peerDependencies":{"@opentelemetry/api":"^1.3.0"},"peerDependenciesMeta":{},"gitHead":"829dd2115043d5d42ebb04ee0b51df3d6af23eac","_id":"@8monkey/opentelemetry-instrumentation-bun-sql@0.2.0","_nodeVersion":"25.7.0","_npmVersion":"11.10.1","dist":{"integrity":"sha512-boua4k0Ji8y66Dtglcnxc+oODxtb5yyT+BcUaCjdZPckJhfxOFvnojRbXLpVjyyZIx3j8wPlydkr16wF6Lhkuw==","shasum":"a9434edc0b58487095297a9149a8935791bb7f9d","tarball":"https://registry.npmjs.org/@8monkey/opentelemetry-instrumentation-bun-sql/-/opentelemetry-instrumentation-bun-sql-0.2.0.tgz","fileCount":15,"unpackedSize":51183,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQD4+vG+mCyWdrhuna0AgqKreRdJ5Dy5XkAivhXGB1Ur9gIhAMZ9Eyg6cXbG+l6vm3uHF9q/MI8ViCPtMB8p3wwfX2+n"}]},"_npmUser":{"name":"heiwen","email":"h@8monkey.ai"},"directories":{},"maintainers":[{"name":"heiwen","email":"h@8monkey.ai"},{"name":"turisanapo","email":"selvaggiodavide@hotmail.it"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/opentelemetry-instrumentation-bun-sql_0.2.0_1776138421532_0.8377398399568747"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-12T03:25:31.044Z","modified":"2026-04-14T03:47:01.808Z","0.1.0-rc0":"2026-04-12T03:25:31.298Z","0.2.0":"2026-04-14T03:47:01.663Z"},"bugs":{"url":"https://github.com/8monkey-ai/opentelemetry-instrumentation-bun-sql/issues"},"license":"Apache-2.0","homepage":"https://hebo.ai","keywords":["bun","mysql","opentelemetry","otel","postgresql","sqlite"],"repository":{"type":"git","url":"git+https://github.com/8monkey-ai/opentelemetry-instrumentation-bun-sql.git"},"description":"OpenTelemetry instrumentation for `Bun.SQL` database client for PostgreSQL / MySQL / SQLite","maintainers":[{"name":"heiwen","email":"h@8monkey.ai"},{"name":"turisanapo","email":"selvaggiodavide@hotmail.it"}],"readme":"# OpenTelemetry Bun.SQL Instrumentation\n\nOpenTelemetry instrumentation for [Bun.SQL](https://bun.sh/docs/api/sql), the built-in database client in Bun supporting PostgreSQL, MySQL, and SQLite.\n\n## Installation\n\n```bash\nbun add @8monkey/opentelemetry-instrumentation-bun-sql\n```\n\n## Supported Versions\n\n- Bun >= 1.2\n\n## Usage\n\n```typescript\nimport { NodeTracerProvider } from \"@opentelemetry/sdk-trace-node\";\nimport { SimpleSpanProcessor, ConsoleSpanExporter } from \"@opentelemetry/sdk-trace-base\";\nimport { registerInstrumentations } from \"@opentelemetry/instrumentation\";\nimport { BunSqlInstrumentation } from \"@8monkey/opentelemetry-instrumentation-bun-sql\";\n\n// 1. Register instrumentation before creating any SQL instances.\n//    Bun built-ins bypass Node.js module hooks, so the instrumentation patches\n//    require(\"bun\").SQL at enable time — instances created before this are not traced.\nconst provider = new NodeTracerProvider({\n  spanProcessors: [new SimpleSpanProcessor(new ConsoleSpanExporter())],\n});\nprovider.register();\n\nregisterInstrumentations({\n  instrumentations: [new BunSqlInstrumentation()],\n});\n\n// 2. Create instances via require(\"bun\"), not `import { SQL } from \"bun\"`.\n//    Static import bindings are resolved at module load time (before step 1 runs)\n//    and therefore always capture the original, unpatched constructor.\nconst sql = new (require(\"bun\") as typeof Bun).SQL({ adapter: \"sqlite\" });\n\nawait sql`SELECT 1`;\nawait sql.close();\n```\n\n## Semantic Conventions\n\nThis instrumentation follows the [OpenTelemetry Database Semantic Conventions](https://opentelemetry.io/docs/specs/semconv/database/).\n\n### Attributes\n\n| Attribute                   | Description                                                                           |\n| --------------------------- | ------------------------------------------------------------------------------------- |\n| `db.system.name`            | Database system: `postgresql`, `mysql`, or `sqlite`                                   |\n| `db.operation.name`         | SQL operation: `SELECT`, `INSERT`, `UPDATE`, `DELETE`, etc.                           |\n| `db.query.text`             | The SQL query text (parameterized for tagged templates, sanitized for unsafe queries) |\n| `db.namespace`              | Database name or SQLite filename                                                      |\n| `db.response.returned_rows` | Number of rows returned                                                               |\n| `server.address`            | Server hostname (PostgreSQL/MySQL)                                                    |\n| `server.port`               | Server port (PostgreSQL/MySQL)                                                        |\n| `error.type`                | Error class name (e.g., `SQLiteError`, `PostgresError`)                               |\n| `db.response.status_code`   | Database-specific error code                                                          |\n\n### Span names\n\nSpan names follow the OTel convention priority:\n\n1. `{db.operation.name} {db.namespace}` (e.g., `SELECT mydb`)\n2. `{db.operation.name}` (e.g., `SELECT`)\n3. `{db.namespace}` (e.g., `mydb`)\n4. `{db.system.name}` (e.g., `postgresql`)\n\n### Metrics\n\nThis instrumentation emits the following metric per the [OTel DB metrics semantic conventions](https://opentelemetry.io/docs/specs/semconv/database/database-metrics/):\n\n#### `db.client.operation.duration`\n\n| Property    | Value                                              |\n| ----------- | -------------------------------------------------- |\n| Type        | Histogram                                          |\n| Unit        | `s` (seconds)                                      |\n| Description | Duration of database client operations             |\n| Buckets     | `0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5, 10`   |\n\nMetric attributes:\n\n| Attribute                 | Requirement           | Description                                 |\n| ------------------------- | --------------------- | ------------------------------------------- |\n| `db.system.name`          | Required              | Database system identifier                  |\n| `db.operation.name`       | Conditionally Required | Database operation (e.g., `SELECT`)         |\n| `db.namespace`            | Conditionally Required | Database name or SQLite filename             |\n| `error.type`              | Conditionally Required | Error class name (only on failure)          |\n| `db.response.status_code` | Conditionally Required | Database error code (only on failure)       |\n| `server.address`          | Recommended           | Server hostname                             |\n| `server.port`             | Conditionally Required | Server port (when non-default)              |\n\n`db.query.text` is intentionally excluded from metric attributes to avoid high-cardinality issues and PII exposure.\n\n## Configuration\n\n| Option                      | Type                        | Default         | Description                                                                                        |\n| --------------------------- | --------------------------- | --------------- | -------------------------------------------------------------------------------------------------- |\n| `requireParentSpan`         | `boolean`                   | `false`         | Only create spans when a parent span exists in context                                             |\n| `enhancedDatabaseReporting` | `boolean`                   | `false`         | Include query parameters (`db.query.parameter.<n>`) and result data in spans                       |\n| `ignoreConnectionSpans`     | `boolean`                   | `false`         | Suppress spans for `CLOSE` and `RESERVE` operations                                                |\n| `maskStatement`             | `boolean`                   | `true`          | Replace integer literals and quoted strings with `?` in non-parameterized queries (`sql.unsafe()`) |\n| `maskStatementHook`         | `(query: string) => string` | Built-in masker | Custom masking function for non-parameterized queries                                              |\n| `addSqlCommenterComment`    | `boolean`                   | `false`         | Append SQL commenter traceparent comments to queries                                               |\n| `requestHook`               | `(span, info) => void`      | -               | Called before query execution to customize span attributes                                         |\n| `responseHook`              | `(span, info) => void`      | -               | Called after query execution with response metadata                                                |\n\n### Example with hooks\n\n```typescript\nimport type {\n  BunSqlRequestHookInformation,\n  BunSqlResponseHookInformation,\n} from \"@8monkey/opentelemetry-instrumentation-bun-sql\";\n\nnew BunSqlInstrumentation({\n  requestHook: (span, info: BunSqlRequestHookInformation) => {\n    span.setAttribute(\"custom.query\", info.query);\n  },\n  responseHook: (span, info: BunSqlResponseHookInformation) => {\n    if (info.rowCount !== undefined) {\n      span.setAttribute(\"custom.row_count\", info.rowCount);\n    }\n  },\n});\n```\n\n## What gets instrumented\n\n- **Tagged template queries**: `` sql`SELECT * FROM users WHERE id = ${id}` ``\n- **Unsafe queries**: `sql.unsafe(\"SELECT * FROM users\")`\n- **Queries inside transactions**: queries run inside `sql.begin(tx => ...)`, `tx.savepoint(sp => ...)`, etc. are individually traced; no span is emitted for the transaction boundary itself\n- **Connection management**: `sql.close()`, `sql.reserve()`\n- **Chaining methods**: `.values()`, `.raw()`, `.simple()`, `.execute()`\n\n### Query text handling\n\n| Query type                                 | `db.query.text` behavior                                   |\n| ------------------------------------------ | ---------------------------------------------------------- |\n| Tagged template                            | Parameterized: `SELECT * FROM users WHERE id = $1`         |\n| `sql.unsafe()`                             | Sanitized by default: `SELECT * FROM users WHERE name = ?` |\n| `sql.unsafe()` with `maskStatement: false` | Raw text preserved                                         |\n","readmeFilename":"README.md"}