Skip to content

Commit 0ed4128

Browse files
committed
ref(core): Avoid looking up openai integration options
1 parent 2cde2a4 commit 0ed4128

File tree

3 files changed

+29
-51
lines changed

3 files changed

+29
-51
lines changed

packages/core/src/utils/openai/index.ts

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { getCurrentScope } from '../../currentScopes';
1+
import { getClient } from '../../currentScopes';
22
import { captureException } from '../../exports';
33
import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '../../semanticAttributes';
44
import { SPAN_STATUS_ERROR } from '../../tracing';
@@ -19,13 +19,11 @@ import {
1919
GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE,
2020
GEN_AI_SYSTEM_ATTRIBUTE,
2121
} from '../ai/gen-ai-attributes';
22-
import { OPENAI_INTEGRATION_NAME } from './constants';
2322
import { instrumentStream } from './streaming';
2423
import type {
2524
ChatCompletionChunk,
2625
InstrumentedMethod,
2726
OpenAiChatCompletionObject,
28-
OpenAiIntegration,
2927
OpenAiOptions,
3028
OpenAiResponse,
3129
OpenAIResponseObject,
@@ -198,18 +196,6 @@ function addRequestAttributes(span: Span, params: Record<string, unknown>): void
198196
}
199197
}
200198

