Skip to content

Commit 4c6c012

Browse files
authored
fix(node-core): Shut down OTel TraceProvider when calling Sentry.close() (#17499)
Ensure we shut down the SDKs internal OTel TraceProvider (if internal OTel SDK is intialized), when calling `Sentry.close()` (or rather `NodeClient::close`).
1 parent ec29e5d commit 4c6c012

File tree

2 files changed

+68
-4
lines changed

2 files changed

+68
-4
lines changed

packages/node-core/src/sdk/client.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,7 @@ export class NodeClient extends ServerRuntimeClient<NodeClientOptions> {
8080
// Eslint ignore explanation: This is already documented in super.
8181
// eslint-disable-next-line jsdoc/require-jsdoc
8282
public async flush(timeout?: number): Promise<boolean> {
83-
const provider = this.traceProvider;
84-
85-
await provider?.forceFlush();
83+
await this.traceProvider?.forceFlush();
8684

8785
if (this.getOptions().sendClientReports) {
8886
this._flushOutcomes();
@@ -106,7 +104,11 @@ export class NodeClient extends ServerRuntimeClient<NodeClientOptions> {
106104
process.off('beforeExit', this._logOnExitFlushListener);
107105
}
108106

109-
return super.close(timeout);
107+
return super
108+
.close(timeout)
109+
.then(allEventsSent =>
110+
this.traceProvider ? this.traceProvider.shutdown().then(() => allEventsSent) : allEventsSent,
111+
);
110112
}
111113

112114
/**

packages/node-core/test/sdk/client.test.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { ProxyTracer } from '@opentelemetry/api';
22
import * as opentelemetryInstrumentationPackage from '@opentelemetry/instrumentation';
3+
import type { BasicTracerProvider } from '@opentelemetry/sdk-trace-base';
34
import type { Event, EventHint, Log } from '@sentry/core';
45
import { getCurrentScope, getGlobalScope, getIsolationScope, Scope, SDK_VERSION } from '@sentry/core';
56
import { setOpenTelemetryContextAsyncContextStrategy } from '@sentry/opentelemetry';
@@ -321,4 +322,65 @@ describe('NodeClient', () => {
321322
});
322323
});
323324
});
325+
326+
describe('close', () => {
327+
beforeEach(() => {
328+
vi.clearAllMocks();
329+
});
330+
331+
it('shuts down the OTel trace provider', async () => {
332+
const shutdownSpy = vi.fn().mockResolvedValue(true);
333+
const forceFlushSpy = vi.fn().mockResolvedValue(undefined);
334+
335+
const client = new NodeClient(getDefaultNodeClientOptions());
336+
337+
client.traceProvider = {
338+
shutdown: shutdownSpy,
339+
forceFlush: forceFlushSpy,
340+
} as unknown as BasicTracerProvider;
341+
342+
const result = await client.close();
343+
344+
// ensure we return the flush result rather than void from the traceProvider shutdown
345+
expect(result).toBe(true);
346+
347+
expect(shutdownSpy).toHaveBeenCalledTimes(1);
348+
349+
// close calls flush and flush force-flushes the traceProvider
350+
expect(forceFlushSpy).toHaveBeenCalledTimes(1);
351+
});
352+
353+
it('stops client report tracking if it was started', async () => {
354+
const processOffSpy = vi.spyOn(process, 'off');
355+
const clearIntervalSpy = vi.spyOn(globalThis, 'clearInterval');
356+
357+
const client = new NodeClient(getDefaultNodeClientOptions({ sendClientReports: true }));
358+
359+
client.startClientReportTracking();
360+
361+
const result = await client.close();
362+
363+
expect(result).toBe(true);
364+
365+
// once call directly in close to stop client reports,
366+
// the other in core client `_isClientDoneProcessing`
367+
expect(clearIntervalSpy).toHaveBeenCalledTimes(2);
368+
369+
// removes `_clientReportOnExitFlushListener`
370+
expect(processOffSpy).toHaveBeenNthCalledWith(1, 'beforeExit', expect.any(Function));
371+
});
372+
373+
it('stops log capture if it was started', async () => {
374+
const processOffSpy = vi.spyOn(process, 'off');
375+
376+
const client = new NodeClient(getDefaultNodeClientOptions({ enableLogs: true }));
377+
378+
const result = await client.close();
379+
380+
expect(result).toBe(true);
381+
382+
// removes `_logOnExitFlushListener`
383+
expect(processOffSpy).toHaveBeenNthCalledWith(1, 'beforeExit', expect.any(Function));
384+
});
385+
});
324386
});

0 commit comments

Comments
 (0)