@sentry/node 9.32.0 → 9.33.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/build/cjs/index.js +2 -0
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/integrations/anr/index.js +1 -1
- package/build/cjs/integrations/local-variables/local-variables-async.js +1 -1
- package/build/cjs/integrations/tracing/fastify/index.js +42 -5
- package/build/cjs/integrations/tracing/fastify/index.js.map +1 -1
- package/build/cjs/integrations/tracing/index.js +3 -0
- package/build/cjs/integrations/tracing/index.js.map +1 -1
- package/build/cjs/integrations/tracing/postgresjs.js +283 -0
- package/build/cjs/integrations/tracing/postgresjs.js.map +1 -0
- package/build/cjs/integrations/tracing/vercelai/index.js +7 -183
- package/build/cjs/integrations/tracing/vercelai/index.js.map +1 -1
- package/build/esm/index.js +1 -0
- package/build/esm/index.js.map +1 -1
- package/build/esm/integrations/anr/index.js +1 -1
- package/build/esm/integrations/anr/worker-script.js +2 -2
- package/build/esm/integrations/local-variables/local-variables-async.js +1 -1
- package/build/esm/integrations/local-variables/worker-script.js +2 -2
- package/build/esm/integrations/tracing/fastify/index.js +43 -6
- package/build/esm/integrations/tracing/fastify/index.js.map +1 -1
- package/build/esm/integrations/tracing/index.js +3 -0
- package/build/esm/integrations/tracing/index.js.map +1 -1
- package/build/esm/integrations/tracing/postgresjs.js +279 -0
- package/build/esm/integrations/tracing/postgresjs.js.map +1 -0
- package/build/esm/integrations/tracing/vercelai/index.js +8 -184
- package/build/esm/integrations/tracing/vercelai/index.js.map +1 -1
- package/build/esm/package.json +1 -1
- package/build/types/index.d.ts +1 -0
- package/build/types/index.d.ts.map +1 -1
- package/build/types/integrations/tracing/fastify/index.d.ts +1 -1
- package/build/types/integrations/tracing/fastify/index.d.ts.map +1 -1
- package/build/types/integrations/tracing/index.d.ts.map +1 -1
- package/build/types/integrations/tracing/postgresjs.d.ts +81 -0
- package/build/types/integrations/tracing/postgresjs.d.ts.map +1 -0
- package/build/types/integrations/tracing/vercelai/index.d.ts +5 -7
- package/build/types/integrations/tracing/vercelai/index.d.ts.map +1 -1
- package/build/types-ts3.8/index.d.ts +1 -0
- package/build/types-ts3.8/integrations/tracing/fastify/index.d.ts +1 -1
- package/build/types-ts3.8/integrations/tracing/postgresjs.d.ts +81 -0
- package/build/types-ts3.8/integrations/tracing/vercelai/index.d.ts +5 -7
- package/package.json +3 -3
- package/build/cjs/integrations/tracing/vercelai/ai_sdk_attributes.js +0 -168
- package/build/cjs/integrations/tracing/vercelai/ai_sdk_attributes.js.map +0 -1
- package/build/esm/integrations/tracing/vercelai/ai_sdk_attributes.js +0 -152
- package/build/esm/integrations/tracing/vercelai/ai_sdk_attributes.js.map +0 -1
- package/build/types/integrations/tracing/vercelai/ai_sdk_attributes.d.ts +0 -669
- package/build/types/integrations/tracing/vercelai/ai_sdk_attributes.d.ts.map +0 -1
- package/build/types-ts3.8/integrations/tracing/vercelai/ai_sdk_attributes.d.ts +0 -669
|
@@ -14,6 +14,7 @@ import { instrumentMongoose, mongooseIntegration } from './mongoose.js';
|
|
|
14
14
|
import { instrumentMysql, mysqlIntegration } from './mysql.js';
|
|
15
15
|
import { instrumentMysql2, mysql2Integration } from './mysql2.js';
|
|
16
16
|
import { instrumentPostgres, postgresIntegration } from './postgres.js';
|
|
17
|
+
import { instrumentPostgresJs, postgresJsIntegration } from './postgresjs.js';
|
|
17
18
|
import { prismaIntegration } from './prisma.js';
|
|
18
19
|
import { instrumentRedis, redisIntegration } from './redis.js';
|
|
19
20
|
import { instrumentTedious, tediousIntegration } from './tedious.js';
|
|
@@ -43,6 +44,7 @@ function getAutoPerformanceIntegrations() {
|
|
|
43
44
|
amqplibIntegration(),
|
|
44
45
|
lruMemoizerIntegration(),
|
|
45
46
|
vercelAIIntegration(),
|
|
47
|
+
postgresJsIntegration(),
|
|
46
48
|
];
|
|
47
49
|
}
|
|
48
50
|
|
|
@@ -74,6 +76,7 @@ function getOpenTelemetryInstrumentationToPreload() {
|
|
|
74
76
|
instrumentGenericPool,
|
|
75
77
|
instrumentAmqplib,
|
|
76
78
|
instrumentVercelAi,
|
|
79
|
+
instrumentPostgresJs,
|
|
77
80
|
];
|
|
78
81
|
}
|
|
79
82
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../src/integrations/tracing/index.ts"],"sourcesContent":["import type { Integration } from '@sentry/core';\nimport { instrumentOtelHttp } from '../http';\nimport { amqplibIntegration, instrumentAmqplib } from './amqplib';\nimport { connectIntegration, instrumentConnect } from './connect';\nimport { expressIntegration, instrumentExpress, instrumentExpressV5 } from './express';\nimport { fastifyIntegration, instrumentFastify, instrumentFastifyV3 } from './fastify';\nimport { genericPoolIntegration, instrumentGenericPool } from './genericPool';\nimport { graphqlIntegration, instrumentGraphql } from './graphql';\nimport { hapiIntegration, instrumentHapi } from './hapi';\nimport { instrumentKafka, kafkaIntegration } from './kafka';\nimport { instrumentKoa, koaIntegration } from './koa';\nimport { instrumentLruMemoizer, lruMemoizerIntegration } from './lrumemoizer';\nimport { instrumentMongo, mongoIntegration } from './mongo';\nimport { instrumentMongoose, mongooseIntegration } from './mongoose';\nimport { instrumentMysql, mysqlIntegration } from './mysql';\nimport { instrumentMysql2, mysql2Integration } from './mysql2';\nimport { instrumentPostgres, postgresIntegration } from './postgres';\nimport { prismaIntegration } from './prisma';\nimport { instrumentRedis, redisIntegration } from './redis';\nimport { instrumentTedious, tediousIntegration } from './tedious';\nimport { instrumentVercelAi, vercelAIIntegration } from './vercelai';\n\n/**\n * With OTEL, all performance integrations will be added, as OTEL only initializes them when the patched package is actually required.\n */\nexport function getAutoPerformanceIntegrations(): Integration[] {\n return [\n expressIntegration(),\n fastifyIntegration(),\n graphqlIntegration(),\n mongoIntegration(),\n mongooseIntegration(),\n mysqlIntegration(),\n mysql2Integration(),\n redisIntegration(),\n postgresIntegration(),\n prismaIntegration(),\n hapiIntegration(),\n koaIntegration(),\n connectIntegration(),\n tediousIntegration(),\n genericPoolIntegration(),\n kafkaIntegration(),\n amqplibIntegration(),\n lruMemoizerIntegration(),\n vercelAIIntegration(),\n ];\n}\n\n/**\n * Get a list of methods to instrument OTEL, when preload instrumentation.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function getOpenTelemetryInstrumentationToPreload(): (((options?: any) => void) & { id: string })[] {\n return [\n instrumentOtelHttp,\n instrumentExpress,\n instrumentExpressV5,\n instrumentConnect,\n instrumentFastify,\n instrumentFastifyV3,\n instrumentHapi,\n instrumentKafka,\n instrumentKoa,\n instrumentLruMemoizer,\n instrumentMongo,\n instrumentMongoose,\n instrumentMysql,\n instrumentMysql2,\n instrumentPostgres,\n instrumentHapi,\n instrumentGraphql,\n instrumentRedis,\n instrumentTedious,\n instrumentGenericPool,\n instrumentAmqplib,\n instrumentVercelAi,\n ];\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/integrations/tracing/index.ts"],"sourcesContent":["import type { Integration } from '@sentry/core';\nimport { instrumentOtelHttp } from '../http';\nimport { amqplibIntegration, instrumentAmqplib } from './amqplib';\nimport { connectIntegration, instrumentConnect } from './connect';\nimport { expressIntegration, instrumentExpress, instrumentExpressV5 } from './express';\nimport { fastifyIntegration, instrumentFastify, instrumentFastifyV3 } from './fastify';\nimport { genericPoolIntegration, instrumentGenericPool } from './genericPool';\nimport { graphqlIntegration, instrumentGraphql } from './graphql';\nimport { hapiIntegration, instrumentHapi } from './hapi';\nimport { instrumentKafka, kafkaIntegration } from './kafka';\nimport { instrumentKoa, koaIntegration } from './koa';\nimport { instrumentLruMemoizer, lruMemoizerIntegration } from './lrumemoizer';\nimport { instrumentMongo, mongoIntegration } from './mongo';\nimport { instrumentMongoose, mongooseIntegration } from './mongoose';\nimport { instrumentMysql, mysqlIntegration } from './mysql';\nimport { instrumentMysql2, mysql2Integration } from './mysql2';\nimport { instrumentPostgres, postgresIntegration } from './postgres';\nimport { instrumentPostgresJs, postgresJsIntegration } from './postgresjs';\nimport { prismaIntegration } from './prisma';\nimport { instrumentRedis, redisIntegration } from './redis';\nimport { instrumentTedious, tediousIntegration } from './tedious';\nimport { instrumentVercelAi, vercelAIIntegration } from './vercelai';\n\n/**\n * With OTEL, all performance integrations will be added, as OTEL only initializes them when the patched package is actually required.\n */\nexport function getAutoPerformanceIntegrations(): Integration[] {\n return [\n expressIntegration(),\n fastifyIntegration(),\n graphqlIntegration(),\n mongoIntegration(),\n mongooseIntegration(),\n mysqlIntegration(),\n mysql2Integration(),\n redisIntegration(),\n postgresIntegration(),\n prismaIntegration(),\n hapiIntegration(),\n koaIntegration(),\n connectIntegration(),\n tediousIntegration(),\n genericPoolIntegration(),\n kafkaIntegration(),\n amqplibIntegration(),\n lruMemoizerIntegration(),\n vercelAIIntegration(),\n postgresJsIntegration(),\n ];\n}\n\n/**\n * Get a list of methods to instrument OTEL, when preload instrumentation.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function getOpenTelemetryInstrumentationToPreload(): (((options?: any) => void) & { id: string })[] {\n return [\n instrumentOtelHttp,\n instrumentExpress,\n instrumentExpressV5,\n instrumentConnect,\n instrumentFastify,\n instrumentFastifyV3,\n instrumentHapi,\n instrumentKafka,\n instrumentKoa,\n instrumentLruMemoizer,\n instrumentMongo,\n instrumentMongoose,\n instrumentMysql,\n instrumentMysql2,\n instrumentPostgres,\n instrumentHapi,\n instrumentGraphql,\n instrumentRedis,\n instrumentTedious,\n instrumentGenericPool,\n instrumentAmqplib,\n instrumentVercelAi,\n instrumentPostgresJs,\n ];\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAuBA;AACA;AACA;AACO,SAAS,8BAA8B,GAAkB;AAChE,EAAE,OAAO;AACT,IAAI,kBAAkB,EAAE;AACxB,IAAI,kBAAkB,EAAE;AACxB,IAAI,kBAAkB,EAAE;AACxB,IAAI,gBAAgB,EAAE;AACtB,IAAI,mBAAmB,EAAE;AACzB,IAAI,gBAAgB,EAAE;AACtB,IAAI,iBAAiB,EAAE;AACvB,IAAI,gBAAgB,EAAE;AACtB,IAAI,mBAAmB,EAAE;AACzB,IAAI,iBAAiB,EAAE;AACvB,IAAI,eAAe,EAAE;AACrB,IAAI,cAAc,EAAE;AACpB,IAAI,kBAAkB,EAAE;AACxB,IAAI,kBAAkB,EAAE;AACxB,IAAI,sBAAsB,EAAE;AAC5B,IAAI,gBAAgB,EAAE;AACtB,IAAI,kBAAkB,EAAE;AACxB,IAAI,sBAAsB,EAAE;AAC5B,IAAI,mBAAmB,EAAE;AACzB,IAAI,qBAAqB,EAAE;AAC3B,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACO,SAAS,wCAAwC,GAAmD;AAC3G,EAAE,OAAO;AACT,IAAI,kBAAkB;AACtB,IAAI,iBAAiB;AACrB,IAAI,mBAAmB;AACvB,IAAI,iBAAiB;AACrB,IAAI,iBAAiB;AACrB,IAAI,mBAAmB;AACvB,IAAI,cAAc;AAClB,IAAI,eAAe;AACnB,IAAI,aAAa;AACjB,IAAI,qBAAqB;AACzB,IAAI,eAAe;AACnB,IAAI,kBAAkB;AACtB,IAAI,eAAe;AACnB,IAAI,gBAAgB;AACpB,IAAI,kBAAkB;AACtB,IAAI,cAAc;AAClB,IAAI,iBAAiB;AACrB,IAAI,eAAe;AACnB,IAAI,iBAAiB;AACrB,IAAI,qBAAqB;AACzB,IAAI,iBAAiB;AACrB,IAAI,kBAAkB;AACtB,IAAI,oBAAoB;AACxB,GAAG;AACH;;;;"}
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { trace, context } from '@opentelemetry/api';
|
|
2
|
+
import { InstrumentationBase, InstrumentationNodeModuleDefinition, InstrumentationNodeModuleFile, safeExecuteInTheMiddle } from '@opentelemetry/instrumentation';
|
|
3
|
+
import { ATTR_DB_RESPONSE_STATUS_CODE, ATTR_ERROR_TYPE, ATTR_DB_OPERATION_NAME, ATTR_DB_SYSTEM_NAME, ATTR_DB_NAMESPACE, ATTR_SERVER_ADDRESS, ATTR_SERVER_PORT, ATTR_DB_QUERY_TEXT } from '@opentelemetry/semantic-conventions';
|
|
4
|
+
import { defineIntegration, SDK_VERSION, SPAN_STATUS_ERROR, startSpanManual, getCurrentScope, logger } from '@sentry/core';
|
|
5
|
+
import { generateInstrumentOnce } from '../../otel/instrument.js';
|
|
6
|
+
import { addOriginToSpan } from '../../utils/addOriginToSpan.js';
|
|
7
|
+
|
|
8
|
+
// Instrumentation for https://github.com/porsager/postgres
|
|
9
|
+
|
|
10
|
+
const INTEGRATION_NAME = 'PostgresJs';
|
|
11
|
+
const SUPPORTED_VERSIONS = ['>=3.0.0 <4'];
|
|
12
|
+
|
|
13
|
+
const instrumentPostgresJs = generateInstrumentOnce(
|
|
14
|
+
INTEGRATION_NAME,
|
|
15
|
+
(options) =>
|
|
16
|
+
new PostgresJsInstrumentation({
|
|
17
|
+
requireParentSpan: options?.requireParentSpan ?? true,
|
|
18
|
+
requestHook: options?.requestHook,
|
|
19
|
+
}),
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Instrumentation for the [postgres](https://www.npmjs.com/package/postgres) library.
|
|
24
|
+
* This instrumentation captures postgresjs queries and their attributes,
|
|
25
|
+
*/
|
|
26
|
+
class PostgresJsInstrumentation extends InstrumentationBase {
|
|
27
|
+
constructor(config) {
|
|
28
|
+
super('sentry-postgres-js', SDK_VERSION, config);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Initializes the instrumentation.
|
|
33
|
+
*/
|
|
34
|
+
init() {
|
|
35
|
+
const instrumentationModule = new InstrumentationNodeModuleDefinition('postgres', SUPPORTED_VERSIONS);
|
|
36
|
+
|
|
37
|
+
['src', 'cf/src', 'cjs/src'].forEach(path => {
|
|
38
|
+
instrumentationModule.files.push(
|
|
39
|
+
new InstrumentationNodeModuleFile(
|
|
40
|
+
`postgres/${path}/connection.js`,
|
|
41
|
+
['*'],
|
|
42
|
+
this._patchConnection.bind(this),
|
|
43
|
+
this._unwrap.bind(this),
|
|
44
|
+
),
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
instrumentationModule.files.push(
|
|
48
|
+
new InstrumentationNodeModuleFile(
|
|
49
|
+
`postgres/${path}/query.js`,
|
|
50
|
+
SUPPORTED_VERSIONS,
|
|
51
|
+
this._patchQuery.bind(this),
|
|
52
|
+
this._unwrap.bind(this),
|
|
53
|
+
),
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return [instrumentationModule];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Determines whether a span should be created based on the current context.
|
|
62
|
+
* If `requireParentSpan` is set to true in the configuration, a span will
|
|
63
|
+
* only be created if there is a parent span available.
|
|
64
|
+
*/
|
|
65
|
+
_shouldCreateSpans() {
|
|
66
|
+
const config = this.getConfig();
|
|
67
|
+
const hasParentSpan = trace.getSpan(context.active()) !== undefined;
|
|
68
|
+
return hasParentSpan || !config.requireParentSpan;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Patches the reject method of the Query class to set the span status and end it
|
|
73
|
+
*/
|
|
74
|
+
_patchReject(rejectTarget, span) {
|
|
75
|
+
return new Proxy(rejectTarget, {
|
|
76
|
+
apply: (
|
|
77
|
+
rejectTarget,
|
|
78
|
+
rejectThisArg,
|
|
79
|
+
rejectArgs
|
|
80
|
+
|
|
81
|
+
,
|
|
82
|
+
) => {
|
|
83
|
+
span.setStatus({
|
|
84
|
+
code: SPAN_STATUS_ERROR,
|
|
85
|
+
// This message is the error message from the rejectArgs, when available
|
|
86
|
+
// e.g "relation 'User' does not exist"
|
|
87
|
+
message: rejectArgs?.[0]?.message || 'unknown_error',
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const result = Reflect.apply(rejectTarget, rejectThisArg, rejectArgs);
|
|
91
|
+
|
|
92
|
+
// This status code is PG error code, e.g. '42P01' for "relation does not exist"
|
|
93
|
+
// https://www.postgresql.org/docs/current/errcodes-appendix.html
|
|
94
|
+
span.setAttribute(ATTR_DB_RESPONSE_STATUS_CODE, rejectArgs?.[0]?.code || 'Unknown error');
|
|
95
|
+
// This is the error type, e.g. 'PostgresError' for a Postgres error
|
|
96
|
+
span.setAttribute(ATTR_ERROR_TYPE, rejectArgs?.[0]?.name || 'Unknown error');
|
|
97
|
+
|
|
98
|
+
span.end();
|
|
99
|
+
return result;
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Patches the resolve method of the Query class to end the span when the query is resolved.
|
|
106
|
+
*/
|
|
107
|
+
_patchResolve(resolveTarget, span) {
|
|
108
|
+
return new Proxy(resolveTarget, {
|
|
109
|
+
apply: (resolveTarget, resolveThisArg, resolveArgs) => {
|
|
110
|
+
const result = Reflect.apply(resolveTarget, resolveThisArg, resolveArgs);
|
|
111
|
+
const sqlCommand = resolveArgs?.[0]?.command;
|
|
112
|
+
|
|
113
|
+
if (sqlCommand) {
|
|
114
|
+
// SQL command is only available when the query is resolved successfully
|
|
115
|
+
span.setAttribute(ATTR_DB_OPERATION_NAME, sqlCommand);
|
|
116
|
+
}
|
|
117
|
+
span.end();
|
|
118
|
+
return result;
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Patches the Query class to instrument the handle method.
|
|
125
|
+
*/
|
|
126
|
+
_patchQuery(moduleExports
|
|
127
|
+
|
|
128
|
+
) {
|
|
129
|
+
moduleExports.Query.prototype.handle = new Proxy(moduleExports.Query.prototype.handle, {
|
|
130
|
+
apply: async (
|
|
131
|
+
handleTarget,
|
|
132
|
+
handleThisArg
|
|
133
|
+
|
|
134
|
+
,
|
|
135
|
+
handleArgs,
|
|
136
|
+
) => {
|
|
137
|
+
if (!this._shouldCreateSpans()) {
|
|
138
|
+
// If we don't need to create spans, just call the original method
|
|
139
|
+
return Reflect.apply(handleTarget, handleThisArg, handleArgs);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const sanitizedSqlQuery = this._sanitizeSqlQuery(handleThisArg.strings?.[0]);
|
|
143
|
+
|
|
144
|
+
return startSpanManual(
|
|
145
|
+
{
|
|
146
|
+
name: sanitizedSqlQuery || 'postgresjs.query',
|
|
147
|
+
op: 'db',
|
|
148
|
+
},
|
|
149
|
+
(span) => {
|
|
150
|
+
const scope = getCurrentScope();
|
|
151
|
+
const postgresConnectionContext = scope.getScopeData().contexts['postgresjsConnection']
|
|
152
|
+
|
|
153
|
+
;
|
|
154
|
+
|
|
155
|
+
addOriginToSpan(span, 'auto.db.otel.postgres');
|
|
156
|
+
|
|
157
|
+
const { requestHook } = this.getConfig();
|
|
158
|
+
|
|
159
|
+
if (requestHook) {
|
|
160
|
+
safeExecuteInTheMiddle(
|
|
161
|
+
() => requestHook(span, sanitizedSqlQuery, postgresConnectionContext),
|
|
162
|
+
error => {
|
|
163
|
+
if (error) {
|
|
164
|
+
logger.error(`Error in requestHook for ${INTEGRATION_NAME} integration:`, error);
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// ATTR_DB_NAMESPACE is used to indicate the database name and the schema name
|
|
171
|
+
// It's only the database name as we don't have the schema information
|
|
172
|
+
const databaseName = postgresConnectionContext?.ATTR_DB_NAMESPACE || '<unknown database>';
|
|
173
|
+
const databaseHost = postgresConnectionContext?.ATTR_SERVER_ADDRESS || '<unknown host>';
|
|
174
|
+
const databasePort = postgresConnectionContext?.ATTR_SERVER_PORT || '<unknown port>';
|
|
175
|
+
|
|
176
|
+
span.setAttribute(ATTR_DB_SYSTEM_NAME, 'postgres');
|
|
177
|
+
span.setAttribute(ATTR_DB_NAMESPACE, databaseName);
|
|
178
|
+
span.setAttribute(ATTR_SERVER_ADDRESS, databaseHost);
|
|
179
|
+
span.setAttribute(ATTR_SERVER_PORT, databasePort);
|
|
180
|
+
span.setAttribute(ATTR_DB_QUERY_TEXT, sanitizedSqlQuery);
|
|
181
|
+
|
|
182
|
+
handleThisArg.resolve = this._patchResolve(handleThisArg.resolve, span);
|
|
183
|
+
handleThisArg.reject = this._patchReject(handleThisArg.reject, span);
|
|
184
|
+
|
|
185
|
+
try {
|
|
186
|
+
return Reflect.apply(handleTarget, handleThisArg, handleArgs);
|
|
187
|
+
} catch (error) {
|
|
188
|
+
span.setStatus({
|
|
189
|
+
code: SPAN_STATUS_ERROR,
|
|
190
|
+
});
|
|
191
|
+
span.end();
|
|
192
|
+
throw error; // Re-throw the error to propagate it
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
);
|
|
196
|
+
},
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
return moduleExports;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Patches the Connection class to set the database, host, and port attributes
|
|
204
|
+
* when a new connection is created.
|
|
205
|
+
*/
|
|
206
|
+
_patchConnection(Connection) {
|
|
207
|
+
return new Proxy(Connection, {
|
|
208
|
+
apply: (connectionTarget, thisArg, connectionArgs) => {
|
|
209
|
+
const databaseName = connectionArgs[0]?.database || '<unknown database>';
|
|
210
|
+
const databaseHost = connectionArgs[0]?.host?.[0] || '<unknown host>';
|
|
211
|
+
const databasePort = connectionArgs[0]?.port?.[0] || '<unknown port>';
|
|
212
|
+
|
|
213
|
+
const scope = getCurrentScope();
|
|
214
|
+
scope.setContext('postgresjsConnection', {
|
|
215
|
+
ATTR_DB_NAMESPACE: databaseName,
|
|
216
|
+
ATTR_SERVER_ADDRESS: databaseHost,
|
|
217
|
+
ATTR_SERVER_PORT: databasePort,
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
return Reflect.apply(connectionTarget, thisArg, connectionArgs);
|
|
221
|
+
},
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Sanitize SQL query as per the OTEL semantic conventions
|
|
227
|
+
* https://opentelemetry.io/docs/specs/semconv/database/database-spans/#sanitization-of-dbquerytext
|
|
228
|
+
*/
|
|
229
|
+
_sanitizeSqlQuery(sqlQuery) {
|
|
230
|
+
if (!sqlQuery) {
|
|
231
|
+
return 'Unknown SQL Query';
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return (
|
|
235
|
+
sqlQuery
|
|
236
|
+
.replace(/\s+/g, ' ')
|
|
237
|
+
.trim() // Remove extra spaces including newlines and trim
|
|
238
|
+
.substring(0, 1024) // Truncate to 1024 characters
|
|
239
|
+
.replace(/--.*?(\r?\n|$)/g, '') // Single line comments
|
|
240
|
+
.replace(/\/\*[\s\S]*?\*\//g, '') // Multi-line comments
|
|
241
|
+
.replace(/;\s*$/, '') // Remove trailing semicolons
|
|
242
|
+
.replace(/\b\d+\b/g, '?') // Replace standalone numbers
|
|
243
|
+
// Collapse whitespace to a single space
|
|
244
|
+
.replace(/\s+/g, ' ')
|
|
245
|
+
// Collapse IN and in clauses
|
|
246
|
+
// eg. IN (?, ?, ?, ?) to IN (?)
|
|
247
|
+
.replace(/\bIN\b\s*\(\s*\?(?:\s*,\s*\?)*\s*\)/g, 'IN (?)')
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const _postgresJsIntegration = (() => {
|
|
253
|
+
return {
|
|
254
|
+
name: INTEGRATION_NAME,
|
|
255
|
+
setupOnce() {
|
|
256
|
+
instrumentPostgresJs();
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
}) ;
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Adds Sentry tracing instrumentation for the [postgres](https://www.npmjs.com/package/postgres) library.
|
|
263
|
+
*
|
|
264
|
+
* For more information, see the [`postgresIntegration` documentation](https://docs.sentry.io/platforms/javascript/guides/node/configuration/integrations/postgres/).
|
|
265
|
+
*
|
|
266
|
+
* @example
|
|
267
|
+
* ```javascript
|
|
268
|
+
* const Sentry = require('@sentry/node');
|
|
269
|
+
*
|
|
270
|
+
* Sentry.init({
|
|
271
|
+
* integrations: [Sentry.postgresJsIntegration()],
|
|
272
|
+
* });
|
|
273
|
+
* ```
|
|
274
|
+
*/
|
|
275
|
+
|
|
276
|
+
const postgresJsIntegration = defineIntegration(_postgresJsIntegration);
|
|
277
|
+
|
|
278
|
+
export { PostgresJsInstrumentation, instrumentPostgresJs, postgresJsIntegration };
|
|
279
|
+
//# sourceMappingURL=postgresjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgresjs.js","sources":["../../../../src/integrations/tracing/postgresjs.ts"],"sourcesContent":["// Instrumentation for https://github.com/porsager/postgres\nimport { context, trace } from '@opentelemetry/api';\nimport type { InstrumentationConfig } from '@opentelemetry/instrumentation';\nimport {\n InstrumentationBase,\n InstrumentationNodeModuleDefinition,\n InstrumentationNodeModuleFile,\n safeExecuteInTheMiddle,\n} from '@opentelemetry/instrumentation';\nimport {\n ATTR_DB_NAMESPACE,\n ATTR_DB_OPERATION_NAME,\n ATTR_DB_QUERY_TEXT,\n ATTR_DB_RESPONSE_STATUS_CODE,\n ATTR_DB_SYSTEM_NAME,\n ATTR_ERROR_TYPE,\n ATTR_SERVER_ADDRESS,\n ATTR_SERVER_PORT,\n} from '@opentelemetry/semantic-conventions';\nimport type { IntegrationFn, Span } from '@sentry/core';\nimport {\n defineIntegration,\n getCurrentScope,\n logger,\n SDK_VERSION,\n SPAN_STATUS_ERROR,\n startSpanManual,\n} from '@sentry/core';\nimport { generateInstrumentOnce } from '../../otel/instrument';\nimport { addOriginToSpan } from '../../utils/addOriginToSpan';\n\nconst INTEGRATION_NAME = 'PostgresJs';\nconst SUPPORTED_VERSIONS = ['>=3.0.0 <4'];\n\ntype PostgresConnectionContext = {\n ATTR_DB_NAMESPACE?: string; // Database name\n ATTR_SERVER_ADDRESS?: string; // Hostname or IP address of the database server\n ATTR_SERVER_PORT?: string; // Port number of the database server\n};\n\ntype PostgresJsInstrumentationConfig = InstrumentationConfig & {\n /**\n * Whether to require a parent span for the instrumentation.\n * If set to true, the instrumentation will only create spans if there is a parent span\n * available in the current scope.\n * @default true\n */\n requireParentSpan?: boolean;\n /**\n * Hook to modify the span before it is started.\n * This can be used to set additional attributes or modify the span in any way.\n */\n requestHook?: (span: Span, sanitizedSqlQuery: string, postgresConnectionContext?: PostgresConnectionContext) => void;\n};\n\nexport const instrumentPostgresJs = generateInstrumentOnce(\n INTEGRATION_NAME,\n (options?: PostgresJsInstrumentationConfig) =>\n new PostgresJsInstrumentation({\n requireParentSpan: options?.requireParentSpan ?? true,\n requestHook: options?.requestHook,\n }),\n);\n\n/**\n * Instrumentation for the [postgres](https://www.npmjs.com/package/postgres) library.\n * This instrumentation captures postgresjs queries and their attributes,\n */\nexport class PostgresJsInstrumentation extends InstrumentationBase<PostgresJsInstrumentationConfig> {\n public constructor(config: PostgresJsInstrumentationConfig) {\n super('sentry-postgres-js', SDK_VERSION, config);\n }\n\n /**\n * Initializes the instrumentation.\n */\n public init(): InstrumentationNodeModuleDefinition[] {\n const instrumentationModule = new InstrumentationNodeModuleDefinition('postgres', SUPPORTED_VERSIONS);\n\n ['src', 'cf/src', 'cjs/src'].forEach(path => {\n instrumentationModule.files.push(\n new InstrumentationNodeModuleFile(\n `postgres/${path}/connection.js`,\n ['*'],\n this._patchConnection.bind(this),\n this._unwrap.bind(this),\n ),\n );\n\n instrumentationModule.files.push(\n new InstrumentationNodeModuleFile(\n `postgres/${path}/query.js`,\n SUPPORTED_VERSIONS,\n this._patchQuery.bind(this),\n this._unwrap.bind(this),\n ),\n );\n });\n\n return [instrumentationModule];\n }\n\n /**\n * Determines whether a span should be created based on the current context.\n * If `requireParentSpan` is set to true in the configuration, a span will\n * only be created if there is a parent span available.\n */\n private _shouldCreateSpans(): boolean {\n const config = this.getConfig();\n const hasParentSpan = trace.getSpan(context.active()) !== undefined;\n return hasParentSpan || !config.requireParentSpan;\n }\n\n /**\n * Patches the reject method of the Query class to set the span status and end it\n */\n private _patchReject(rejectTarget: any, span: Span): any {\n return new Proxy(rejectTarget, {\n apply: (\n rejectTarget,\n rejectThisArg,\n rejectArgs: {\n message?: string;\n code?: string;\n name?: string;\n }[],\n ) => {\n span.setStatus({\n code: SPAN_STATUS_ERROR,\n // This message is the error message from the rejectArgs, when available\n // e.g \"relation 'User' does not exist\"\n message: rejectArgs?.[0]?.message || 'unknown_error',\n });\n\n const result = Reflect.apply(rejectTarget, rejectThisArg, rejectArgs);\n\n // This status code is PG error code, e.g. '42P01' for \"relation does not exist\"\n // https://www.postgresql.org/docs/current/errcodes-appendix.html\n span.setAttribute(ATTR_DB_RESPONSE_STATUS_CODE, rejectArgs?.[0]?.code || 'Unknown error');\n // This is the error type, e.g. 'PostgresError' for a Postgres error\n span.setAttribute(ATTR_ERROR_TYPE, rejectArgs?.[0]?.name || 'Unknown error');\n\n span.end();\n return result;\n },\n });\n }\n\n /**\n * Patches the resolve method of the Query class to end the span when the query is resolved.\n */\n private _patchResolve(resolveTarget: any, span: Span): any {\n return new Proxy(resolveTarget, {\n apply: (resolveTarget, resolveThisArg, resolveArgs: [{ command?: string }]) => {\n const result = Reflect.apply(resolveTarget, resolveThisArg, resolveArgs);\n const sqlCommand = resolveArgs?.[0]?.command;\n\n if (sqlCommand) {\n // SQL command is only available when the query is resolved successfully\n span.setAttribute(ATTR_DB_OPERATION_NAME, sqlCommand);\n }\n span.end();\n return result;\n },\n });\n }\n\n /**\n * Patches the Query class to instrument the handle method.\n */\n private _patchQuery(moduleExports: {\n Query: {\n prototype: {\n handle: any;\n };\n };\n }): any {\n moduleExports.Query.prototype.handle = new Proxy(moduleExports.Query.prototype.handle, {\n apply: async (\n handleTarget,\n handleThisArg: {\n resolve: any;\n reject: any;\n strings?: string[];\n },\n handleArgs,\n ) => {\n if (!this._shouldCreateSpans()) {\n // If we don't need to create spans, just call the original method\n return Reflect.apply(handleTarget, handleThisArg, handleArgs);\n }\n\n const sanitizedSqlQuery = this._sanitizeSqlQuery(handleThisArg.strings?.[0]);\n\n return startSpanManual(\n {\n name: sanitizedSqlQuery || 'postgresjs.query',\n op: 'db',\n },\n (span: Span) => {\n const scope = getCurrentScope();\n const postgresConnectionContext = scope.getScopeData().contexts['postgresjsConnection'] as\n | PostgresConnectionContext\n | undefined;\n\n addOriginToSpan(span, 'auto.db.otel.postgres');\n\n const { requestHook } = this.getConfig();\n\n if (requestHook) {\n safeExecuteInTheMiddle(\n () => requestHook(span, sanitizedSqlQuery, postgresConnectionContext),\n error => {\n if (error) {\n logger.error(`Error in requestHook for ${INTEGRATION_NAME} integration:`, error);\n }\n },\n );\n }\n\n // ATTR_DB_NAMESPACE is used to indicate the database name and the schema name\n // It's only the database name as we don't have the schema information\n const databaseName = postgresConnectionContext?.ATTR_DB_NAMESPACE || '<unknown database>';\n const databaseHost = postgresConnectionContext?.ATTR_SERVER_ADDRESS || '<unknown host>';\n const databasePort = postgresConnectionContext?.ATTR_SERVER_PORT || '<unknown port>';\n\n span.setAttribute(ATTR_DB_SYSTEM_NAME, 'postgres');\n span.setAttribute(ATTR_DB_NAMESPACE, databaseName);\n span.setAttribute(ATTR_SERVER_ADDRESS, databaseHost);\n span.setAttribute(ATTR_SERVER_PORT, databasePort);\n span.setAttribute(ATTR_DB_QUERY_TEXT, sanitizedSqlQuery);\n\n handleThisArg.resolve = this._patchResolve(handleThisArg.resolve, span);\n handleThisArg.reject = this._patchReject(handleThisArg.reject, span);\n\n try {\n return Reflect.apply(handleTarget, handleThisArg, handleArgs);\n } catch (error) {\n span.setStatus({\n code: SPAN_STATUS_ERROR,\n });\n span.end();\n throw error; // Re-throw the error to propagate it\n }\n },\n );\n },\n });\n\n return moduleExports;\n }\n\n /**\n * Patches the Connection class to set the database, host, and port attributes\n * when a new connection is created.\n */\n private _patchConnection(Connection: any): any {\n return new Proxy(Connection, {\n apply: (connectionTarget, thisArg, connectionArgs: { database: string; host: string[]; port: number[] }[]) => {\n const databaseName = connectionArgs[0]?.database || '<unknown database>';\n const databaseHost = connectionArgs[0]?.host?.[0] || '<unknown host>';\n const databasePort = connectionArgs[0]?.port?.[0] || '<unknown port>';\n\n const scope = getCurrentScope();\n scope.setContext('postgresjsConnection', {\n ATTR_DB_NAMESPACE: databaseName,\n ATTR_SERVER_ADDRESS: databaseHost,\n ATTR_SERVER_PORT: databasePort,\n });\n\n return Reflect.apply(connectionTarget, thisArg, connectionArgs);\n },\n });\n }\n\n /**\n * Sanitize SQL query as per the OTEL semantic conventions\n * https://opentelemetry.io/docs/specs/semconv/database/database-spans/#sanitization-of-dbquerytext\n */\n private _sanitizeSqlQuery(sqlQuery: string | undefined): string {\n if (!sqlQuery) {\n return 'Unknown SQL Query';\n }\n\n return (\n sqlQuery\n .replace(/\\s+/g, ' ')\n .trim() // Remove extra spaces including newlines and trim\n .substring(0, 1024) // Truncate to 1024 characters\n .replace(/--.*?(\\r?\\n|$)/g, '') // Single line comments\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '') // Multi-line comments\n .replace(/;\\s*$/, '') // Remove trailing semicolons\n .replace(/\\b\\d+\\b/g, '?') // Replace standalone numbers\n // Collapse whitespace to a single space\n .replace(/\\s+/g, ' ')\n // Collapse IN and in clauses\n // eg. IN (?, ?, ?, ?) to IN (?)\n .replace(/\\bIN\\b\\s*\\(\\s*\\?(?:\\s*,\\s*\\?)*\\s*\\)/g, 'IN (?)')\n );\n }\n}\n\nconst _postgresJsIntegration = (() => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n instrumentPostgresJs();\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Adds Sentry tracing instrumentation for the [postgres](https://www.npmjs.com/package/postgres) library.\n *\n * For more information, see the [`postgresIntegration` documentation](https://docs.sentry.io/platforms/javascript/guides/node/configuration/integrations/postgres/).\n *\n * @example\n * ```javascript\n * const Sentry = require('@sentry/node');\n *\n * Sentry.init({\n * integrations: [Sentry.postgresJsIntegration()],\n * });\n * ```\n */\n\nexport const postgresJsIntegration = defineIntegration(_postgresJsIntegration);\n"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { defineIntegration,
|
|
1
|
+
import { defineIntegration, addVercelAiProcessors } from '@sentry/core';
|
|
2
2
|
import { generateInstrumentOnce } from '../../../otel/instrument.js';
|
|
3
|
-
import { addOriginToSpan } from '../../../utils/addOriginToSpan.js';
|
|
4
|
-
import { AI_TOOL_CALL_NAME_ATTRIBUTE, AI_TOOL_CALL_ID_ATTRIBUTE, AI_MODEL_ID_ATTRIBUTE, AI_MODEL_PROVIDER_ATTRIBUTE, AI_TELEMETRY_FUNCTION_ID_ATTRIBUTE, AI_PROMPT_ATTRIBUTE, GEN_AI_RESPONSE_MODEL_ATTRIBUTE, GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE, GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE, AI_USAGE_COMPLETION_TOKENS_ATTRIBUTE, AI_USAGE_PROMPT_TOKENS_ATTRIBUTE, AI_PROMPT_MESSAGES_ATTRIBUTE, AI_RESPONSE_TEXT_ATTRIBUTE, AI_RESPONSE_TOOL_CALLS_ATTRIBUTE, AI_PROMPT_TOOLS_ATTRIBUTE } from './ai_sdk_attributes.js';
|
|
5
3
|
import { INTEGRATION_NAME } from './constants.js';
|
|
6
4
|
import { SentryVercelAiInstrumentation } from './instrumentation.js';
|
|
7
5
|
|
|
@@ -26,175 +24,14 @@ const _vercelAIIntegration = ((options = {}) => {
|
|
|
26
24
|
instrumentation = instrumentVercelAi();
|
|
27
25
|
},
|
|
28
26
|
afterAllSetup(client) {
|
|
29
|
-
function registerProcessors() {
|
|
30
|
-
client.on('spanStart', span => {
|
|
31
|
-
const { data: attributes, description: name } = spanToJSON(span);
|
|
32
|
-
|
|
33
|
-
if (!name) {
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Tool call spans
|
|
38
|
-
// https://ai-sdk.dev/docs/ai-sdk-core/telemetry#tool-call-spans
|
|
39
|
-
if (
|
|
40
|
-
attributes[AI_TOOL_CALL_NAME_ATTRIBUTE] &&
|
|
41
|
-
attributes[AI_TOOL_CALL_ID_ATTRIBUTE] &&
|
|
42
|
-
name === 'ai.toolCall'
|
|
43
|
-
) {
|
|
44
|
-
addOriginToSpan(span, 'auto.vercelai.otel');
|
|
45
|
-
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'gen_ai.execute_tool');
|
|
46
|
-
span.setAttribute('gen_ai.tool.call.id', attributes[AI_TOOL_CALL_ID_ATTRIBUTE]);
|
|
47
|
-
span.setAttribute('gen_ai.tool.name', attributes[AI_TOOL_CALL_NAME_ATTRIBUTE]);
|
|
48
|
-
span.updateName(`execute_tool ${attributes[AI_TOOL_CALL_NAME_ATTRIBUTE]}`);
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// The AI and Provider must be defined for generate, stream, and embed spans.
|
|
53
|
-
// The id of the model
|
|
54
|
-
const aiModelId = attributes[AI_MODEL_ID_ATTRIBUTE];
|
|
55
|
-
// the provider of the model
|
|
56
|
-
const aiModelProvider = attributes[AI_MODEL_PROVIDER_ATTRIBUTE];
|
|
57
|
-
if (typeof aiModelId !== 'string' || typeof aiModelProvider !== 'string' || !aiModelId || !aiModelProvider) {
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
addOriginToSpan(span, 'auto.vercelai.otel');
|
|
62
|
-
|
|
63
|
-
const nameWthoutAi = name.replace('ai.', '');
|
|
64
|
-
span.setAttribute('ai.pipeline.name', nameWthoutAi);
|
|
65
|
-
span.updateName(nameWthoutAi);
|
|
66
|
-
|
|
67
|
-
// If a Telemetry name is set and it is a pipeline span, use that as the operation name
|
|
68
|
-
const functionId = attributes[AI_TELEMETRY_FUNCTION_ID_ATTRIBUTE];
|
|
69
|
-
if (functionId && typeof functionId === 'string' && name.split('.').length - 1 === 1) {
|
|
70
|
-
span.updateName(`${nameWthoutAi} ${functionId}`);
|
|
71
|
-
span.setAttribute('ai.pipeline.name', functionId);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (attributes[AI_PROMPT_ATTRIBUTE]) {
|
|
75
|
-
span.setAttribute('gen_ai.prompt', attributes[AI_PROMPT_ATTRIBUTE]);
|
|
76
|
-
}
|
|
77
|
-
if (attributes[AI_MODEL_ID_ATTRIBUTE] && !attributes[GEN_AI_RESPONSE_MODEL_ATTRIBUTE]) {
|
|
78
|
-
span.setAttribute(GEN_AI_RESPONSE_MODEL_ATTRIBUTE, attributes[AI_MODEL_ID_ATTRIBUTE]);
|
|
79
|
-
}
|
|
80
|
-
span.setAttribute('ai.streaming', name.includes('stream'));
|
|
81
|
-
|
|
82
|
-
// Generate Spans
|
|
83
|
-
if (name === 'ai.generateText') {
|
|
84
|
-
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'gen_ai.invoke_agent');
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (name === 'ai.generateText.doGenerate') {
|
|
89
|
-
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'gen_ai.generate_text');
|
|
90
|
-
span.updateName(`generate_text ${attributes[AI_MODEL_ID_ATTRIBUTE]}`);
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (name === 'ai.streamText') {
|
|
95
|
-
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'gen_ai.invoke_agent');
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (name === 'ai.streamText.doStream') {
|
|
100
|
-
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'gen_ai.stream_text');
|
|
101
|
-
span.updateName(`stream_text ${attributes[AI_MODEL_ID_ATTRIBUTE]}`);
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (name === 'ai.generateObject') {
|
|
106
|
-
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'gen_ai.invoke_agent');
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (name === 'ai.generateObject.doGenerate') {
|
|
111
|
-
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'gen_ai.generate_object');
|
|
112
|
-
span.updateName(`generate_object ${attributes[AI_MODEL_ID_ATTRIBUTE]}`);
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (name === 'ai.streamObject') {
|
|
117
|
-
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'gen_ai.invoke_agent');
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (name === 'ai.streamObject.doStream') {
|
|
122
|
-
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'gen_ai.stream_object');
|
|
123
|
-
span.updateName(`stream_object ${attributes[AI_MODEL_ID_ATTRIBUTE]}`);
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (name === 'ai.embed') {
|
|
128
|
-
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'gen_ai.invoke_agent');
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (name === 'ai.embed.doEmbed') {
|
|
133
|
-
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'gen_ai.embed');
|
|
134
|
-
span.updateName(`embed ${attributes[AI_MODEL_ID_ATTRIBUTE]}`);
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
if (name === 'ai.embedMany') {
|
|
139
|
-
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'gen_ai.invoke_agent');
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (name === 'ai.embedMany.doEmbed') {
|
|
144
|
-
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'gen_ai.embed_many');
|
|
145
|
-
span.updateName(`embed_many ${attributes[AI_MODEL_ID_ATTRIBUTE]}`);
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (name.startsWith('ai.stream')) {
|
|
150
|
-
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'ai.run');
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
client.addEventProcessor(event => {
|
|
156
|
-
if (event.type === 'transaction' && event.spans?.length) {
|
|
157
|
-
for (const span of event.spans) {
|
|
158
|
-
const { data: attributes, description: name } = span;
|
|
159
|
-
|
|
160
|
-
if (!name || span.origin !== 'auto.vercelai.otel') {
|
|
161
|
-
continue;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
renameAttributeKey(
|
|
165
|
-
attributes,
|
|
166
|
-
AI_USAGE_COMPLETION_TOKENS_ATTRIBUTE,
|
|
167
|
-
GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE,
|
|
168
|
-
);
|
|
169
|
-
renameAttributeKey(attributes, AI_USAGE_PROMPT_TOKENS_ATTRIBUTE, GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE);
|
|
170
|
-
if (
|
|
171
|
-
typeof attributes[GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE] === 'number' &&
|
|
172
|
-
typeof attributes[GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE] === 'number'
|
|
173
|
-
) {
|
|
174
|
-
attributes['gen_ai.usage.total_tokens'] =
|
|
175
|
-
attributes[GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE] + attributes[GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE];
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// Rename AI SDK attributes to standardized gen_ai attributes
|
|
179
|
-
renameAttributeKey(attributes, AI_PROMPT_MESSAGES_ATTRIBUTE, 'gen_ai.request.messages');
|
|
180
|
-
renameAttributeKey(attributes, AI_RESPONSE_TEXT_ATTRIBUTE, 'gen_ai.response.text');
|
|
181
|
-
renameAttributeKey(attributes, AI_RESPONSE_TOOL_CALLS_ATTRIBUTE, 'gen_ai.response.tool_calls');
|
|
182
|
-
renameAttributeKey(attributes, AI_PROMPT_TOOLS_ATTRIBUTE, 'gen_ai.request.available_tools');
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
return event;
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
|
|
190
27
|
// Auto-detect if we should force the integration when running with 'ai' package available
|
|
191
28
|
// Note that this can only be detected if the 'Modules' integration is available, and running in CJS mode
|
|
192
29
|
const shouldForce = options.force ?? shouldForceIntegration(client);
|
|
193
30
|
|
|
194
31
|
if (shouldForce) {
|
|
195
|
-
|
|
32
|
+
addVercelAiProcessors(client);
|
|
196
33
|
} else {
|
|
197
|
-
instrumentation?.callWhenPatched(
|
|
34
|
+
instrumentation?.callWhenPatched(() => addVercelAiProcessors(client));
|
|
198
35
|
}
|
|
199
36
|
},
|
|
200
37
|
};
|
|
@@ -202,6 +39,7 @@ const _vercelAIIntegration = ((options = {}) => {
|
|
|
202
39
|
|
|
203
40
|
/**
|
|
204
41
|
* Adds Sentry tracing instrumentation for the [ai](https://www.npmjs.com/package/ai) library.
|
|
42
|
+
* This integration is not enabled by default, you need to manually add it.
|
|
205
43
|
*
|
|
206
44
|
* For more information, see the [`ai` documentation](https://sdk.vercel.ai/docs/ai-sdk-core/telemetry).
|
|
207
45
|
*
|
|
@@ -214,17 +52,14 @@ const _vercelAIIntegration = ((options = {}) => {
|
|
|
214
52
|
* });
|
|
215
53
|
* ```
|
|
216
54
|
*
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
* By default this integration adds tracing support to all `ai` function calls. If you need to disable
|
|
221
|
-
* collecting spans for a specific call, you can do so by setting `experimental_telemetry.isEnabled` to
|
|
222
|
-
* `false` in the first argument of the function call.
|
|
55
|
+
* This integration adds tracing support to all `ai` function calls.
|
|
56
|
+
* You need to opt-in to collecting spans for a specific call,
|
|
57
|
+
* you can do so by setting `experimental_telemetry.isEnabled` to `true` in the first argument of the function call.
|
|
223
58
|
*
|
|
224
59
|
* ```javascript
|
|
225
60
|
* const result = await generateText({
|
|
226
61
|
* model: openai('gpt-4-turbo'),
|
|
227
|
-
* experimental_telemetry: { isEnabled:
|
|
62
|
+
* experimental_telemetry: { isEnabled: true },
|
|
228
63
|
* });
|
|
229
64
|
* ```
|
|
230
65
|
*
|
|
@@ -240,16 +75,5 @@ const _vercelAIIntegration = ((options = {}) => {
|
|
|
240
75
|
*/
|
|
241
76
|
const vercelAIIntegration = defineIntegration(_vercelAIIntegration);
|
|
242
77
|
|
|
243
|
-
/**
|
|
244
|
-
* Renames an attribute key in the provided attributes object if the old key exists.
|
|
245
|
-
* This function safely handles null and undefined values.
|
|
246
|
-
*/
|
|
247
|
-
function renameAttributeKey(attributes, oldKey, newKey) {
|
|
248
|
-
if (attributes[oldKey] != null) {
|
|
249
|
-
attributes[newKey] = attributes[oldKey];
|
|
250
|
-
delete attributes[oldKey];
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
78
|
export { instrumentVercelAi, vercelAIIntegration };
|
|
255
79
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../../src/integrations/tracing/vercelai/index.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-dynamic-delete */\n/* eslint-disable complexity */\nimport type { Client, IntegrationFn } from '@sentry/core';\nimport { defineIntegration, SEMANTIC_ATTRIBUTE_SENTRY_OP, spanToJSON } from '@sentry/core';\nimport { generateInstrumentOnce } from '../../../otel/instrument';\nimport { addOriginToSpan } from '../../../utils/addOriginToSpan';\nimport type { modulesIntegration } from '../../modules';\nimport {\n AI_MODEL_ID_ATTRIBUTE,\n AI_MODEL_PROVIDER_ATTRIBUTE,\n AI_PROMPT_ATTRIBUTE,\n AI_PROMPT_MESSAGES_ATTRIBUTE,\n AI_PROMPT_TOOLS_ATTRIBUTE,\n AI_RESPONSE_TEXT_ATTRIBUTE,\n AI_RESPONSE_TOOL_CALLS_ATTRIBUTE,\n AI_TELEMETRY_FUNCTION_ID_ATTRIBUTE,\n AI_TOOL_CALL_ID_ATTRIBUTE,\n AI_TOOL_CALL_NAME_ATTRIBUTE,\n AI_USAGE_COMPLETION_TOKENS_ATTRIBUTE,\n AI_USAGE_PROMPT_TOKENS_ATTRIBUTE,\n GEN_AI_RESPONSE_MODEL_ATTRIBUTE,\n GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE,\n GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE,\n} from './ai_sdk_attributes';\nimport { INTEGRATION_NAME } from './constants';\nimport { SentryVercelAiInstrumentation } from './instrumentation';\nimport type { VercelAiOptions } from './types';\n\nexport const instrumentVercelAi = generateInstrumentOnce(INTEGRATION_NAME, () => new SentryVercelAiInstrumentation({}));\n\n/**\n * Determines if the integration should be forced based on environment and package availability.\n * Returns true if the 'ai' package is available.\n */\nfunction shouldForceIntegration(client: Client): boolean {\n const modules = client.getIntegrationByName<ReturnType<typeof modulesIntegration>>('Modules');\n return !!modules?.getModules?.()?.ai;\n}\n\nconst _vercelAIIntegration = ((options: VercelAiOptions = {}) => {\n let instrumentation: undefined | SentryVercelAiInstrumentation;\n\n return {\n name: INTEGRATION_NAME,\n options,\n setupOnce() {\n instrumentation = instrumentVercelAi();\n },\n afterAllSetup(client) {\n function registerProcessors(): void {\n client.on('spanStart', span => {\n const { data: attributes, description: name } = spanToJSON(span);\n\n if (!name) {\n return;\n }\n\n // Tool call spans\n // https://ai-sdk.dev/docs/ai-sdk-core/telemetry#tool-call-spans\n if (\n attributes[AI_TOOL_CALL_NAME_ATTRIBUTE] &&\n attributes[AI_TOOL_CALL_ID_ATTRIBUTE] &&\n name === 'ai.toolCall'\n ) {\n addOriginToSpan(span, 'auto.vercelai.otel');\n span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'gen_ai.execute_tool');\n span.setAttribute('gen_ai.tool.call.id', attributes[AI_TOOL_CALL_ID_ATTRIBUTE]);\n span.setAttribute('gen_ai.tool.name', attributes[AI_TOOL_CALL_NAME_ATTRIBUTE]);\n span.updateName(`execute_tool ${attributes[AI_TOOL_CALL_NAME_ATTRIBUTE]}`);\n return;\n }\n\n // The AI and Provider must be defined for generate, stream, and embed spans.\n // The id of the model\n const aiModelId = attributes[AI_MODEL_ID_ATTRIBUTE];\n // the provider of the model\n const aiModelProvider = attributes[AI_MODEL_PROVIDER_ATTRIBUTE];\n if (typeof aiModelId !== 'string' || typeof aiModelProvider !== 'string' || !aiModelId || !aiModelProvider) {\n return;\n }\n\n addOriginToSpan(span, 'auto.vercelai.otel');\n\n const nameWthoutAi = name.replace('ai.', '');\n span.setAttribute('ai.pipeline.name', nameWthoutAi);\n span.updateName(nameWthoutAi);\n\n // If a Telemetry name is set and it is a pipeline span, use that as the operation name\n const functionId = attributes[AI_TELEMETRY_FUNCTION_ID_ATTRIBUTE];\n if (functionId && typeof functionId === 'string' && name.split('.').length - 1 === 1) {\n span.updateName(`${nameWthoutAi} ${functionId}`);\n span.setAttribute('ai.pipeline.name', functionId);\n }\n\n if (attributes[AI_PROMPT_ATTRIBUTE]) {\n span.setAttribute('gen_ai.prompt', attributes[AI_PROMPT_ATTRIBUTE]);\n }\n if (attributes[AI_MODEL_ID_ATTRIBUTE] && !attributes[GEN_AI_RESPONSE_MODEL_ATTRIBUTE]) {\n span.setAttribute(GEN_AI_RESPONSE_MODEL_ATTRIBUTE, attributes[AI_MODEL_ID_ATTRIBUTE]);\n }\n span.setAttribute('ai.streaming', name.includes('stream'));\n\n // Generate Spans\n if (name === 'ai.generateText') {\n span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'gen_ai.invoke_agent');\n return;\n }\n\n if (name === 'ai.generateText.doGenerate') {\n span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'gen_ai.generate_text');\n span.updateName(`generate_text ${attributes[AI_MODEL_ID_ATTRIBUTE]}`);\n return;\n }\n\n if (name === 'ai.streamText') {\n span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'gen_ai.invoke_agent');\n return;\n }\n\n if (name === 'ai.streamText.doStream') {\n span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'gen_ai.stream_text');\n span.updateName(`stream_text ${attributes[AI_MODEL_ID_ATTRIBUTE]}`);\n return;\n }\n\n if (name === 'ai.generateObject') {\n span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'gen_ai.invoke_agent');\n return;\n }\n\n if (name === 'ai.generateObject.doGenerate') {\n span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'gen_ai.generate_object');\n span.updateName(`generate_object ${attributes[AI_MODEL_ID_ATTRIBUTE]}`);\n return;\n }\n\n if (name === 'ai.streamObject') {\n span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'gen_ai.invoke_agent');\n return;\n }\n\n if (name === 'ai.streamObject.doStream') {\n span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'gen_ai.stream_object');\n span.updateName(`stream_object ${attributes[AI_MODEL_ID_ATTRIBUTE]}`);\n return;\n }\n\n if (name === 'ai.embed') {\n span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'gen_ai.invoke_agent');\n return;\n }\n\n if (name === 'ai.embed.doEmbed') {\n span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'gen_ai.embed');\n span.updateName(`embed ${attributes[AI_MODEL_ID_ATTRIBUTE]}`);\n return;\n }\n\n if (name === 'ai.embedMany') {\n span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'gen_ai.invoke_agent');\n return;\n }\n\n if (name === 'ai.embedMany.doEmbed') {\n span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'gen_ai.embed_many');\n span.updateName(`embed_many ${attributes[AI_MODEL_ID_ATTRIBUTE]}`);\n return;\n }\n\n if (name.startsWith('ai.stream')) {\n span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'ai.run');\n return;\n }\n });\n\n client.addEventProcessor(event => {\n if (event.type === 'transaction' && event.spans?.length) {\n for (const span of event.spans) {\n const { data: attributes, description: name } = span;\n\n if (!name || span.origin !== 'auto.vercelai.otel') {\n continue;\n }\n\n renameAttributeKey(\n attributes,\n AI_USAGE_COMPLETION_TOKENS_ATTRIBUTE,\n GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE,\n );\n renameAttributeKey(attributes, AI_USAGE_PROMPT_TOKENS_ATTRIBUTE, GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE);\n if (\n typeof attributes[GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE] === 'number' &&\n typeof attributes[GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE] === 'number'\n ) {\n attributes['gen_ai.usage.total_tokens'] =\n attributes[GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE] + attributes[GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE];\n }\n\n // Rename AI SDK attributes to standardized gen_ai attributes\n renameAttributeKey(attributes, AI_PROMPT_MESSAGES_ATTRIBUTE, 'gen_ai.request.messages');\n renameAttributeKey(attributes, AI_RESPONSE_TEXT_ATTRIBUTE, 'gen_ai.response.text');\n renameAttributeKey(attributes, AI_RESPONSE_TOOL_CALLS_ATTRIBUTE, 'gen_ai.response.tool_calls');\n renameAttributeKey(attributes, AI_PROMPT_TOOLS_ATTRIBUTE, 'gen_ai.request.available_tools');\n }\n }\n\n return event;\n });\n }\n\n // Auto-detect if we should force the integration when running with 'ai' package available\n // Note that this can only be detected if the 'Modules' integration is available, and running in CJS mode\n const shouldForce = options.force ?? shouldForceIntegration(client);\n\n if (shouldForce) {\n registerProcessors();\n } else {\n instrumentation?.callWhenPatched(registerProcessors);\n }\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Adds Sentry tracing instrumentation for the [ai](https://www.npmjs.com/package/ai) library.\n *\n * For more information, see the [`ai` documentation](https://sdk.vercel.ai/docs/ai-sdk-core/telemetry).\n *\n * @example\n * ```javascript\n * const Sentry = require('@sentry/node');\n *\n * Sentry.init({\n * integrations: [Sentry.vercelAIIntegration()],\n * });\n * ```\n *\n * The integration automatically detects when to force registration in CommonJS environments\n * when the 'ai' package is available. You can still manually set the `force` option if needed.\n *\n * By default this integration adds tracing support to all `ai` function calls. If you need to disable\n * collecting spans for a specific call, you can do so by setting `experimental_telemetry.isEnabled` to\n * `false` in the first argument of the function call.\n *\n * ```javascript\n * const result = await generateText({\n * model: openai('gpt-4-turbo'),\n * experimental_telemetry: { isEnabled: false },\n * });\n * ```\n *\n * If you want to collect inputs and outputs for a specific call, you must specifically opt-in to each\n * function call by setting `experimental_telemetry.recordInputs` and `experimental_telemetry.recordOutputs`\n * to `true`.\n *\n * ```javascript\n * const result = await generateText({\n * model: openai('gpt-4-turbo'),\n * experimental_telemetry: { isEnabled: true, recordInputs: true, recordOutputs: true },\n * });\n */\nexport const vercelAIIntegration = defineIntegration(_vercelAIIntegration);\n\n/**\n * Renames an attribute key in the provided attributes object if the old key exists.\n * This function safely handles null and undefined values.\n */\nfunction renameAttributeKey(attributes: Record<string, unknown>, oldKey: string, newKey: string): void {\n if (attributes[oldKey] != null) {\n attributes[newKey] = attributes[oldKey];\n delete attributes[oldKey];\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../../src/integrations/tracing/vercelai/index.ts"],"sourcesContent":["import type { Client, IntegrationFn } from '@sentry/core';\nimport { addVercelAiProcessors, defineIntegration } from '@sentry/core';\nimport { generateInstrumentOnce } from '../../../otel/instrument';\nimport type { modulesIntegration } from '../../modules';\nimport { INTEGRATION_NAME } from './constants';\nimport { SentryVercelAiInstrumentation } from './instrumentation';\nimport type { VercelAiOptions } from './types';\n\nexport const instrumentVercelAi = generateInstrumentOnce(INTEGRATION_NAME, () => new SentryVercelAiInstrumentation({}));\n\n/**\n * Determines if the integration should be forced based on environment and package availability.\n * Returns true if the 'ai' package is available.\n */\nfunction shouldForceIntegration(client: Client): boolean {\n const modules = client.getIntegrationByName<ReturnType<typeof modulesIntegration>>('Modules');\n return !!modules?.getModules?.()?.ai;\n}\n\nconst _vercelAIIntegration = ((options: VercelAiOptions = {}) => {\n let instrumentation: undefined | SentryVercelAiInstrumentation;\n\n return {\n name: INTEGRATION_NAME,\n options,\n setupOnce() {\n instrumentation = instrumentVercelAi();\n },\n afterAllSetup(client) {\n // Auto-detect if we should force the integration when running with 'ai' package available\n // Note that this can only be detected if the 'Modules' integration is available, and running in CJS mode\n const shouldForce = options.force ?? shouldForceIntegration(client);\n\n if (shouldForce) {\n addVercelAiProcessors(client);\n } else {\n instrumentation?.callWhenPatched(() => addVercelAiProcessors(client));\n }\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Adds Sentry tracing instrumentation for the [ai](https://www.npmjs.com/package/ai) library.\n * This integration is not enabled by default, you need to manually add it.\n *\n * For more information, see the [`ai` documentation](https://sdk.vercel.ai/docs/ai-sdk-core/telemetry).\n *\n * @example\n * ```javascript\n * const Sentry = require('@sentry/node');\n *\n * Sentry.init({\n * integrations: [Sentry.vercelAIIntegration()],\n * });\n * ```\n *\n * This integration adds tracing support to all `ai` function calls.\n * You need to opt-in to collecting spans for a specific call,\n * you can do so by setting `experimental_telemetry.isEnabled` to `true` in the first argument of the function call.\n *\n * ```javascript\n * const result = await generateText({\n * model: openai('gpt-4-turbo'),\n * experimental_telemetry: { isEnabled: true },\n * });\n * ```\n *\n * If you want to collect inputs and outputs for a specific call, you must specifically opt-in to each\n * function call by setting `experimental_telemetry.recordInputs` and `experimental_telemetry.recordOutputs`\n * to `true`.\n *\n * ```javascript\n * const result = await generateText({\n * model: openai('gpt-4-turbo'),\n * experimental_telemetry: { isEnabled: true, recordInputs: true, recordOutputs: true },\n * });\n */\nexport const vercelAIIntegration = defineIntegration(_vercelAIIntegration);\n"],"names":[],"mappings":";;;;;MAQa,kBAAmB,GAAE,sBAAsB,CAAC,gBAAgB,EAAE,MAAM,IAAI,6BAA6B,CAAC,EAAE,CAAC;;AAEtH;AACA;AACA;AACA;AACA,SAAS,sBAAsB,CAAC,MAAM,EAAmB;AACzD,EAAE,MAAM,UAAU,MAAM,CAAC,oBAAoB,CAAwC,SAAS,CAAC;AAC/F,EAAE,OAAO,CAAC,CAAC,OAAO,EAAE,UAAU,IAAI,EAAE,EAAE;AACtC;;AAEA,MAAM,oBAAA,IAAwB,CAAC,OAAO,GAAoB,EAAE,KAAK;AACjE,EAAE,IAAI,eAAe;;AAErB,EAAE,OAAO;AACT,IAAI,IAAI,EAAE,gBAAgB;AAC1B,IAAI,OAAO;AACX,IAAI,SAAS,GAAG;AAChB,MAAM,eAAgB,GAAE,kBAAkB,EAAE;AAC5C,KAAK;AACL,IAAI,aAAa,CAAC,MAAM,EAAE;AAC1B;AACA;AACA,MAAM,MAAM,WAAY,GAAE,OAAO,CAAC,SAAS,sBAAsB,CAAC,MAAM,CAAC;;AAEzE,MAAM,IAAI,WAAW,EAAE;AACvB,QAAQ,qBAAqB,CAAC,MAAM,CAAC;AACrC,aAAa;AACb,QAAQ,eAAe,EAAE,eAAe,CAAC,MAAM,qBAAqB,CAAC,MAAM,CAAC,CAAC;AAC7E;AACA,KAAK;AACL,GAAG;AACH,CAAC,CAAE;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;MACa,mBAAoB,GAAE,iBAAiB,CAAC,oBAAoB;;;;"}
|
package/build/esm/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"type":"module","version":"9.
|
|
1
|
+
{"type":"module","version":"9.33.0","sideEffects":false}
|