201-
function getOptionsFromIntegration(): OpenAiOptions {
202-
const scope = getCurrentScope();
203-
const client = scope.getClient();
204-
const integration = client?.getIntegrationByName(OPENAI_INTEGRATION_NAME) as OpenAiIntegration | undefined;
205-
const shouldRecordInputsAndOutputs = integration ? Boolean(client?.getOptions().sendDefaultPii) : false;
206-
207-
return {
208-
recordInputs: integration?.options?.recordInputs ?? shouldRecordInputsAndOutputs,
209-
recordOutputs: integration?.options?.recordOutputs ?? shouldRecordInputsAndOutputs,
210-
};
211-
}
212-
213199
/**
214200
* Instrument a method with Sentry spans
215201
* Following Sentry AI Agents Manual Instrumentation conventions
@@ -219,10 +205,9 @@ function instrumentMethod<T extends unknown[], R>(
219205
originalMethod: (...args: T) => Promise<R>,
220206
methodPath: InstrumentedMethod,
221207
context: unknown,
222-
options?: OpenAiOptions,
208+
options: OpenAiOptions,
223209
): (...args: T) => Promise<R> {
224210
return async function instrumentedMethod(...args: T): Promise<R> {
225-
const finalOptions = options || getOptionsFromIntegration();
226211
const requestAttributes = extractRequestAttributes(args, methodPath);
227212
const model = (requestAttributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE] as string) || 'unknown';
228213
const operationName = getOperationName(methodPath);
@@ -240,16 +225,16 @@ function instrumentMethod<T extends unknown[], R>(
240225
},
241226
async (span: Span) => {
242227
try {
243-
if (finalOptions.recordInputs && args[0] && typeof args[0] === 'object') {
244-
addRequestAttributes(span, args[0] as Record<string, unknown>);
228+
if (options.recordInputs && params) {
229+
addRequestAttributes(span, params);
245230
}
246231

247232
const result = await originalMethod.apply(context, args);
248233

249234
return instrumentStream(
250235
result as OpenAIStream<ChatCompletionChunk | ResponseStreamingEvent>,
251236
span,
252-
finalOptions.recordOutputs ?? false,
237+
options.recordOutputs ?? false,
253238
) as unknown as R;
254239
} catch (error) {
255240
// For streaming requests that fail before stream creation, we still want to record
@@ -279,12 +264,12 @@ function instrumentMethod<T extends unknown[], R>(
279264
},
280265
async (span: Span) => {
281266
try {
282-
if (finalOptions.recordInputs && args[0] && typeof args[0] === 'object') {
283-
addRequestAttributes(span, args[0] as Record<string, unknown>);
267+
if (options.recordInputs && params) {
268+
addRequestAttributes(span, params);
284269
}
285270

286271
const result = await originalMethod.apply(context, args);
287-
addResponseAttributes(span, result, finalOptions.recordOutputs);
272+
addResponseAttributes(span, result, options.recordOutputs);
288273
return result;
289274
} catch (error) {
290275
captureException(error, {
@@ -307,7 +292,7 @@ function instrumentMethod<T extends unknown[], R>(
307292
/**
308293
* Create a deep proxy for OpenAI client instrumentation
309294
*/
310-
function createDeepProxy<T extends object>(target: T, currentPath = '', options?: OpenAiOptions): T {
295+
function createDeepProxy<T extends object>(target: T, currentPath = '', options: OpenAiOptions): T {
311296
return new Proxy(target, {
312297
get(obj: object, prop: string): unknown {
313298
const value = (obj as Record<string, unknown>)[prop];
@@ -336,6 +321,13 @@ function createDeepProxy<T extends object>(target: T, currentPath = '', options?
336321
* Instrument an OpenAI client with Sentry tracing
337322
* Can be used across Node.js, Cloudflare Workers, and Vercel Edge
338323
*/
339-
export function instrumentOpenAiClient<T extends object>(client: T, options?: OpenAiOptions): T {
340-
return createDeepProxy(client, '', options);
324+
export function instrumentOpenAiClient<T extends object>(openAiClient: T, options?: OpenAiOptions): T {
325+
const sendDefaultPii = Boolean(getClient()?.getOptions().sendDefaultPii);
326+
327+
const _options = {
328+
recordInputs: sendDefaultPii,
329+
recordOutputs: sendDefaultPii,
330+
...options,
331+
};
332+
return createDeepProxy(openAiClient, '', _options);
341333
}

packages/node/src/integrations/tracing/openai/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,17 @@ import { defineIntegration, OPENAI_INTEGRATION_NAME } from '@sentry/core';
33
import { generateInstrumentOnce } from '@sentry/node-core';
44
import { SentryOpenAiInstrumentation } from './instrumentation';
55

6-
export const instrumentOpenAi = generateInstrumentOnce(
6+
export const instrumentOpenAi = generateInstrumentOnce<OpenAiOptions>(
77
OPENAI_INTEGRATION_NAME,
8-
() => new SentryOpenAiInstrumentation({}),
8+
options => new SentryOpenAiInstrumentation(options),
99
);
1010

1111
const _openAiIntegration = ((options: OpenAiOptions = {}) => {
1212
return {
1313
name: OPENAI_INTEGRATION_NAME,
1414
options,
1515
setupOnce() {
16-
instrumentOpenAi();
16+
instrumentOpenAi(options);
1717
},
1818
};
1919
}) satisfies IntegrationFn;

packages/node/src/integrations/tracing/openai/instrumentation.ts

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,12 @@ import {
44
InstrumentationBase,
55
InstrumentationNodeModuleDefinition,
66
} from '@opentelemetry/instrumentation';
7-
import type { Integration, OpenAiClient, OpenAiOptions } from '@sentry/core';
8-
import { getClient, instrumentOpenAiClient, OPENAI_INTEGRATION_NAME, SDK_VERSION } from '@sentry/core';
7+
import type { OpenAiClient, OpenAiOptions } from '@sentry/core';
8+
import { getClient, instrumentOpenAiClient, SDK_VERSION } from '@sentry/core';
99

1010
const supportedVersions = ['>=4.0.0 <6'];
1111

12-
export interface OpenAiIntegration extends Integration {
13-
options: OpenAiOptions;
14-
}
12+
type OpenAiInstrumentationOptions = InstrumentationConfig & OpenAiOptions;
1513

1614
/**
1715
* Represents the patched shape of the OpenAI module export.
@@ -21,23 +19,11 @@ interface PatchedModuleExports {
2119
OpenAI: abstract new (...args: unknown[]) => OpenAiClient;
2220
}
2321

24-
/**
25-
* Determines telemetry recording settings.
26-
*/
27-
function determineRecordingSettings(
28-
integrationOptions: OpenAiOptions | undefined,
29-
defaultEnabled: boolean,
30-
): { recordInputs: boolean; recordOutputs: boolean } {
31-
const recordInputs = integrationOptions?.recordInputs ?? defaultEnabled;
32-
const recordOutputs = integrationOptions?.recordOutputs ?? defaultEnabled;
33-
return { recordInputs, recordOutputs };
34-
}
35-
3622
/**
3723
* Sentry OpenAI instrumentation using OpenTelemetry.
3824
*/
39-
export class SentryOpenAiInstrumentation extends InstrumentationBase<InstrumentationConfig> {
40-
public constructor(config: InstrumentationConfig = {}) {
25+
export class SentryOpenAiInstrumentation extends InstrumentationBase<OpenAiInstrumentationOptions> {
26+
public constructor(config: OpenAiInstrumentationOptions = {}) {
4127
super('@sentry/instrumentation-openai', SDK_VERSION, config);
4228
}
4329

@@ -54,15 +40,15 @@ export class SentryOpenAiInstrumentation extends InstrumentationBase<Instrumenta
5440
*/
5541
private _patch(exports: PatchedModuleExports): PatchedModuleExports | void {
5642
const Original = exports.OpenAI;
43+
const config = this.getConfig();
5744

5845
const WrappedOpenAI = function (this: unknown, ...args: unknown[]) {
5946
const instance = Reflect.construct(Original, args);
6047
const client = getClient();
61-
const integration = client?.getIntegrationByName<OpenAiIntegration>(OPENAI_INTEGRATION_NAME);
62-
const integrationOpts = integration?.options;
6348
const defaultPii = Boolean(client?.getOptions().sendDefaultPii);
6449

65-
const { recordInputs, recordOutputs } = determineRecordingSettings(integrationOpts, defaultPii);
50+
const recordInputs = config.recordInputs ?? defaultPii;
51+
const recordOutputs = config.recordOutputs ?? defaultPii;
6652

6753
return instrumentOpenAiClient(instance as OpenAiClient, {
6854
recordInputs,

0 commit comments

Comments
 (0)