Skip to content

Commit 9a8e910

Browse files
authored
fix(node): Improve OTEL validation logic (#13079)
When using the SDK without tracing, the span processor is not required - we should reflect this in our validation logic. While at it, I also improved the warning for not using the SentrySampler.
1 parent df45d65 commit 9a8e910

File tree

2 files changed

+72
-3
lines changed

2 files changed

+72
-3
lines changed

packages/node/src/sdk/index.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,12 @@ export function validateOpenTelemetrySetup(): void {
195195

196196
const setup = openTelemetrySetupCheck();
197197

198-
const required = ['SentrySpanProcessor', 'SentryContextManager', 'SentryPropagator'] as const;
198+
const required: ReturnType<typeof openTelemetrySetupCheck> = ['SentryContextManager', 'SentryPropagator'];
199+
200+
if (hasTracingEnabled()) {
201+
required.push('SentrySpanProcessor');
202+
}
203+
199204
for (const k of required) {
200205
if (!setup.includes(k)) {
201206
logger.error(
@@ -206,7 +211,7 @@ export function validateOpenTelemetrySetup(): void {
206211

207212
if (!setup.includes('SentrySampler')) {
208213
logger.warn(
209-
'You have to set up the SentrySampler. Without this, the OpenTelemetry & Sentry integration may still work, but sample rates set for the Sentry SDK will not be respected.',
214+
'You have to set up the SentrySampler. Without this, the OpenTelemetry & Sentry integration may still work, but sample rates set for the Sentry SDK will not be respected. If you use a custom sampler, make sure to use `wrapSamplingDecision`.',
210215
);
211216
}
212217
}

packages/node/test/sdk/init.test.ts

+65-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import type { Integration } from '@sentry/types';
2+
import { logger } from '@sentry/utils';
23

4+
import * as SentryOpentelemetry from '@sentry/opentelemetry';
35
import { getClient, getIsolationScope } from '../../src/';
46
import * as auto from '../../src/integrations/tracing';
5-
import { init } from '../../src/sdk';
7+
import { init, validateOpenTelemetrySetup } from '../../src/sdk';
68
import { NodeClient } from '../../src/sdk/client';
79
import { cleanupOtel } from '../helpers/mockSdkInit';
810

@@ -193,3 +195,65 @@ describe('init()', () => {
193195
});
194196
});
195197
});
198+
199+
describe('validateOpenTelemetrySetup', () => {
200+
afterEach(() => {
201+
global.__SENTRY__ = {};
202+
cleanupOtel();
203+
jest.clearAllMocks();
204+
});
205+
206+
it('works with correct setup', () => {
207+
const errorSpy = jest.spyOn(logger, 'error').mockImplementation(() => {});
208+
const warnSpy = jest.spyOn(logger, 'warn').mockImplementation(() => {});
209+
210+
jest.spyOn(SentryOpentelemetry, 'openTelemetrySetupCheck').mockImplementation(() => {
211+
return ['SentryContextManager', 'SentryPropagator', 'SentrySampler'];
212+
});
213+
214+
validateOpenTelemetrySetup();
215+
216+
expect(errorSpy).toHaveBeenCalledTimes(0);
217+
expect(warnSpy).toHaveBeenCalledTimes(0);
218+
});
219+
220+
it('works with missing setup, without tracing', () => {
221+
const errorSpy = jest.spyOn(logger, 'error').mockImplementation(() => {});
222+
const warnSpy = jest.spyOn(logger, 'warn').mockImplementation(() => {});
223+
224+
jest.spyOn(SentryOpentelemetry, 'openTelemetrySetupCheck').mockImplementation(() => {
225+
return [];
226+
});
227+
228+
validateOpenTelemetrySetup();
229+
230+
// Without tracing, this is expected only twice
231+
expect(errorSpy).toHaveBeenCalledTimes(2);
232+
expect(warnSpy).toHaveBeenCalledTimes(1);
233+
234+
expect(errorSpy).toBeCalledWith(expect.stringContaining('You have to set up the SentryContextManager.'));
235+
expect(errorSpy).toBeCalledWith(expect.stringContaining('You have to set up the SentryPropagator.'));
236+
expect(warnSpy).toBeCalledWith(expect.stringContaining('You have to set up the SentrySampler.'));
237+
});
238+
239+
it('works with missing setup, with tracing', () => {
240+
const errorSpy = jest.spyOn(logger, 'error').mockImplementation(() => {});
241+
const warnSpy = jest.spyOn(logger, 'warn').mockImplementation(() => {});
242+
243+
jest.spyOn(SentryOpentelemetry, 'openTelemetrySetupCheck').mockImplementation(() => {
244+
return [];
245+
});
246+
247+
init({ dsn: PUBLIC_DSN, skipOpenTelemetrySetup: true, tracesSampleRate: 1 });
248+
249+
validateOpenTelemetrySetup();
250+
251+
expect(errorSpy).toHaveBeenCalledTimes(3);
252+
expect(warnSpy).toHaveBeenCalledTimes(1);
253+
254+
expect(errorSpy).toBeCalledWith(expect.stringContaining('You have to set up the SentryContextManager.'));
255+
expect(errorSpy).toBeCalledWith(expect.stringContaining('You have to set up the SentryPropagator.'));
256+
expect(errorSpy).toBeCalledWith(expect.stringContaining('You have to set up the SentrySpanProcessor.'));
257+
expect(warnSpy).toBeCalledWith(expect.stringContaining('You have to set up the SentrySampler.'));
258+
});
259+
});

0 commit comments

Comments
 (0)