Skip to content

Commit c0a0f25

Browse files
committed
refactor
1 parent 1586c5d commit c0a0f25

File tree

3 files changed

+29
-46
lines changed

3 files changed

+29
-46
lines changed

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

Lines changed: 18 additions & 25 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';
@@ -20,12 +20,10 @@ import {
2020
GEN_AI_SYSTEM_ATTRIBUTE,
2121
} from '../ai/gen-ai-attributes';
2222
import { getTruncatedJsonString } from '../ai/utils';
23-
import { OPENAI_INTEGRATION_NAME } from './constants';
2423
import { instrumentStream } from './streaming';
2524
import type {
2625
ChatCompletionChunk,
2726
InstrumentedMethod,
28-
OpenAiIntegration,
2927
OpenAiOptions,
3028
OpenAiResponse,
3129
OpenAIStream,
@@ -128,18 +126,6 @@ function addRequestAttributes(span: Span, params: Record<string, unknown>): void
128126
}
129127
}
130128

131-
function getOptionsFromIntegration(): OpenAiOptions {
132-
const scope = getCurrentScope();
133-
const client = scope.getClient();
134-
const integration = client?.getIntegrationByName<OpenAiIntegration>(OPENAI_INTEGRATION_NAME);
135-
const shouldRecordInputsAndOutputs = integration ? Boolean(client?.getOptions().sendDefaultPii) : false;
136-
137-
return {
138-
recordInputs: integration?.options?.recordInputs ?? shouldRecordInputsAndOutputs,
139-
recordOutputs: integration?.options?.recordOutputs ?? shouldRecordInputsAndOutputs,
140-
};
141-
}
142-
143129
/**
144130
* Instrument a method with Sentry spans
145131
* Following Sentry AI Agents Manual Instrumentation conventions
@@ -149,10 +135,9 @@ function instrumentMethod<T extends unknown[], R>(
149135
originalMethod: (...args: T) => Promise<R>,
150136
methodPath: InstrumentedMethod,
151137
context: unknown,
152-
options?: OpenAiOptions,
138+
options: OpenAiOptions,
153139
): (...args: T) => Promise<R> {
154140
return async function instrumentedMethod(...args: T): Promise<R> {
155-
const finalOptions = options || getOptionsFromIntegration();
156141
const requestAttributes = extractRequestAttributes(args, methodPath);
157142
const model = (requestAttributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE] as string) || 'unknown';
158143
const operationName = getOperationName(methodPath);
@@ -170,16 +155,16 @@ function instrumentMethod<T extends unknown[], R>(
170155
},
171156
async (span: Span) => {
172157
try {
173-
if (finalOptions.recordInputs && args[0] && typeof args[0] === 'object') {
174-
addRequestAttributes(span, args[0] as Record<string, unknown>);
158+
if (options.recordInputs && params) {
159+
addRequestAttributes(span, params);
175160
}
176161

177162
const result = await originalMethod.apply(context, args);
178163

179164
return instrumentStream(
180165
result as OpenAIStream<ChatCompletionChunk | ResponseStreamingEvent>,
181166
span,
182-
finalOptions.recordOutputs ?? false,
167+
options.recordOutputs ?? false,
183168
) as unknown as R;
184169
} catch (error) {
185170
// For streaming requests that fail before stream creation, we still want to record
@@ -209,12 +194,12 @@ function instrumentMethod<T extends unknown[], R>(
209194
},
210195
async (span: Span) => {
211196
try {
212-
if (finalOptions.recordInputs && args[0] && typeof args[0] === 'object') {
213-
addRequestAttributes(span, args[0] as Record<string, unknown>);
197+
if (options.recordInputs && params) {
198+
addRequestAttributes(span, params);
214199
}
215200

216201
const result = await originalMethod.apply(context, args);
217-
addResponseAttributes(span, result, finalOptions.recordOutputs);
202+
addResponseAttributes(span, result, options.recordOutputs);
218203
return result;
219204
} catch (error) {
220205
captureException(error, {
@@ -237,7 +222,7 @@ function instrumentMethod<T extends unknown[], R>(
237222
/**
238223
* Create a deep proxy for OpenAI client instrumentation
239224
*/
240-
function createDeepProxy<T extends object>(target: T, currentPath = '', options?: OpenAiOptions): T {
225+
function createDeepProxy<T extends object>(target: T, currentPath = '', options: OpenAiOptions): T {
241226
return new Proxy(target, {
242227
get(obj: object, prop: string): unknown {
243228
const value = (obj as Record<string, unknown>)[prop];
@@ -267,5 +252,13 @@ function createDeepProxy<T extends object>(target: T, currentPath = '', options?
267252
* Can be used across Node.js, Cloudflare Workers, and Vercel Edge
268253
*/
269254
export function instrumentOpenAiClient<T extends object>(client: T, options?: OpenAiOptions): T {
270-
return createDeepProxy(client, '', options);
255+
const sendDefaultPii = Boolean(getClient()?.getOptions().sendDefaultPii);
256+
257+
const _options = {
258+
recordInputs: sendDefaultPii,
259+
recordOutputs: sendDefaultPii,
260+
...options,
261+
};
262+
263+
return createDeepProxy(client, '', _options);
271264
}

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,16 @@ 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,
14-
options,
1514
setupOnce() {
16-
instrumentOpenAi();
15+
instrumentOpenAi(options);
1716
},
1817
};
1918
}) satisfies IntegrationFn;

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

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ export interface OpenAiIntegration extends Integration {
1919
options: OpenAiOptions;
2020
}
2121

22+
type OpenAiInstrumentationOptions = InstrumentationConfig & OpenAiOptions;
23+
2224
/**
2325
* Represents the patched shape of the OpenAI module export.
2426
*/
@@ -28,23 +30,11 @@ interface PatchedModuleExports {
2830
AzureOpenAI?: abstract new (...args: unknown[]) => OpenAiClient;
2931
}
3032

31-
/**
32-
* Determines telemetry recording settings.
33-
*/
34-
function determineRecordingSettings(
35-
integrationOptions: OpenAiOptions | undefined,
36-
defaultEnabled: boolean,
37-
): { recordInputs: boolean; recordOutputs: boolean } {
38-
const recordInputs = integrationOptions?.recordInputs ?? defaultEnabled;
39-
const recordOutputs = integrationOptions?.recordOutputs ?? defaultEnabled;
40-
return { recordInputs, recordOutputs };
41-
}
42-
4333
/**
4434
* Sentry OpenAI instrumentation using OpenTelemetry.
4535
*/
46-
export class SentryOpenAiInstrumentation extends InstrumentationBase<InstrumentationConfig> {
47-
public constructor(config: InstrumentationConfig = {}) {
36+
export class SentryOpenAiInstrumentation extends InstrumentationBase<OpenAiInstrumentationOptions> {
37+
public constructor(config: OpenAiInstrumentationOptions = {}) {
4838
super('@sentry/instrumentation-openai', SDK_VERSION, config);
4939
}
5040

@@ -75,6 +65,8 @@ export class SentryOpenAiInstrumentation extends InstrumentationBase<Instrumenta
7565
return exports;
7666
}
7767

68+
const config = this.getConfig();
69+
7870
const WrappedOpenAI = function (this: unknown, ...args: unknown[]) {
7971
// Check if wrapping should be skipped (e.g., when LangChain is handling instrumentation)
8072
if (_INTERNAL_shouldSkipAiProviderWrapping(OPENAI_INTEGRATION_NAME)) {
@@ -83,11 +75,10 @@ export class SentryOpenAiInstrumentation extends InstrumentationBase<Instrumenta
8375

8476
const instance = Reflect.construct(Original, args);
8577
const client = getClient();
86-
const integration = client?.getIntegrationByName<OpenAiIntegration>(OPENAI_INTEGRATION_NAME);
87-
const integrationOpts = integration?.options;
8878
const defaultPii = Boolean(client?.getOptions().sendDefaultPii);
8979

90-
const { recordInputs, recordOutputs } = determineRecordingSettings(integrationOpts, defaultPii);
80+
const recordInputs = config.recordInputs ?? defaultPii;
81+
const recordOutputs = config.recordOutputs ?? defaultPii;
9182

9283
return instrumentOpenAiClient(instance as OpenAiClient, {
9384
recordInputs,

0 commit comments

Comments
 (0)