@vestig/next 0.16.0 → 0.19.0
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/dist/db/index.d.ts +2 -1
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +2 -0
- package/dist/db/index.js.map +1 -1
- package/dist/db/postgres.d.ts +123 -0
- package/dist/db/postgres.d.ts.map +1 -0
- package/dist/db/postgres.js +298 -0
- package/dist/db/postgres.js.map +1 -0
- package/dist/db/types.d.ts +36 -0
- package/dist/db/types.d.ts.map +1 -1
- package/dist/instrumentation/index.d.ts +24 -0
- package/dist/instrumentation/index.d.ts.map +1 -0
- package/dist/instrumentation/index.js +23 -0
- package/dist/instrumentation/index.js.map +1 -0
- package/dist/instrumentation/register.d.ts +92 -0
- package/dist/instrumentation/register.d.ts.map +1 -0
- package/dist/instrumentation/register.js +305 -0
- package/dist/instrumentation/register.js.map +1 -0
- package/dist/instrumentation/types.d.ts +147 -0
- package/dist/instrumentation/types.d.ts.map +1 -0
- package/dist/instrumentation/types.js +5 -0
- package/dist/instrumentation/types.js.map +1 -0
- package/package.json +10 -3
package/dist/db/index.d.ts
CHANGED
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
*/
|
|
45
45
|
export { withVestigPrisma, createPrismaQueryHandler, createPrismaLogConfig, type VestigPrismaOptions, } from './prisma';
|
|
46
46
|
export { createVestigDrizzleLogger, createDrizzleQueryLogger, measureQuery, type VestigDrizzleLoggerOptions, } from './drizzle';
|
|
47
|
+
export { instrumentPostgres, isPostgresInstrumented, type PostgresInstrumentConfig, } from './postgres';
|
|
47
48
|
export { formatDuration, createQueryLogEntry, logQuery, mergeConfig, extractAllTableNames, } from './query-logger';
|
|
48
|
-
export type { QueryLogEntry, DbLoggerConfig, PrismaQueryEvent, PrismaLogEvent, DrizzleLogger, } from './types';
|
|
49
|
+
export type { QueryLogEntry, DbLoggerConfig, DatabaseInstrumentConfig, PrismaQueryEvent, PrismaLogEvent, DrizzleLogger, } from './types';
|
|
49
50
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/db/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAGH,OAAO,EACN,gBAAgB,EAChB,wBAAwB,EACxB,qBAAqB,EACrB,KAAK,mBAAmB,GACxB,MAAM,UAAU,CAAA;AAGjB,OAAO,EACN,yBAAyB,EACzB,wBAAwB,EACxB,YAAY,EACZ,KAAK,0BAA0B,GAC/B,MAAM,WAAW,CAAA;AAGlB,OAAO,EACN,cAAc,EACd,mBAAmB,EACnB,QAAQ,EACR,WAAW,EACX,oBAAoB,GACpB,MAAM,gBAAgB,CAAA;AAGvB,YAAY,EACX,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,cAAc,EACd,aAAa,GACb,MAAM,SAAS,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAGH,OAAO,EACN,gBAAgB,EAChB,wBAAwB,EACxB,qBAAqB,EACrB,KAAK,mBAAmB,GACxB,MAAM,UAAU,CAAA;AAGjB,OAAO,EACN,yBAAyB,EACzB,wBAAwB,EACxB,YAAY,EACZ,KAAK,0BAA0B,GAC/B,MAAM,WAAW,CAAA;AAGlB,OAAO,EACN,kBAAkB,EAClB,sBAAsB,EACtB,KAAK,wBAAwB,GAC7B,MAAM,YAAY,CAAA;AAGnB,OAAO,EACN,cAAc,EACd,mBAAmB,EACnB,QAAQ,EACR,WAAW,EACX,oBAAoB,GACpB,MAAM,gBAAgB,CAAA;AAGvB,YAAY,EACX,aAAa,EACb,cAAc,EACd,wBAAwB,EACxB,gBAAgB,EAChB,cAAc,EACd,aAAa,GACb,MAAM,SAAS,CAAA"}
|
package/dist/db/index.js
CHANGED
|
@@ -46,6 +46,8 @@
|
|
|
46
46
|
export { withVestigPrisma, createPrismaQueryHandler, createPrismaLogConfig, } from './prisma';
|
|
47
47
|
// Drizzle integration
|
|
48
48
|
export { createVestigDrizzleLogger, createDrizzleQueryLogger, measureQuery, } from './drizzle';
|
|
49
|
+
// PostgreSQL driver instrumentation
|
|
50
|
+
export { instrumentPostgres, isPostgresInstrumented, } from './postgres';
|
|
49
51
|
// Core utilities
|
|
50
52
|
export { formatDuration, createQueryLogEntry, logQuery, mergeConfig, extractAllTableNames, } from './query-logger';
|
|
51
53
|
//# sourceMappingURL=index.js.map
|
package/dist/db/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,qBAAqB;AACrB,OAAO,EACN,gBAAgB,EAChB,wBAAwB,EACxB,qBAAqB,GAErB,MAAM,UAAU,CAAA;AAEjB,sBAAsB;AACtB,OAAO,EACN,yBAAyB,EACzB,wBAAwB,EACxB,YAAY,GAEZ,MAAM,WAAW,CAAA;AAElB,iBAAiB;AACjB,OAAO,EACN,cAAc,EACd,mBAAmB,EACnB,QAAQ,EACR,WAAW,EACX,oBAAoB,GACpB,MAAM,gBAAgB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,qBAAqB;AACrB,OAAO,EACN,gBAAgB,EAChB,wBAAwB,EACxB,qBAAqB,GAErB,MAAM,UAAU,CAAA;AAEjB,sBAAsB;AACtB,OAAO,EACN,yBAAyB,EACzB,wBAAwB,EACxB,YAAY,GAEZ,MAAM,WAAW,CAAA;AAElB,oCAAoC;AACpC,OAAO,EACN,kBAAkB,EAClB,sBAAsB,GAEtB,MAAM,YAAY,CAAA;AAEnB,iBAAiB;AACjB,OAAO,EACN,cAAc,EACd,mBAAmB,EACnB,QAAQ,EACR,WAAW,EACX,oBAAoB,GACpB,MAAM,gBAAgB,CAAA"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PostgreSQL Auto-Instrumentation
|
|
3
|
+
*
|
|
4
|
+
* Wraps postgres-js client for automatic span creation and metrics.
|
|
5
|
+
* Provides precise timing measurement by wrapping at the driver level.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import postgres from 'postgres'
|
|
10
|
+
* import { instrumentPostgres } from '@vestig/next/db'
|
|
11
|
+
* import { drizzle } from 'drizzle-orm/postgres-js'
|
|
12
|
+
*
|
|
13
|
+
* const client = instrumentPostgres(postgres(DATABASE_URL), {
|
|
14
|
+
* slowQueryThreshold: 100,
|
|
15
|
+
* onQuery: (entry) => {
|
|
16
|
+
* if (entry.isSlow) metrics.recordSlowQuery(entry)
|
|
17
|
+
* }
|
|
18
|
+
* })
|
|
19
|
+
*
|
|
20
|
+
* export const db = drizzle(client)
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @packageDocumentation
|
|
24
|
+
*/
|
|
25
|
+
import type { DbLoggerConfig } from './types';
|
|
26
|
+
/**
|
|
27
|
+
* Configuration for postgres-js instrumentation
|
|
28
|
+
*/
|
|
29
|
+
export interface PostgresInstrumentConfig extends DbLoggerConfig {
|
|
30
|
+
/**
|
|
31
|
+
* Database system name for OTLP semantic conventions
|
|
32
|
+
* @default 'postgresql'
|
|
33
|
+
*/
|
|
34
|
+
dbSystem?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Database name for OTLP attributes
|
|
37
|
+
*/
|
|
38
|
+
dbName?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Connection string or identifier (will be sanitized)
|
|
41
|
+
* Used for debugging, credentials are removed
|
|
42
|
+
*/
|
|
43
|
+
connectionName?: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Type for postgres-js Sql client
|
|
47
|
+
* We use a minimal interface to avoid requiring postgres as a dependency
|
|
48
|
+
*/
|
|
49
|
+
interface PostgresSql {
|
|
50
|
+
(strings: TemplateStringsArray, ...values: unknown[]): Promise<unknown[]>;
|
|
51
|
+
unsafe: (query: string, params?: unknown[]) => Promise<unknown[]>;
|
|
52
|
+
begin: <T>(fn: (sql: PostgresSql) => Promise<T>) => Promise<T>;
|
|
53
|
+
end: (options?: {
|
|
54
|
+
timeout?: number;
|
|
55
|
+
}) => Promise<void>;
|
|
56
|
+
file: (path: string, options?: unknown) => Promise<unknown[]>;
|
|
57
|
+
[key: string]: unknown;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Instrument a postgres-js client for automatic span creation and metrics
|
|
61
|
+
*
|
|
62
|
+
* This function wraps the postgres-js client to automatically:
|
|
63
|
+
* - Create OTLP spans for each query
|
|
64
|
+
* - Measure precise query duration
|
|
65
|
+
* - Detect slow queries
|
|
66
|
+
* - Call the onQuery callback for external metrics
|
|
67
|
+
*
|
|
68
|
+
* @example Basic usage
|
|
69
|
+
* ```typescript
|
|
70
|
+
* import postgres from 'postgres'
|
|
71
|
+
* import { instrumentPostgres } from '@vestig/next/db'
|
|
72
|
+
*
|
|
73
|
+
* const sql = instrumentPostgres(postgres(DATABASE_URL))
|
|
74
|
+
*
|
|
75
|
+
* // All queries now create spans automatically
|
|
76
|
+
* const users = await sql`SELECT * FROM users`
|
|
77
|
+
* ```
|
|
78
|
+
*
|
|
79
|
+
* @example With Drizzle ORM
|
|
80
|
+
* ```typescript
|
|
81
|
+
* import postgres from 'postgres'
|
|
82
|
+
* import { instrumentPostgres } from '@vestig/next/db'
|
|
83
|
+
* import { drizzle } from 'drizzle-orm/postgres-js'
|
|
84
|
+
*
|
|
85
|
+
* const client = instrumentPostgres(postgres(DATABASE_URL), {
|
|
86
|
+
* slowQueryThreshold: 100,
|
|
87
|
+
* onQuery: (entry) => {
|
|
88
|
+
* // Send to your metrics system for noisy neighbor detection
|
|
89
|
+
* if (entry.isSlow) {
|
|
90
|
+
* metrics.recordSlowQuery({
|
|
91
|
+
* table: entry.table,
|
|
92
|
+
* operation: entry.operation,
|
|
93
|
+
* duration: entry.duration,
|
|
94
|
+
* })
|
|
95
|
+
* }
|
|
96
|
+
* }
|
|
97
|
+
* })
|
|
98
|
+
*
|
|
99
|
+
* export const db = drizzle(client)
|
|
100
|
+
* ```
|
|
101
|
+
*
|
|
102
|
+
* @example With custom database name
|
|
103
|
+
* ```typescript
|
|
104
|
+
* const sql = instrumentPostgres(postgres(DATABASE_URL), {
|
|
105
|
+
* dbName: 'myapp_production',
|
|
106
|
+
* dbSystem: 'postgresql',
|
|
107
|
+
* })
|
|
108
|
+
* ```
|
|
109
|
+
*
|
|
110
|
+
* @param client - The postgres-js client instance
|
|
111
|
+
* @param options - Configuration options
|
|
112
|
+
* @returns Instrumented postgres-js client with the same interface
|
|
113
|
+
*/
|
|
114
|
+
export declare function instrumentPostgres<T extends PostgresSql>(client: T, options?: PostgresInstrumentConfig): T;
|
|
115
|
+
/**
|
|
116
|
+
* Check if a postgres-js client is instrumented
|
|
117
|
+
*
|
|
118
|
+
* Note: This is a best-effort check. Due to Proxy transparency,
|
|
119
|
+
* it's not always possible to detect instrumentation.
|
|
120
|
+
*/
|
|
121
|
+
export declare function isPostgresInstrumented(client: unknown): boolean;
|
|
122
|
+
export {};
|
|
123
|
+
//# sourceMappingURL=postgres.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../src/db/postgres.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAE7C;;GAEG;AACH,MAAM,WAAW,wBAAyB,SAAQ,cAAc;IAC/D;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IAEjB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;CACvB;AAED;;;GAGG;AACH,UAAU,WAAW;IAEpB,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;IAGzE,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;IACjE,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAA;IAC9D,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACtD,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;IAG7D,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACtB;AAyLD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,WAAW,EACvD,MAAM,EAAE,CAAC,EACT,OAAO,CAAC,EAAE,wBAAwB,GAChC,CAAC,CA2EH;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAI/D"}
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PostgreSQL Auto-Instrumentation
|
|
3
|
+
*
|
|
4
|
+
* Wraps postgres-js client for automatic span creation and metrics.
|
|
5
|
+
* Provides precise timing measurement by wrapping at the driver level.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import postgres from 'postgres'
|
|
10
|
+
* import { instrumentPostgres } from '@vestig/next/db'
|
|
11
|
+
* import { drizzle } from 'drizzle-orm/postgres-js'
|
|
12
|
+
*
|
|
13
|
+
* const client = instrumentPostgres(postgres(DATABASE_URL), {
|
|
14
|
+
* slowQueryThreshold: 100,
|
|
15
|
+
* onQuery: (entry) => {
|
|
16
|
+
* if (entry.isSlow) metrics.recordSlowQuery(entry)
|
|
17
|
+
* }
|
|
18
|
+
* })
|
|
19
|
+
*
|
|
20
|
+
* export const db = drizzle(client)
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @packageDocumentation
|
|
24
|
+
*/
|
|
25
|
+
import { span } from 'vestig';
|
|
26
|
+
import { getDatabaseConfig } from '../instrumentation/register';
|
|
27
|
+
import { createQueryLogEntry, mergeConfig } from './query-logger';
|
|
28
|
+
/**
|
|
29
|
+
* Build a parameterized query string from template literal parts
|
|
30
|
+
*/
|
|
31
|
+
function buildQueryString(strings, values) {
|
|
32
|
+
let result = strings[0] ?? '';
|
|
33
|
+
for (let i = 0; i < values.length; i++) {
|
|
34
|
+
result += `$${i + 1}${strings[i + 1] ?? ''}`;
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Execute an instrumented query with span creation
|
|
40
|
+
*/
|
|
41
|
+
async function instrumentedQuery(target, args, state) {
|
|
42
|
+
const [strings, ...values] = args;
|
|
43
|
+
const query = buildQueryString(strings, values);
|
|
44
|
+
// Create initial entry (duration will be updated after execution)
|
|
45
|
+
const entry = createQueryLogEntry(query, values, 0, state.config);
|
|
46
|
+
const spanName = `db.query ${entry.operation}${entry.table ? ` ${entry.table}` : ''}`;
|
|
47
|
+
return span(spanName, async (s) => {
|
|
48
|
+
// Set OpenTelemetry semantic conventions for database
|
|
49
|
+
s.setAttribute('db.system', state.dbSystem);
|
|
50
|
+
s.setAttribute('db.operation', entry.operation);
|
|
51
|
+
s.setAttribute('db.statement', entry.query);
|
|
52
|
+
if (entry.table)
|
|
53
|
+
s.setAttribute('db.sql.table', entry.table);
|
|
54
|
+
if (state.dbName)
|
|
55
|
+
s.setAttribute('db.name', state.dbName);
|
|
56
|
+
const start = performance.now();
|
|
57
|
+
try {
|
|
58
|
+
// Call original postgres-js function
|
|
59
|
+
const result = (await Reflect.apply(target, target, args));
|
|
60
|
+
const duration = performance.now() - start;
|
|
61
|
+
// Update entry with real duration
|
|
62
|
+
entry.duration = duration;
|
|
63
|
+
entry.isSlow = duration >= state.config.slowQueryThreshold;
|
|
64
|
+
// Set span attributes
|
|
65
|
+
s.setAttribute('db.duration_ms', Math.round(duration));
|
|
66
|
+
if (Array.isArray(result)) {
|
|
67
|
+
s.setAttribute('db.rows_affected', result.length);
|
|
68
|
+
}
|
|
69
|
+
if (entry.isSlow) {
|
|
70
|
+
s.setAttribute('db.slow_query', true);
|
|
71
|
+
}
|
|
72
|
+
s.setStatus('ok');
|
|
73
|
+
// Call user callback with complete entry
|
|
74
|
+
state.config.onQuery(entry);
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
const duration = performance.now() - start;
|
|
79
|
+
entry.duration = duration;
|
|
80
|
+
s.setAttribute('db.duration_ms', Math.round(duration));
|
|
81
|
+
s.setAttribute('db.error', true);
|
|
82
|
+
s.setStatus('error', error instanceof Error ? error.message : String(error));
|
|
83
|
+
// Still call callback on error
|
|
84
|
+
state.config.onQuery(entry);
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Execute an instrumented unsafe query
|
|
91
|
+
*/
|
|
92
|
+
async function instrumentedUnsafe(unsafeFn, query, params, state) {
|
|
93
|
+
const entry = createQueryLogEntry(query, params ?? [], 0, state.config);
|
|
94
|
+
const spanName = `db.query.unsafe ${entry.operation}${entry.table ? ` ${entry.table}` : ''}`;
|
|
95
|
+
return span(spanName, async (s) => {
|
|
96
|
+
s.setAttribute('db.system', state.dbSystem);
|
|
97
|
+
s.setAttribute('db.operation', entry.operation);
|
|
98
|
+
s.setAttribute('db.statement', entry.query);
|
|
99
|
+
s.setAttribute('db.query_type', 'unsafe');
|
|
100
|
+
if (entry.table)
|
|
101
|
+
s.setAttribute('db.sql.table', entry.table);
|
|
102
|
+
if (state.dbName)
|
|
103
|
+
s.setAttribute('db.name', state.dbName);
|
|
104
|
+
const start = performance.now();
|
|
105
|
+
try {
|
|
106
|
+
const result = await unsafeFn(query, params);
|
|
107
|
+
const duration = performance.now() - start;
|
|
108
|
+
entry.duration = duration;
|
|
109
|
+
entry.isSlow = duration >= state.config.slowQueryThreshold;
|
|
110
|
+
s.setAttribute('db.duration_ms', Math.round(duration));
|
|
111
|
+
if (Array.isArray(result)) {
|
|
112
|
+
s.setAttribute('db.rows_affected', result.length);
|
|
113
|
+
}
|
|
114
|
+
if (entry.isSlow) {
|
|
115
|
+
s.setAttribute('db.slow_query', true);
|
|
116
|
+
}
|
|
117
|
+
s.setStatus('ok');
|
|
118
|
+
state.config.onQuery(entry);
|
|
119
|
+
return result;
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
const duration = performance.now() - start;
|
|
123
|
+
entry.duration = duration;
|
|
124
|
+
s.setAttribute('db.duration_ms', Math.round(duration));
|
|
125
|
+
s.setAttribute('db.error', true);
|
|
126
|
+
s.setStatus('error', error instanceof Error ? error.message : String(error));
|
|
127
|
+
state.config.onQuery(entry);
|
|
128
|
+
throw error;
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Create an instrumented begin (transaction) wrapper
|
|
134
|
+
*/
|
|
135
|
+
function createInstrumentedBegin(originalBegin, state) {
|
|
136
|
+
return async (fn) => {
|
|
137
|
+
return span('db.transaction', async (s) => {
|
|
138
|
+
s.setAttribute('db.system', state.dbSystem);
|
|
139
|
+
s.setAttribute('db.operation', 'TRANSACTION');
|
|
140
|
+
if (state.dbName)
|
|
141
|
+
s.setAttribute('db.name', state.dbName);
|
|
142
|
+
const start = performance.now();
|
|
143
|
+
try {
|
|
144
|
+
// Wrap the inner sql client passed to the transaction
|
|
145
|
+
const result = await originalBegin(async (txSql) => {
|
|
146
|
+
// Create instrumented version for transaction queries
|
|
147
|
+
const instrumentedTxSql = instrumentPostgres(txSql, {
|
|
148
|
+
...state.config,
|
|
149
|
+
dbSystem: state.dbSystem,
|
|
150
|
+
dbName: state.dbName,
|
|
151
|
+
});
|
|
152
|
+
return fn(instrumentedTxSql);
|
|
153
|
+
});
|
|
154
|
+
const duration = performance.now() - start;
|
|
155
|
+
s.setAttribute('db.duration_ms', Math.round(duration));
|
|
156
|
+
s.setStatus('ok');
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
const duration = performance.now() - start;
|
|
161
|
+
s.setAttribute('db.duration_ms', Math.round(duration));
|
|
162
|
+
s.setAttribute('db.error', true);
|
|
163
|
+
s.setAttribute('db.transaction_rollback', true);
|
|
164
|
+
s.setStatus('error', error instanceof Error ? error.message : String(error));
|
|
165
|
+
throw error;
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Instrument a postgres-js client for automatic span creation and metrics
|
|
172
|
+
*
|
|
173
|
+
* This function wraps the postgres-js client to automatically:
|
|
174
|
+
* - Create OTLP spans for each query
|
|
175
|
+
* - Measure precise query duration
|
|
176
|
+
* - Detect slow queries
|
|
177
|
+
* - Call the onQuery callback for external metrics
|
|
178
|
+
*
|
|
179
|
+
* @example Basic usage
|
|
180
|
+
* ```typescript
|
|
181
|
+
* import postgres from 'postgres'
|
|
182
|
+
* import { instrumentPostgres } from '@vestig/next/db'
|
|
183
|
+
*
|
|
184
|
+
* const sql = instrumentPostgres(postgres(DATABASE_URL))
|
|
185
|
+
*
|
|
186
|
+
* // All queries now create spans automatically
|
|
187
|
+
* const users = await sql`SELECT * FROM users`
|
|
188
|
+
* ```
|
|
189
|
+
*
|
|
190
|
+
* @example With Drizzle ORM
|
|
191
|
+
* ```typescript
|
|
192
|
+
* import postgres from 'postgres'
|
|
193
|
+
* import { instrumentPostgres } from '@vestig/next/db'
|
|
194
|
+
* import { drizzle } from 'drizzle-orm/postgres-js'
|
|
195
|
+
*
|
|
196
|
+
* const client = instrumentPostgres(postgres(DATABASE_URL), {
|
|
197
|
+
* slowQueryThreshold: 100,
|
|
198
|
+
* onQuery: (entry) => {
|
|
199
|
+
* // Send to your metrics system for noisy neighbor detection
|
|
200
|
+
* if (entry.isSlow) {
|
|
201
|
+
* metrics.recordSlowQuery({
|
|
202
|
+
* table: entry.table,
|
|
203
|
+
* operation: entry.operation,
|
|
204
|
+
* duration: entry.duration,
|
|
205
|
+
* })
|
|
206
|
+
* }
|
|
207
|
+
* }
|
|
208
|
+
* })
|
|
209
|
+
*
|
|
210
|
+
* export const db = drizzle(client)
|
|
211
|
+
* ```
|
|
212
|
+
*
|
|
213
|
+
* @example With custom database name
|
|
214
|
+
* ```typescript
|
|
215
|
+
* const sql = instrumentPostgres(postgres(DATABASE_URL), {
|
|
216
|
+
* dbName: 'myapp_production',
|
|
217
|
+
* dbSystem: 'postgresql',
|
|
218
|
+
* })
|
|
219
|
+
* ```
|
|
220
|
+
*
|
|
221
|
+
* @param client - The postgres-js client instance
|
|
222
|
+
* @param options - Configuration options
|
|
223
|
+
* @returns Instrumented postgres-js client with the same interface
|
|
224
|
+
*/
|
|
225
|
+
export function instrumentPostgres(client, options) {
|
|
226
|
+
// Merge with global config from registerVestig() if available
|
|
227
|
+
const globalConfig = getDatabaseConfig();
|
|
228
|
+
const mergedOptions = { ...globalConfig, ...options };
|
|
229
|
+
const config = mergeConfig(mergedOptions);
|
|
230
|
+
const dbSystem = mergedOptions?.dbSystem ?? 'postgresql';
|
|
231
|
+
const dbName = mergedOptions?.dbName;
|
|
232
|
+
const state = {
|
|
233
|
+
config,
|
|
234
|
+
dbSystem,
|
|
235
|
+
dbName,
|
|
236
|
+
};
|
|
237
|
+
// Create a proxy that intercepts both template literal calls and method access
|
|
238
|
+
return new Proxy(client, {
|
|
239
|
+
// Handle template literal calls: sql`SELECT * FROM users`
|
|
240
|
+
apply(target, _thisArg, args) {
|
|
241
|
+
return instrumentedQuery(target, args, state);
|
|
242
|
+
},
|
|
243
|
+
// Handle method access: sql.unsafe(), sql.begin(), etc.
|
|
244
|
+
get(target, prop, receiver) {
|
|
245
|
+
const value = Reflect.get(target, prop, receiver);
|
|
246
|
+
// Wrap special postgres-js methods
|
|
247
|
+
if (prop === 'unsafe' && typeof value === 'function') {
|
|
248
|
+
return (query, params) => {
|
|
249
|
+
return instrumentedUnsafe(value.bind(target), query, params, state);
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
if (prop === 'begin' && typeof value === 'function') {
|
|
253
|
+
return createInstrumentedBegin(value.bind(target), state);
|
|
254
|
+
}
|
|
255
|
+
// For file() - wrap with basic span
|
|
256
|
+
if (prop === 'file' && typeof value === 'function') {
|
|
257
|
+
return async (path, fileOptions) => {
|
|
258
|
+
return span(`db.file ${path}`, async (s) => {
|
|
259
|
+
s.setAttribute('db.system', state.dbSystem);
|
|
260
|
+
s.setAttribute('db.operation', 'FILE');
|
|
261
|
+
s.setAttribute('db.file_path', path);
|
|
262
|
+
if (state.dbName)
|
|
263
|
+
s.setAttribute('db.name', state.dbName);
|
|
264
|
+
const start = performance.now();
|
|
265
|
+
try {
|
|
266
|
+
const result = await value.call(target, path, fileOptions);
|
|
267
|
+
const duration = performance.now() - start;
|
|
268
|
+
s.setAttribute('db.duration_ms', Math.round(duration));
|
|
269
|
+
s.setStatus('ok');
|
|
270
|
+
return result;
|
|
271
|
+
}
|
|
272
|
+
catch (error) {
|
|
273
|
+
const duration = performance.now() - start;
|
|
274
|
+
s.setAttribute('db.duration_ms', Math.round(duration));
|
|
275
|
+
s.setAttribute('db.error', true);
|
|
276
|
+
s.setStatus('error', error instanceof Error ? error.message : String(error));
|
|
277
|
+
throw error;
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
// Pass through all other properties unchanged
|
|
283
|
+
return value;
|
|
284
|
+
},
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Check if a postgres-js client is instrumented
|
|
289
|
+
*
|
|
290
|
+
* Note: This is a best-effort check. Due to Proxy transparency,
|
|
291
|
+
* it's not always possible to detect instrumentation.
|
|
292
|
+
*/
|
|
293
|
+
export function isPostgresInstrumented(client) {
|
|
294
|
+
// Proxy objects don't have a reliable way to detect them
|
|
295
|
+
// This is mainly for documentation purposes
|
|
296
|
+
return typeof client === 'function' && 'unsafe' in client;
|
|
297
|
+
}
|
|
298
|
+
//# sourceMappingURL=postgres.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres.js","sourceRoot":"","sources":["../../src/db/postgres.ts"],"names":[],"mappings":"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"}
|
package/dist/db/types.d.ts
CHANGED
|
@@ -99,4 +99,40 @@ export declare const SENSITIVE_PATTERNS: RegExp[];
|
|
|
99
99
|
* Check if a parameter name is sensitive
|
|
100
100
|
*/
|
|
101
101
|
export declare function isSensitiveParam(name: string): boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Configuration for database auto-instrumentation
|
|
104
|
+
*
|
|
105
|
+
* Used with registerVestig() to configure database instrumentation
|
|
106
|
+
* from the instrumentation.ts file.
|
|
107
|
+
*/
|
|
108
|
+
export interface DatabaseInstrumentConfig {
|
|
109
|
+
/**
|
|
110
|
+
* Slow query threshold in milliseconds
|
|
111
|
+
* Queries exceeding this will be marked as slow
|
|
112
|
+
* @default 100
|
|
113
|
+
*/
|
|
114
|
+
slowQueryThreshold?: number;
|
|
115
|
+
/**
|
|
116
|
+
* Log level for query logging
|
|
117
|
+
* - 'all': Log all queries
|
|
118
|
+
* - 'slow': Only log slow queries
|
|
119
|
+
* - 'none': Disable logging (spans still created)
|
|
120
|
+
* @default 'slow' in production, 'all' in development
|
|
121
|
+
*/
|
|
122
|
+
logLevel?: 'all' | 'slow' | 'none';
|
|
123
|
+
/**
|
|
124
|
+
* Callback when a query completes
|
|
125
|
+
* Use this for external metrics (e.g., noisy neighbor detection)
|
|
126
|
+
*/
|
|
127
|
+
onQuery?: (entry: QueryLogEntry) => void;
|
|
128
|
+
/**
|
|
129
|
+
* Database system for OTLP semantic attributes
|
|
130
|
+
* @default 'postgresql'
|
|
131
|
+
*/
|
|
132
|
+
dbSystem?: string;
|
|
133
|
+
/**
|
|
134
|
+
* Database name for OTLP attributes
|
|
135
|
+
*/
|
|
136
|
+
dbName?: string;
|
|
137
|
+
}
|
|
102
138
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/db/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/db/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,sBAAsB;IACtB,EAAE,EAAE,MAAM,CAAA;IACV,oBAAoB;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,mCAAmC;IACnC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAA;IAClB,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAA;IAChB,kDAAkD;IAClD,MAAM,EAAE,OAAO,CAAA;IACf,8BAA8B;IAC9B,SAAS,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAA;IAC9D,qCAAqC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,mCAAmC;IACnC,OAAO,CAAC,EAAE;QACT,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,OAAO,CAAC,EAAE,MAAM,CAAA;KAChB,CAAA;CACD;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC9B;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B;;;OAGG;IACH,QAAQ,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAAA;IAClC;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;CACxC;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC5B,SAAS,EAAE,IAAI,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC9B,SAAS,EAAE,IAAI,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;CACd,CAAA;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;CAChD;AAED;;GAEG;AACH,eAAO,MAAM,kBAAkB,UAU9B,CAAA;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEtD"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/db/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,sBAAsB;IACtB,EAAE,EAAE,MAAM,CAAA;IACV,oBAAoB;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,mCAAmC;IACnC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAA;IAClB,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAA;IAChB,kDAAkD;IAClD,MAAM,EAAE,OAAO,CAAA;IACf,8BAA8B;IAC9B,SAAS,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAA;IAC9D,qCAAqC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,mCAAmC;IACnC,OAAO,CAAC,EAAE;QACT,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,OAAO,CAAC,EAAE,MAAM,CAAA;KAChB,CAAA;CACD;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC9B;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B;;;OAGG;IACH,QAAQ,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAAA;IAClC;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;CACxC;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC5B,SAAS,EAAE,IAAI,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC9B,SAAS,EAAE,IAAI,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;CACd,CAAA;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;CAChD;AAED;;GAEG;AACH,eAAO,MAAM,kBAAkB,UAU9B,CAAA;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED;;;;;GAKG;AACH,MAAM,WAAW,wBAAwB;IACxC;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAE3B;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAAA;IAElC;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;IAExC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IAEjB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;CACf"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Next.js Instrumentation for vestig
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```typescript
|
|
6
|
+
* // instrumentation.ts
|
|
7
|
+
* import { registerVestig } from '@vestig/next/instrumentation'
|
|
8
|
+
*
|
|
9
|
+
* export function register() {
|
|
10
|
+
* registerVestig({
|
|
11
|
+
* serviceName: 'my-app',
|
|
12
|
+
* otlp: {
|
|
13
|
+
* endpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
|
|
14
|
+
* },
|
|
15
|
+
* autoInstrument: {
|
|
16
|
+
* fetch: true,
|
|
17
|
+
* },
|
|
18
|
+
* })
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export { registerVestig } from './register';
|
|
23
|
+
export type { RegisterVestigOptions, RegisterVestigResult, OTLPConfig, AutoInstrumentConfig, } from './types';
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/instrumentation/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAC3C,YAAY,EACX,qBAAqB,EACrB,oBAAoB,EACpB,UAAU,EACV,oBAAoB,GACpB,MAAM,SAAS,CAAA"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Next.js Instrumentation for vestig
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```typescript
|
|
6
|
+
* // instrumentation.ts
|
|
7
|
+
* import { registerVestig } from '@vestig/next/instrumentation'
|
|
8
|
+
*
|
|
9
|
+
* export function register() {
|
|
10
|
+
* registerVestig({
|
|
11
|
+
* serviceName: 'my-app',
|
|
12
|
+
* otlp: {
|
|
13
|
+
* endpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
|
|
14
|
+
* },
|
|
15
|
+
* autoInstrument: {
|
|
16
|
+
* fetch: true,
|
|
17
|
+
* },
|
|
18
|
+
* })
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export { registerVestig } from './register';
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/instrumentation/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified vestig setup for Next.js instrumentation
|
|
3
|
+
*
|
|
4
|
+
* Call in your instrumentation.ts file for complete auto-instrumentation.
|
|
5
|
+
*/
|
|
6
|
+
import type { DatabaseInstrumentConfig } from '../db/types';
|
|
7
|
+
import type { RegisterVestigOptions, RegisterVestigResult } from './types';
|
|
8
|
+
/**
|
|
9
|
+
* Get the global database configuration
|
|
10
|
+
*
|
|
11
|
+
* Used internally by instrumentPostgres() to get default config
|
|
12
|
+
*/
|
|
13
|
+
export declare function getDatabaseConfig(): DatabaseInstrumentConfig | null;
|
|
14
|
+
/**
|
|
15
|
+
* Set the global database configuration
|
|
16
|
+
*
|
|
17
|
+
* Called by registerVestig() when database config is provided
|
|
18
|
+
*/
|
|
19
|
+
export declare function setDatabaseConfig(config: DatabaseInstrumentConfig | null): void;
|
|
20
|
+
/**
|
|
21
|
+
* Register vestig for Next.js instrumentation
|
|
22
|
+
*
|
|
23
|
+
* Call this in your `instrumentation.ts` file to enable:
|
|
24
|
+
* - OTLP trace export (Vercel, Honeycomb, Jaeger, etc.)
|
|
25
|
+
* - Automatic fetch() instrumentation
|
|
26
|
+
* - Console error capture (optional)
|
|
27
|
+
*
|
|
28
|
+
* @example Basic usage
|
|
29
|
+
* ```typescript
|
|
30
|
+
* // instrumentation.ts
|
|
31
|
+
* import { registerVestig } from '@vestig/next/instrumentation'
|
|
32
|
+
*
|
|
33
|
+
* export function register() {
|
|
34
|
+
* registerVestig({
|
|
35
|
+
* serviceName: 'my-app',
|
|
36
|
+
* })
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* @example With OTLP export
|
|
41
|
+
* ```typescript
|
|
42
|
+
* // instrumentation.ts
|
|
43
|
+
* import { registerVestig } from '@vestig/next/instrumentation'
|
|
44
|
+
*
|
|
45
|
+
* export function register() {
|
|
46
|
+
* registerVestig({
|
|
47
|
+
* serviceName: 'my-app',
|
|
48
|
+
* otlp: {
|
|
49
|
+
* endpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
|
|
50
|
+
* headers: {
|
|
51
|
+
* 'Authorization': `Bearer ${process.env.OTEL_AUTH_TOKEN}`,
|
|
52
|
+
* },
|
|
53
|
+
* },
|
|
54
|
+
* })
|
|
55
|
+
* }
|
|
56
|
+
* ```
|
|
57
|
+
*
|
|
58
|
+
* @example Full configuration
|
|
59
|
+
* ```typescript
|
|
60
|
+
* // instrumentation.ts
|
|
61
|
+
* import { registerVestig } from '@vestig/next/instrumentation'
|
|
62
|
+
*
|
|
63
|
+
* export function register() {
|
|
64
|
+
* registerVestig({
|
|
65
|
+
* serviceName: 'my-app',
|
|
66
|
+
* otlp: {
|
|
67
|
+
* endpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
|
|
68
|
+
* serviceVersion: '1.0.0',
|
|
69
|
+
* environment: process.env.VERCEL_ENV,
|
|
70
|
+
* },
|
|
71
|
+
* autoInstrument: {
|
|
72
|
+
* fetch: {
|
|
73
|
+
* captureHeaders: ['content-type', 'x-request-id'],
|
|
74
|
+
* ignoreUrls: ['/health', /^\/_next/],
|
|
75
|
+
* },
|
|
76
|
+
* console: true,
|
|
77
|
+
* },
|
|
78
|
+
* debug: process.env.NODE_ENV === 'development',
|
|
79
|
+
* })
|
|
80
|
+
* }
|
|
81
|
+
* ```
|
|
82
|
+
*
|
|
83
|
+
* @example Environment variables
|
|
84
|
+
* ```bash
|
|
85
|
+
* # These are automatically read if not specified in config:
|
|
86
|
+
* OTEL_EXPORTER_OTLP_ENDPOINT=https://otel.vercel.com/v1/traces
|
|
87
|
+
* OTEL_EXPORTER_OTLP_HEADERS=Authorization=Bearer token
|
|
88
|
+
* VERCEL_ENV=production
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
export declare function registerVestig(options: RegisterVestigOptions): RegisterVestigResult;
|
|
92
|
+
//# sourceMappingURL=register.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../src/instrumentation/register.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAA;AAC3D,OAAO,KAAK,EAGX,qBAAqB,EACrB,oBAAoB,EACpB,MAAM,SAAS,CAAA;AAUhB;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,wBAAwB,GAAG,IAAI,CAEnE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,wBAAwB,GAAG,IAAI,GAAG,IAAI,CAE/E;AAkMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,oBAAoB,CAsDnF"}
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified vestig setup for Next.js instrumentation
|
|
3
|
+
*
|
|
4
|
+
* Call in your instrumentation.ts file for complete auto-instrumentation.
|
|
5
|
+
*/
|
|
6
|
+
import { instrumentFetch, registerSpanProcessor, shutdownSpanProcessors, } from 'vestig';
|
|
7
|
+
import { OTLPExporter } from 'vestig/otlp';
|
|
8
|
+
/**
|
|
9
|
+
* Global database configuration store
|
|
10
|
+
*
|
|
11
|
+
* This allows instrumentPostgres() to pick up the config set by registerVestig()
|
|
12
|
+
* without requiring users to pass it explicitly.
|
|
13
|
+
*/
|
|
14
|
+
let globalDatabaseConfig = null;
|
|
15
|
+
/**
|
|
16
|
+
* Get the global database configuration
|
|
17
|
+
*
|
|
18
|
+
* Used internally by instrumentPostgres() to get default config
|
|
19
|
+
*/
|
|
20
|
+
export function getDatabaseConfig() {
|
|
21
|
+
return globalDatabaseConfig;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Set the global database configuration
|
|
25
|
+
*
|
|
26
|
+
* Called by registerVestig() when database config is provided
|
|
27
|
+
*/
|
|
28
|
+
export function setDatabaseConfig(config) {
|
|
29
|
+
globalDatabaseConfig = config;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Parse OTEL headers from environment variable
|
|
33
|
+
* Format: key1=value1,key2=value2
|
|
34
|
+
*/
|
|
35
|
+
function parseOTLPHeaders(headersStr) {
|
|
36
|
+
if (!headersStr)
|
|
37
|
+
return {};
|
|
38
|
+
const headers = {};
|
|
39
|
+
const pairs = headersStr.split(',');
|
|
40
|
+
for (const pair of pairs) {
|
|
41
|
+
const [key, ...valueParts] = pair.split('=');
|
|
42
|
+
if (key && valueParts.length > 0) {
|
|
43
|
+
headers[key.trim()] = valueParts.join('=').trim();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return headers;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get environment from various sources
|
|
50
|
+
*/
|
|
51
|
+
function getEnvironment(config) {
|
|
52
|
+
return config?.environment ?? process.env.VERCEL_ENV ?? process.env.NODE_ENV ?? 'development';
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Setup OTLP export if configured
|
|
56
|
+
*/
|
|
57
|
+
function setupOTLP(serviceName, config, debug) {
|
|
58
|
+
// Get endpoint from config or environment
|
|
59
|
+
const endpoint = config?.endpoint ?? process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
|
|
60
|
+
if (!endpoint) {
|
|
61
|
+
if (debug) {
|
|
62
|
+
console.log('[vestig] OTLP not configured: no endpoint provided');
|
|
63
|
+
}
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
// Ensure endpoint has /v1/traces suffix
|
|
67
|
+
const tracesEndpoint = endpoint.endsWith('/v1/traces')
|
|
68
|
+
? endpoint
|
|
69
|
+
: `${endpoint.replace(/\/$/, '')}/v1/traces`;
|
|
70
|
+
// Get headers from config or environment
|
|
71
|
+
const headers = {
|
|
72
|
+
...parseOTLPHeaders(process.env.OTEL_EXPORTER_OTLP_HEADERS),
|
|
73
|
+
...config?.headers,
|
|
74
|
+
};
|
|
75
|
+
// Create and register exporter
|
|
76
|
+
const exporter = new OTLPExporter({
|
|
77
|
+
endpoint: tracesEndpoint,
|
|
78
|
+
serviceName,
|
|
79
|
+
serviceVersion: config?.serviceVersion,
|
|
80
|
+
environment: getEnvironment(config),
|
|
81
|
+
headers: Object.keys(headers).length > 0 ? headers : undefined,
|
|
82
|
+
resourceAttributes: config?.resourceAttributes,
|
|
83
|
+
batchSize: config?.batchSize,
|
|
84
|
+
flushInterval: config?.flushInterval,
|
|
85
|
+
});
|
|
86
|
+
registerSpanProcessor(exporter);
|
|
87
|
+
if (debug) {
|
|
88
|
+
console.log(`[vestig] OTLP enabled: ${tracesEndpoint}`);
|
|
89
|
+
}
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Setup fetch instrumentation if configured
|
|
94
|
+
*/
|
|
95
|
+
function setupFetch(config, debug) {
|
|
96
|
+
// Default to enabled unless explicitly disabled
|
|
97
|
+
const fetchConfig = config?.fetch;
|
|
98
|
+
if (fetchConfig === false) {
|
|
99
|
+
if (debug) {
|
|
100
|
+
console.log('[vestig] Fetch instrumentation disabled');
|
|
101
|
+
}
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
// Determine options
|
|
105
|
+
const options = typeof fetchConfig === 'object'
|
|
106
|
+
? fetchConfig
|
|
107
|
+
: {
|
|
108
|
+
// Default options for Next.js
|
|
109
|
+
ignoreUrls: [
|
|
110
|
+
// Next.js internal routes
|
|
111
|
+
/^\/_next/,
|
|
112
|
+
// Health checks
|
|
113
|
+
'/health',
|
|
114
|
+
'/healthz',
|
|
115
|
+
'/ready',
|
|
116
|
+
// Metrics
|
|
117
|
+
'/metrics',
|
|
118
|
+
// Favicon
|
|
119
|
+
'/favicon.ico',
|
|
120
|
+
],
|
|
121
|
+
};
|
|
122
|
+
instrumentFetch(options);
|
|
123
|
+
if (debug) {
|
|
124
|
+
console.log('[vestig] Fetch instrumentation enabled');
|
|
125
|
+
}
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Setup database configuration if provided
|
|
130
|
+
*
|
|
131
|
+
* This stores the config globally so instrumentPostgres() can access it
|
|
132
|
+
*/
|
|
133
|
+
function setupDatabase(config, debug) {
|
|
134
|
+
const dbConfig = config?.database;
|
|
135
|
+
if (!dbConfig) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
// Store config globally for instrumentPostgres() to use
|
|
139
|
+
setDatabaseConfig(dbConfig);
|
|
140
|
+
if (debug) {
|
|
141
|
+
console.log('[vestig] Database instrumentation configured');
|
|
142
|
+
if (dbConfig.slowQueryThreshold) {
|
|
143
|
+
console.log(`[vestig] Slow query threshold: ${dbConfig.slowQueryThreshold}ms`);
|
|
144
|
+
}
|
|
145
|
+
if (dbConfig.onQuery) {
|
|
146
|
+
console.log('[vestig] onQuery callback registered');
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Setup console capture if configured
|
|
153
|
+
*/
|
|
154
|
+
function setupConsole(config, debug) {
|
|
155
|
+
if (!config?.console) {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
// Store original console.error
|
|
159
|
+
const originalError = console.error;
|
|
160
|
+
// Wrap console.error to create spans
|
|
161
|
+
console.error = (...args) => {
|
|
162
|
+
// Call original first
|
|
163
|
+
originalError.apply(console, args);
|
|
164
|
+
// Create span for the error (non-blocking)
|
|
165
|
+
// This is a fire-and-forget operation
|
|
166
|
+
try {
|
|
167
|
+
const message = args
|
|
168
|
+
.map((arg) => (typeof arg === 'string' ? arg : JSON.stringify(arg)))
|
|
169
|
+
.join(' ');
|
|
170
|
+
// Import dynamically to avoid circular deps
|
|
171
|
+
import('vestig').then(({ spanSync }) => {
|
|
172
|
+
spanSync('console.error', (s) => {
|
|
173
|
+
s.setAttribute('message', message.slice(0, 1000));
|
|
174
|
+
s.setStatus('error', 'console.error');
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
// Ignore errors in instrumentation
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
if (debug) {
|
|
183
|
+
console.log('[vestig] Console capture enabled');
|
|
184
|
+
}
|
|
185
|
+
// Return restore function
|
|
186
|
+
return () => {
|
|
187
|
+
console.error = originalError;
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Register vestig for Next.js instrumentation
|
|
192
|
+
*
|
|
193
|
+
* Call this in your `instrumentation.ts` file to enable:
|
|
194
|
+
* - OTLP trace export (Vercel, Honeycomb, Jaeger, etc.)
|
|
195
|
+
* - Automatic fetch() instrumentation
|
|
196
|
+
* - Console error capture (optional)
|
|
197
|
+
*
|
|
198
|
+
* @example Basic usage
|
|
199
|
+
* ```typescript
|
|
200
|
+
* // instrumentation.ts
|
|
201
|
+
* import { registerVestig } from '@vestig/next/instrumentation'
|
|
202
|
+
*
|
|
203
|
+
* export function register() {
|
|
204
|
+
* registerVestig({
|
|
205
|
+
* serviceName: 'my-app',
|
|
206
|
+
* })
|
|
207
|
+
* }
|
|
208
|
+
* ```
|
|
209
|
+
*
|
|
210
|
+
* @example With OTLP export
|
|
211
|
+
* ```typescript
|
|
212
|
+
* // instrumentation.ts
|
|
213
|
+
* import { registerVestig } from '@vestig/next/instrumentation'
|
|
214
|
+
*
|
|
215
|
+
* export function register() {
|
|
216
|
+
* registerVestig({
|
|
217
|
+
* serviceName: 'my-app',
|
|
218
|
+
* otlp: {
|
|
219
|
+
* endpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
|
|
220
|
+
* headers: {
|
|
221
|
+
* 'Authorization': `Bearer ${process.env.OTEL_AUTH_TOKEN}`,
|
|
222
|
+
* },
|
|
223
|
+
* },
|
|
224
|
+
* })
|
|
225
|
+
* }
|
|
226
|
+
* ```
|
|
227
|
+
*
|
|
228
|
+
* @example Full configuration
|
|
229
|
+
* ```typescript
|
|
230
|
+
* // instrumentation.ts
|
|
231
|
+
* import { registerVestig } from '@vestig/next/instrumentation'
|
|
232
|
+
*
|
|
233
|
+
* export function register() {
|
|
234
|
+
* registerVestig({
|
|
235
|
+
* serviceName: 'my-app',
|
|
236
|
+
* otlp: {
|
|
237
|
+
* endpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
|
|
238
|
+
* serviceVersion: '1.0.0',
|
|
239
|
+
* environment: process.env.VERCEL_ENV,
|
|
240
|
+
* },
|
|
241
|
+
* autoInstrument: {
|
|
242
|
+
* fetch: {
|
|
243
|
+
* captureHeaders: ['content-type', 'x-request-id'],
|
|
244
|
+
* ignoreUrls: ['/health', /^\/_next/],
|
|
245
|
+
* },
|
|
246
|
+
* console: true,
|
|
247
|
+
* },
|
|
248
|
+
* debug: process.env.NODE_ENV === 'development',
|
|
249
|
+
* })
|
|
250
|
+
* }
|
|
251
|
+
* ```
|
|
252
|
+
*
|
|
253
|
+
* @example Environment variables
|
|
254
|
+
* ```bash
|
|
255
|
+
* # These are automatically read if not specified in config:
|
|
256
|
+
* OTEL_EXPORTER_OTLP_ENDPOINT=https://otel.vercel.com/v1/traces
|
|
257
|
+
* OTEL_EXPORTER_OTLP_HEADERS=Authorization=Bearer token
|
|
258
|
+
* VERCEL_ENV=production
|
|
259
|
+
* ```
|
|
260
|
+
*/
|
|
261
|
+
export function registerVestig(options) {
|
|
262
|
+
const { serviceName, otlp, autoInstrument, debug = false } = options;
|
|
263
|
+
if (debug) {
|
|
264
|
+
console.log(`[vestig] Initializing for ${serviceName}...`);
|
|
265
|
+
}
|
|
266
|
+
// Track what was enabled
|
|
267
|
+
let otlpEnabled = false;
|
|
268
|
+
let fetchInstrumented = false;
|
|
269
|
+
let databaseConfigured = false;
|
|
270
|
+
let consoleRestore = null;
|
|
271
|
+
// Setup OTLP export
|
|
272
|
+
otlpEnabled = setupOTLP(serviceName, otlp, debug);
|
|
273
|
+
// Setup fetch instrumentation
|
|
274
|
+
fetchInstrumented = setupFetch(autoInstrument, debug);
|
|
275
|
+
// Setup database configuration
|
|
276
|
+
databaseConfigured = setupDatabase(autoInstrument, debug);
|
|
277
|
+
// Setup console capture
|
|
278
|
+
consoleRestore = setupConsole(autoInstrument, debug);
|
|
279
|
+
if (debug) {
|
|
280
|
+
console.log('[vestig] Initialization complete');
|
|
281
|
+
}
|
|
282
|
+
// Return result with shutdown function
|
|
283
|
+
return {
|
|
284
|
+
otlpEnabled,
|
|
285
|
+
fetchInstrumented,
|
|
286
|
+
consoleInstrumented: consoleRestore !== null,
|
|
287
|
+
databaseConfigured,
|
|
288
|
+
shutdown: async () => {
|
|
289
|
+
// Restore console
|
|
290
|
+
if (consoleRestore) {
|
|
291
|
+
consoleRestore();
|
|
292
|
+
}
|
|
293
|
+
// Clear database config
|
|
294
|
+
if (databaseConfigured) {
|
|
295
|
+
setDatabaseConfig(null);
|
|
296
|
+
}
|
|
297
|
+
// Shutdown span processors (flushes pending spans)
|
|
298
|
+
await shutdownSpanProcessors();
|
|
299
|
+
if (debug) {
|
|
300
|
+
console.log('[vestig] Shutdown complete');
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
//# sourceMappingURL=register.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.js","sourceRoot":"","sources":["../../src/instrumentation/register.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for registerVestig
|
|
3
|
+
*/
|
|
4
|
+
import type { InstrumentFetchOptions, TailSamplingConfig } from 'vestig';
|
|
5
|
+
import type { DatabaseInstrumentConfig } from '../db/types';
|
|
6
|
+
/**
|
|
7
|
+
* OTLP configuration options
|
|
8
|
+
*/
|
|
9
|
+
export interface OTLPConfig {
|
|
10
|
+
/**
|
|
11
|
+
* OTLP endpoint URL for traces
|
|
12
|
+
* Falls back to OTEL_EXPORTER_OTLP_ENDPOINT env var
|
|
13
|
+
* @example 'https://otel.vercel.com/v1/traces'
|
|
14
|
+
*/
|
|
15
|
+
endpoint?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Custom headers for authentication
|
|
18
|
+
* Falls back to OTEL_EXPORTER_OTLP_HEADERS env var (comma-separated key=value pairs)
|
|
19
|
+
* @example { 'Authorization': 'Bearer token' }
|
|
20
|
+
*/
|
|
21
|
+
headers?: Record<string, string>;
|
|
22
|
+
/**
|
|
23
|
+
* Service version (optional)
|
|
24
|
+
* @example '1.0.0'
|
|
25
|
+
*/
|
|
26
|
+
serviceVersion?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Deployment environment
|
|
29
|
+
* Falls back to VERCEL_ENV, NODE_ENV
|
|
30
|
+
* @example 'production', 'development'
|
|
31
|
+
*/
|
|
32
|
+
environment?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Additional resource attributes
|
|
35
|
+
* @example { 'cloud.region': 'us-east-1' }
|
|
36
|
+
*/
|
|
37
|
+
resourceAttributes?: Record<string, unknown>;
|
|
38
|
+
/**
|
|
39
|
+
* Batch size for span export
|
|
40
|
+
* @default 100
|
|
41
|
+
*/
|
|
42
|
+
batchSize?: number;
|
|
43
|
+
/**
|
|
44
|
+
* Flush interval in ms
|
|
45
|
+
* @default 5000
|
|
46
|
+
*/
|
|
47
|
+
flushInterval?: number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Auto-instrumentation options
|
|
51
|
+
*/
|
|
52
|
+
export interface AutoInstrumentConfig {
|
|
53
|
+
/**
|
|
54
|
+
* Auto-instrument all fetch() calls
|
|
55
|
+
* @default true
|
|
56
|
+
*/
|
|
57
|
+
fetch?: boolean | InstrumentFetchOptions;
|
|
58
|
+
/**
|
|
59
|
+
* Capture console.error as spans
|
|
60
|
+
* @default false
|
|
61
|
+
*/
|
|
62
|
+
console?: boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Database instrumentation configuration
|
|
65
|
+
*
|
|
66
|
+
* When provided, this configuration is stored globally and can be
|
|
67
|
+
* accessed by instrumentPostgres() for consistent settings.
|
|
68
|
+
*
|
|
69
|
+
* Note: You still need to wrap your postgres client with instrumentPostgres()
|
|
70
|
+
* in your database setup file. This config just provides the default settings.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* // instrumentation.ts
|
|
75
|
+
* registerVestig({
|
|
76
|
+
* autoInstrument: {
|
|
77
|
+
* database: {
|
|
78
|
+
* slowQueryThreshold: 100,
|
|
79
|
+
* onQuery: (entry) => {
|
|
80
|
+
* if (entry.isSlow) sendToMetrics(entry)
|
|
81
|
+
* }
|
|
82
|
+
* }
|
|
83
|
+
* }
|
|
84
|
+
* })
|
|
85
|
+
*
|
|
86
|
+
* // lib/db.ts
|
|
87
|
+
* const client = instrumentPostgres(postgres(DATABASE_URL))
|
|
88
|
+
* // ^ Will use the config from registerVestig()
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
database?: DatabaseInstrumentConfig;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Options for registerVestig
|
|
95
|
+
*/
|
|
96
|
+
export interface RegisterVestigOptions {
|
|
97
|
+
/**
|
|
98
|
+
* Service name (required)
|
|
99
|
+
* Used in OTLP resource attributes
|
|
100
|
+
*/
|
|
101
|
+
serviceName: string;
|
|
102
|
+
/**
|
|
103
|
+
* OTLP configuration
|
|
104
|
+
* If provided, enables automatic span export
|
|
105
|
+
*/
|
|
106
|
+
otlp?: OTLPConfig;
|
|
107
|
+
/**
|
|
108
|
+
* Auto-instrumentation options
|
|
109
|
+
*/
|
|
110
|
+
autoInstrument?: AutoInstrumentConfig;
|
|
111
|
+
/**
|
|
112
|
+
* Tail sampling configuration for wide events
|
|
113
|
+
*/
|
|
114
|
+
tailSampling?: TailSamplingConfig;
|
|
115
|
+
/**
|
|
116
|
+
* Enable debug logging
|
|
117
|
+
* @default false
|
|
118
|
+
*/
|
|
119
|
+
debug?: boolean;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Result of registerVestig
|
|
123
|
+
*/
|
|
124
|
+
export interface RegisterVestigResult {
|
|
125
|
+
/**
|
|
126
|
+
* Whether OTLP export was enabled
|
|
127
|
+
*/
|
|
128
|
+
otlpEnabled: boolean;
|
|
129
|
+
/**
|
|
130
|
+
* Whether fetch was instrumented
|
|
131
|
+
*/
|
|
132
|
+
fetchInstrumented: boolean;
|
|
133
|
+
/**
|
|
134
|
+
* Whether console capture was enabled
|
|
135
|
+
*/
|
|
136
|
+
consoleInstrumented: boolean;
|
|
137
|
+
/**
|
|
138
|
+
* Whether database instrumentation config was set
|
|
139
|
+
* Note: You still need to use instrumentPostgres() in your db setup
|
|
140
|
+
*/
|
|
141
|
+
databaseConfigured: boolean;
|
|
142
|
+
/**
|
|
143
|
+
* Shutdown function to cleanup resources
|
|
144
|
+
*/
|
|
145
|
+
shutdown: () => Promise<void>;
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/instrumentation/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAA;AACxE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAA;AAE3D;;GAEG;AACH,MAAM,WAAW,UAAU;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IAEjB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAEhC;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IAEvB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IAEpB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAE5C;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAElB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACpC;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,sBAAsB,CAAA;IAExC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IAEjB;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,QAAQ,CAAC,EAAE,wBAAwB,CAAA;CACnC;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACrC;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAA;IAEnB;;;OAGG;IACH,IAAI,CAAC,EAAE,UAAU,CAAA;IAEjB;;OAEG;IACH,cAAc,CAAC,EAAE,oBAAoB,CAAA;IAErC;;OAEG;IACH,YAAY,CAAC,EAAE,kBAAkB,CAAA;IAEjC;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;CACf;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACpC;;OAEG;IACH,WAAW,EAAE,OAAO,CAAA;IAEpB;;OAEG;IACH,iBAAiB,EAAE,OAAO,CAAA;IAE1B;;OAEG;IACH,mBAAmB,EAAE,OAAO,CAAA;IAE5B;;;OAGG;IACH,kBAAkB,EAAE,OAAO,CAAA;IAE3B;;OAEG;IACH,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/instrumentation/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vestig/next",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"description": "First-class Next.js 15+ integration for vestig logging library. Zero boilerplate, automatic request correlation, full type safety.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -49,6 +49,10 @@
|
|
|
49
49
|
"./wide-events": {
|
|
50
50
|
"types": "./dist/wide-events/index.d.ts",
|
|
51
51
|
"import": "./dist/wide-events/index.js"
|
|
52
|
+
},
|
|
53
|
+
"./instrumentation": {
|
|
54
|
+
"types": "./dist/instrumentation/index.d.ts",
|
|
55
|
+
"import": "./dist/instrumentation/index.js"
|
|
52
56
|
}
|
|
53
57
|
},
|
|
54
58
|
"files": [
|
|
@@ -79,7 +83,10 @@
|
|
|
79
83
|
"observability",
|
|
80
84
|
"wide-events",
|
|
81
85
|
"canonical-log-lines",
|
|
82
|
-
"tail-sampling"
|
|
86
|
+
"tail-sampling",
|
|
87
|
+
"auto-instrumentation",
|
|
88
|
+
"otlp",
|
|
89
|
+
"opentelemetry"
|
|
83
90
|
],
|
|
84
91
|
"author": "Arakiss",
|
|
85
92
|
"license": "MIT",
|
|
@@ -99,7 +106,7 @@
|
|
|
99
106
|
"vestig": ">=0.2.0"
|
|
100
107
|
},
|
|
101
108
|
"dependencies": {
|
|
102
|
-
"vestig": "0.
|
|
109
|
+
"vestig": "0.19.0",
|
|
103
110
|
"web-vitals": "^4.2.4"
|
|
104
111
|
},
|
|
105
112
|
"devDependencies": {
|