@tokenbooks/zenstack-otel
v0.1.1
Published
OpenTelemetry runtime plugin for ZenStack ORM query and Kysely hooks
Maintainers
Readme
@tokenbooks/zenstack-otel
OpenTelemetry runtime plugin for ZenStack ORM.
This package wraps ZenStack's runtime plugin hooks and emits spans for:
- ORM query operations via
onQuery - Kysely query execution via
onKyselyQuery
It is a runtime plugin for ZenStack ORM, not a zen generate CLI plugin.
Install
pnpm add @tokenbooks/zenstack-otel @opentelemetry/api @zenstackhq/ormUsage
Install the plugin either through the client constructor's plugins option or by calling $use.
import { Pool } from 'pg';
import { ZenStackClient } from '@zenstackhq/orm';
import { PostgresDialect } from '@zenstackhq/orm/dialects/postgres';
import { createZenStackOtelPlugin } from '@tokenbooks/zenstack-otel';
import { schema } from './schema';
const db = new ZenStackClient(schema, {
dialect: new PostgresDialect({
pool: new Pool({
connectionString: process.env.DATABASE_URL,
}),
}),
plugins: [
createZenStackOtelPlugin({
tracerName: 'api-db',
}),
],
});Or:
const tracedDb = db.$use(createZenStackOtelPlugin());Emitted spans
createZenStackOtelPlugin() creates spans with these names:
zenstack.<Model>.<operation>for ORM query hookszenstack.kysely.queryfor Kysely query hooks
It sets these attributes when available:
db.orm=zenstackdb.zenstack.modeldb.zenstack.operationdb.zenstack.kysely.kinddb.statementwhencaptureStatementis enableddb.zenstack.kysely.parameter_countwhencaptureStatementis enableddb.zenstack.kysely.parameterswhen bothcaptureStatementandcaptureParametersare enabled
API
createZenStackOtelPlugin(options?)
Creates a ZenStack runtime plugin instance.
Options:
pluginId?: stringoverrides the default plugin id (zenstack-otel)tracerName?: stringoverrides the tracer name passed totrace.getTracercaptureStatement?: booleanattaches the compiled Kysely SQL text with placeholders to Kysely spanscaptureParameters?: booleanalso attaches compiled bind parameters as JSON; requirescaptureStatement: truespanLifecycle?: SpanLifecycleinjects a custom span runner, useful for tests or custom wrappers
new ZenStackOtelPlugin(options).create()
Class-based API for callers who prefer explicit construction over the factory function.
getDefaultZenStackOtelPlugin()
Returns a lazily cached default plugin instance.
SQL capture
By default, the plugin records logical ZenStack attributes only. If you enable captureStatement, the Kysely hook recompiles the operation node to recover dialect-specific SQL text with placeholders. If you also enable captureParameters, it serializes the compiled bind parameters into a separate span attribute.
Example:
createZenStackOtelPlugin({
tracerName: 'api-db',
captureStatement: true,
captureParameters: true,
});That produces Kysely span attributes like:
db.statement = select * from "User" where "id" = $1db.zenstack.kysely.parameter_count = 1db.zenstack.kysely.parameters = ["user-1"]
captureParameters requires captureStatement: true.
This extra compilation work can add overhead on hot paths. ZenStack's current onKyselyQuery hook exposes the Kysely operation node, not ZenStack's already-compiled query object, so there is no stable public hook payload to reuse instead of recompiling.
Development notes
ZenStack's plugin API is currently documented as a preview feature, so this package tracks the ZenStack v3 runtime plugin surface described here:
- https://zenstack.dev/docs/orm/plugins
- https://zenstack.dev/docs/orm/plugins/kysely-query-hooks
- https://zenstack.dev/docs/recipe/plugin-dev
Release
pnpm release:patch
pnpm release:minor
pnpm release:majorThe release script runs lint, tests, and build, bumps package.json, tags vX.Y.Z, and pushes to main. GitHub Actions publishes to npm from the tag.
