diff --git a/packages/node/src/checkin.ts b/packages/core/src/checkin.ts similarity index 100% rename from packages/node/src/checkin.ts rename to packages/core/src/checkin.ts diff --git a/packages/core/src/exports.ts b/packages/core/src/exports.ts index 72a5f8587f94..207cfde505b6 100644 --- a/packages/core/src/exports.ts +++ b/packages/core/src/exports.ts @@ -1,17 +1,20 @@ import type { Breadcrumb, CaptureContext, + CheckIn, CustomSamplingContext, Event, EventHint, Extra, Extras, + MonitorConfig, Primitive, Severity, SeverityLevel, TransactionContext, User, } from '@sentry/types'; +import { logger, uuid4 } from '@sentry/utils'; import type { Hub } from './hub'; import { getCurrentHub } from './hub'; @@ -184,3 +187,26 @@ export function startTransaction( ): ReturnType { return getCurrentHub().startTransaction({ ...context }, customSamplingContext); } + +/** + * Create a cron monitor check in and send it to Sentry. + * + * @param checkIn An object that describes a check in. + * @param upsertMonitorConfig An optional object that describes a monitor config. Use this if you want + * to create a monitor automatically when sending a check in. + */ +export function captureCheckIn(checkIn: CheckIn, upsertMonitorConfig?: MonitorConfig): string { + const capturedCheckIn = + checkIn.status !== 'in_progress' && checkIn.checkInId ? checkIn : { ...checkIn, checkInId: uuid4() }; + + const client = getCurrentHub().getClient(); + if (!client) { + __DEBUG_BUILD__ && logger.warn('Cannot capture check-in. No client defined.'); + } else if (!client.captureCheckIn) { + __DEBUG_BUILD__ && logger.warn('Cannot capture check-in. Client does not support sending check-ins.'); + } else { + client.captureCheckIn(capturedCheckIn, upsertMonitorConfig); + } + + return capturedCheckIn.checkInId; +} diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 1acf0264f69b..db9d21c2f2e8 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -17,6 +17,7 @@ export { setTags, setUser, withScope, + captureCheckIn, } from './exports'; export { getCurrentHub, @@ -42,6 +43,7 @@ export { SDK_VERSION } from './version'; export { getIntegrationsToSetup } from './integration'; export { FunctionToString, InboundFilters } from './integrations'; export { prepareEvent } from './utils/prepareEvent'; +export { createCheckInEnvelope } from './checkin'; export { hasTracingEnabled } from './utils/hasTracingEnabled'; export { DEFAULT_ENVIRONMENT } from './constants'; diff --git a/packages/node/test/checkin.test.ts b/packages/core/test/lib/checkin.test.ts similarity index 96% rename from packages/node/test/checkin.test.ts rename to packages/core/test/lib/checkin.test.ts index 9fe59ad66971..38a8fce56e95 100644 --- a/packages/node/test/checkin.test.ts +++ b/packages/core/test/lib/checkin.test.ts @@ -1,8 +1,8 @@ import type { SerializedCheckIn } from '@sentry/types'; -import { createCheckInEnvelope } from '../src/checkin'; +import { createCheckInEnvelope } from '../../src/checkin'; -describe('CheckIn', () => { +describe('createCheckInEnvelope', () => { test('creates a check in envelope header', () => { const envelope = createCheckInEnvelope( { diff --git a/packages/core/test/lib/sdk.test.ts b/packages/core/test/lib/sdk.test.ts index c2838d7ed115..46c694951ab2 100644 --- a/packages/core/test/lib/sdk.test.ts +++ b/packages/core/test/lib/sdk.test.ts @@ -1,4 +1,4 @@ -import { Scope } from '@sentry/core'; +import { captureCheckIn, getCurrentHub } from '@sentry/core'; import type { Client, Integration } from '@sentry/types'; import { installedIntegrations } from '../../src/integration'; @@ -10,31 +10,6 @@ declare var global: any; const PUBLIC_DSN = 'https://username@domain/123'; -jest.mock('@sentry/core', () => { - const original = jest.requireActual('@sentry/core'); - return { - ...original, - getCurrentHub(): { - bindClient(client: Client): boolean; - getClient(): boolean; - getScope(): Scope; - } { - return { - getClient(): boolean { - return false; - }, - getScope(): Scope { - return new Scope(); - }, - bindClient(client: Client): boolean { - client.setupIntegrations(); - return true; - }, - }; - }, - }; -}); - export class MockIntegration implements Integration { public name: string; public setupOnce: () => void = jest.fn(); @@ -62,3 +37,23 @@ describe('SDK', () => { }); }); }); + +describe('captureCheckIn', () => { + it('returns an id when client is defined', () => { + const hub = getCurrentHub(); + jest.spyOn(hub, 'getClient').mockImplementation(() => { + return { + captureCheckIn: () => 'some-id-wasd-1234', + } as unknown as Client; + }); + + expect(captureCheckIn({ monitorSlug: 'gogogo', status: 'in_progress' })).toStrictEqual(expect.any(String)); + }); + + it('returns an id when client is undefined', () => { + const hub = getCurrentHub(); + jest.spyOn(hub, 'getClient').mockImplementation(() => undefined); + + expect(captureCheckIn({ monitorSlug: 'gogogo', status: 'in_progress' })).toStrictEqual(expect.any(String)); + }); +}); diff --git a/packages/node/src/client.ts b/packages/node/src/client.ts index af39f786ac3c..7424e4b10a26 100644 --- a/packages/node/src/client.ts +++ b/packages/node/src/client.ts @@ -1,5 +1,5 @@ import type { Scope } from '@sentry/core'; -import { addTracingExtensions, BaseClient, SDK_VERSION, SessionFlusher } from '@sentry/core'; +import { addTracingExtensions, BaseClient, createCheckInEnvelope, SDK_VERSION, SessionFlusher } from '@sentry/core'; import type { CheckIn, Event, @@ -13,7 +13,6 @@ import { logger, resolvedSyncPromise, uuid4 } from '@sentry/utils'; import * as os from 'os'; import { TextEncoder } from 'util'; -import { createCheckInEnvelope } from './checkin'; import { eventFromMessage, eventFromUnknownInput } from './eventbuilder'; import type { NodeClientOptions } from './types'; diff --git a/packages/node/src/index.ts b/packages/node/src/index.ts index b9e6202b9496..0e57936a02a9 100644 --- a/packages/node/src/index.ts +++ b/packages/node/src/index.ts @@ -50,22 +50,14 @@ export { spanStatusfromHttpCode, trace, withScope, + captureCheckIn, } from '@sentry/core'; export type { SpanStatusType } from '@sentry/core'; export { autoDiscoverNodePerformanceMonitoringIntegrations } from './tracing'; export { NodeClient } from './client'; export { makeNodeTransport } from './transports'; -export { - defaultIntegrations, - init, - defaultStackParser, - lastEventId, - flush, - close, - getSentryRelease, - captureCheckIn, -} from './sdk'; +export { defaultIntegrations, init, defaultStackParser, lastEventId, flush, close, getSentryRelease } from './sdk'; export { addRequestDataToEvent, DEFAULT_USER_INCLUDES, extractRequestData } from './requestdata'; export { deepReadDirSync } from './utils'; diff --git a/packages/node/src/sdk.ts b/packages/node/src/sdk.ts index d4e2df4ac5f9..d0a02c746247 100644 --- a/packages/node/src/sdk.ts +++ b/packages/node/src/sdk.ts @@ -6,14 +6,13 @@ import { initAndBind, Integrations as CoreIntegrations, } from '@sentry/core'; -import type { CheckIn, MonitorConfig, SessionStatus, StackParser } from '@sentry/types'; +import type { SessionStatus, StackParser } from '@sentry/types'; import { createStackParser, GLOBAL_OBJ, logger, nodeStackLineParser, stackParserFromStackParserOptions, - uuid4, } from '@sentry/utils'; import { setNodeAsyncContextStrategy } from './async'; @@ -263,30 +262,6 @@ export function getSentryRelease(fallback?: string): string | undefined { ); } -/** - * Create a cron monitor check in and send it to Sentry. - * - * @param checkIn An object that describes a check in. - * @param upsertMonitorConfig An optional object that describes a monitor config. Use this if you want - * to create a monitor automatically when sending a check in. - */ -export function captureCheckIn( - checkIn: CheckIn, - upsertMonitorConfig?: MonitorConfig, -): ReturnType { - const capturedCheckIn = - checkIn.status !== 'in_progress' && checkIn.checkInId ? checkIn : { ...checkIn, checkInId: uuid4() }; - - const client = getCurrentHub().getClient(); - if (client) { - client.captureCheckIn(capturedCheckIn, upsertMonitorConfig); - } else { - __DEBUG_BUILD__ && logger.warn('Cannot capture check in. No client defined.'); - } - - return capturedCheckIn.checkInId; -} - /** Node.js stack parser */ export const defaultStackParser: StackParser = createStackParser(nodeStackLineParser(getModule)); diff --git a/packages/node/test/sdk.test.ts b/packages/node/test/sdk.test.ts index f7c2595c66a5..abd0265b62c4 100644 --- a/packages/node/test/sdk.test.ts +++ b/packages/node/test/sdk.test.ts @@ -1,7 +1,5 @@ -import { getCurrentHub } from '@sentry/core'; import type { Integration } from '@sentry/types'; -import type { NodeClient } from '../build/types'; import { init } from '../src/sdk'; import * as sdk from '../src/sdk'; @@ -92,21 +90,3 @@ describe('init()', () => { expect(newIntegration.setupOnce as jest.Mock).toHaveBeenCalledTimes(1); }); }); - -describe('captureCheckIn', () => { - it('always returns an id', () => { - const hub = getCurrentHub(); - const client = hub.getClient(); - expect(client).toBeDefined(); - - const captureCheckInSpy = jest.spyOn(client!, 'captureCheckIn'); - - // test if captureCheckIn returns an id even if client is not defined - hub.bindClient(undefined); - - expect(captureCheckInSpy).toHaveBeenCalledTimes(0); - expect(sdk.captureCheckIn({ monitorSlug: 'gogogo', status: 'in_progress' })).toBeTruthy(); - - hub.bindClient(client); - }); -}); diff --git a/packages/types/src/client.ts b/packages/types/src/client.ts index d455c4a7590b..831b1c10e9f2 100644 --- a/packages/types/src/client.ts +++ b/packages/types/src/client.ts @@ -1,4 +1,5 @@ import type { Breadcrumb, BreadcrumbHint } from './breadcrumb'; +import type { CheckIn, MonitorConfig } from './checkin'; import type { EventDropReason } from './clientreport'; import type { DataCategory } from './datacategory'; import type { DsnComponents } from './dsn'; @@ -67,6 +68,16 @@ export interface Client { */ captureSession?(session: Session): void; + /** + * Create a cron monitor check in and send it to Sentry. This method is not available on all clients. + * + * @param checkIn An object that describes a check in. + * @param upsertMonitorConfig An optional object that describes a monitor config. Use this if you want + * to create a monitor automatically when sending a check in. + * @returns A string representing the id of the check in. + */ + captureCheckIn?(checkIn: CheckIn, monitorConfig?: MonitorConfig): string; + /** Returns the current Dsn. */ getDsn(): DsnComponents | undefined;