Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions packages/node-core/src/sdk/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,7 @@ export class NodeClient extends ServerRuntimeClient<NodeClientOptions> {
// Eslint ignore explanation: This is already documented in super.
// eslint-disable-next-line jsdoc/require-jsdoc
public async flush(timeout?: number): Promise<boolean> {
const provider = this.traceProvider;

await provider?.forceFlush();
await this.traceProvider?.forceFlush();

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

return super.close(timeout);
return super
.close(timeout)
.then(allEventsSent =>
this.traceProvider ? this.traceProvider.shutdown().then(() => allEventsSent) : allEventsSent,
);
}

/**
Expand Down
62 changes: 62 additions & 0 deletions packages/node-core/test/sdk/client.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ProxyTracer } from '@opentelemetry/api';
import * as opentelemetryInstrumentationPackage from '@opentelemetry/instrumentation';
import type { BasicTracerProvider } from '@opentelemetry/sdk-trace-base';
import type { Event, EventHint, Log } from '@sentry/core';
import { getCurrentScope, getGlobalScope, getIsolationScope, Scope, SDK_VERSION } from '@sentry/core';
import { setOpenTelemetryContextAsyncContextStrategy } from '@sentry/opentelemetry';
Expand Down Expand Up @@ -321,4 +322,65 @@ describe('NodeClient', () => {
});
});
});

describe('close', () => {
beforeEach(() => {
vi.clearAllMocks();
});

it('shuts down the OTel trace provider', async () => {
const shutdownSpy = vi.fn().mockResolvedValue(true);
const forceFlushSpy = vi.fn().mockResolvedValue(undefined);

const client = new NodeClient(getDefaultNodeClientOptions());

client.traceProvider = {
shutdown: shutdownSpy,
forceFlush: forceFlushSpy,
} as unknown as BasicTracerProvider;

const result = await client.close();

// ensure we return the flush result rather than void from the traceProvider shutdown
expect(result).toBe(true);

expect(shutdownSpy).toHaveBeenCalledTimes(1);

// close calls flush and flush force-flushes the traceProvider
expect(forceFlushSpy).toHaveBeenCalledTimes(1);
});

it('stops client report tracking if it was started', async () => {
const processOffSpy = vi.spyOn(process, 'off');
const clearIntervalSpy = vi.spyOn(globalThis, 'clearInterval');

const client = new NodeClient(getDefaultNodeClientOptions({ sendClientReports: true }));

client.startClientReportTracking();

const result = await client.close();

expect(result).toBe(true);

// once call directly in close to stop client reports,
// the other in core client `_isClientDoneProcessing`
expect(clearIntervalSpy).toHaveBeenCalledTimes(2);

// removes `_clientReportOnExitFlushListener`
expect(processOffSpy).toHaveBeenNthCalledWith(1, 'beforeExit', expect.any(Function));
});

it('stops log capture if it was started', async () => {
const processOffSpy = vi.spyOn(process, 'off');

const client = new NodeClient(getDefaultNodeClientOptions({ enableLogs: true }));

const result = await client.close();

expect(result).toBe(true);

// removes `_logOnExitFlushListener`
expect(processOffSpy).toHaveBeenNthCalledWith(1, 'beforeExit', expect.any(Function));
});
});
});
Loading