feat(otel): server instrumentation script
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* OTEL instrumentation preload — loaded via `--import` BEFORE tsx processes
|
||||
* any application module. This ensures @opentelemetry/instrumentation-pg can
|
||||
* monkey-patch the CJS `pg` module before it is imported anywhere.
|
||||
*
|
||||
* Only instrumentations that patch third-party modules need to live here.
|
||||
* The full SDK (exporters, metrics, log processors) is still configured in
|
||||
* src/libs/otel.ts — the NodeSDK there will reuse the already-registered
|
||||
* instrumentations.
|
||||
*
|
||||
* NOTICE: `pg` and `ioredis` are CJS packages. When ESM code does
|
||||
* `import pg from 'pg'`, Node.js internally calls `require()` to load
|
||||
* the CJS module, so `require-in-the-middle` hooks still intercept it.
|
||||
*/
|
||||
|
||||
import { registerInstrumentations } from '@opentelemetry/instrumentation'
|
||||
import { HttpInstrumentation } from '@opentelemetry/instrumentation-http'
|
||||
import { IORedisInstrumentation } from '@opentelemetry/instrumentation-ioredis'
|
||||
import { PgInstrumentation } from '@opentelemetry/instrumentation-pg'
|
||||
|
||||
registerInstrumentations({
|
||||
instrumentations: [
|
||||
new HttpInstrumentation({
|
||||
ignoreIncomingRequestHook: req => req.url === '/health',
|
||||
}),
|
||||
new PgInstrumentation({
|
||||
enhancedDatabaseReporting: true,
|
||||
}),
|
||||
new IORedisInstrumentation(),
|
||||
],
|
||||
})
|
||||
@@ -6,9 +6,9 @@
|
||||
"scripts": {
|
||||
"apply:env": "dotenvx run -f .env.local --overload --ignore=MISSING_ENV_FILE",
|
||||
"auth:generate": "pnpm run apply:env -- better-auth generate --config src/scripts/auth.ts --output src/schemas/accounts.ts -y",
|
||||
"dev": "pnpm run apply:env -- tsx --watch src/bin/run.ts api",
|
||||
"start": "pnpm run apply:env -- tsx src/bin/run.ts api",
|
||||
"server": "pnpm run apply:env -- tsx src/bin/run.ts",
|
||||
"dev": "pnpm run apply:env -- tsx --import ./instrumentation.mjs --watch src/bin/run.ts api",
|
||||
"start": "pnpm run apply:env -- tsx --import ./instrumentation.mjs src/bin/run.ts api",
|
||||
"server": "pnpm run apply:env -- tsx --import ./instrumentation.mjs src/bin/run.ts",
|
||||
"build": "tsc -b",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"db:generate": "drizzle-kit generate",
|
||||
@@ -29,6 +29,7 @@
|
||||
"@opentelemetry/exporter-logs-otlp-proto": "^0.214.0",
|
||||
"@opentelemetry/exporter-metrics-otlp-proto": "^0.214.0",
|
||||
"@opentelemetry/exporter-trace-otlp-proto": "^0.214.0",
|
||||
"@opentelemetry/instrumentation": "^0.214.0",
|
||||
"@opentelemetry/instrumentation-http": "^0.214.0",
|
||||
"@opentelemetry/instrumentation-ioredis": "^0.62.0",
|
||||
"@opentelemetry/instrumentation-pg": "^0.66.0",
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import type { Env } from './env'
|
||||
|
||||
import pg from 'pg'
|
||||
|
||||
import { useLogger } from '@guiiai/logg'
|
||||
import { migrate } from '@proj-airi/drizzle-orm-browser-migrator/pg'
|
||||
import { migrations } from '@proj-airi/server-schema'
|
||||
import { drizzle } from 'drizzle-orm/node-postgres'
|
||||
import { Pool } from 'pg'
|
||||
|
||||
import * as fullSchema from '../schemas'
|
||||
|
||||
@@ -14,8 +15,11 @@ export type Database = ReturnType<typeof createDrizzle>['db']
|
||||
|
||||
type DrizzleEnv = Pick<Env, 'DATABASE_URL' | 'DB_POOL_MAX' | 'DB_POOL_IDLE_TIMEOUT_MS' | 'DB_POOL_CONNECTION_TIMEOUT_MS' | 'DB_POOL_KEEPALIVE_INITIAL_DELAY_MS'>
|
||||
|
||||
// NOTICE: pg is imported statically here. The OTEL instrumentation hooks are
|
||||
// registered via --import ./instrumentation.mjs (preload) which runs before
|
||||
// tsx loads application modules, allowing require-in-the-middle to patch pg.
|
||||
export function createDrizzle(env: DrizzleEnv) {
|
||||
const pool = new Pool({
|
||||
const pool = new pg.Pool({
|
||||
connectionString: env.DATABASE_URL,
|
||||
max: env.DB_POOL_MAX,
|
||||
idleTimeoutMillis: env.DB_POOL_IDLE_TIMEOUT_MS,
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import type { IncomingMessage } from 'node:http'
|
||||
|
||||
import type { Counter, Histogram, UpDownCounter } from '@opentelemetry/api'
|
||||
|
||||
import type { Env } from './env'
|
||||
@@ -12,9 +10,6 @@ import { logs, SeverityNumber } from '@opentelemetry/api-logs'
|
||||
import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-proto'
|
||||
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-proto'
|
||||
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto'
|
||||
import { HttpInstrumentation } from '@opentelemetry/instrumentation-http'
|
||||
import { IORedisInstrumentation } from '@opentelemetry/instrumentation-ioredis'
|
||||
import { PgInstrumentation } from '@opentelemetry/instrumentation-pg'
|
||||
import { RuntimeNodeInstrumentation } from '@opentelemetry/instrumentation-runtime-node'
|
||||
import { resourceFromAttributes } from '@opentelemetry/resources'
|
||||
import { BatchLogRecordProcessor } from '@opentelemetry/sdk-logs'
|
||||
@@ -172,17 +167,11 @@ export function initOtel(env: Env): OtelInstance | undefined {
|
||||
exportTimeoutMillis: 10_000,
|
||||
})],
|
||||
logRecordProcessors: [new BatchLogRecordProcessor(logExporter)],
|
||||
// NOTICE: HttpInstrumentation, PgInstrumentation, and IORedisInstrumentation
|
||||
// are registered in instrumentation.cjs (loaded via --require) so that
|
||||
// require-in-the-middle can patch the CJS modules before tsx's ESM loader
|
||||
// imports them. Only non-patching instrumentations belong here.
|
||||
instrumentations: [
|
||||
new HttpInstrumentation({
|
||||
ignoreIncomingRequestHook: (req: IncomingMessage) => {
|
||||
// Ignore health check requests to reduce noise
|
||||
return req.url === '/health'
|
||||
},
|
||||
}),
|
||||
new PgInstrumentation({
|
||||
enhancedDatabaseReporting: true,
|
||||
}),
|
||||
new IORedisInstrumentation(),
|
||||
new RuntimeNodeInstrumentation(),
|
||||
],
|
||||
})
|
||||
|
||||
Generated
+3
@@ -563,6 +563,9 @@ importers:
|
||||
'@opentelemetry/exporter-trace-otlp-proto':
|
||||
specifier: ^0.214.0
|
||||
version: 0.214.0(@opentelemetry/api@1.9.1)
|
||||
'@opentelemetry/instrumentation':
|
||||
specifier: ^0.214.0
|
||||
version: 0.214.0(@opentelemetry/api@1.9.1)
|
||||
'@opentelemetry/instrumentation-http':
|
||||
specifier: ^0.214.0
|
||||
version: 0.214.0(@opentelemetry/api@1.9.1)
|
||||
|
||||
Reference in New Issue
Block a user