From 948583b8b62507895b98e725c28b3fdb48faadbd Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Sat, 23 Sep 2023 17:09:35 +0100 Subject: [PATCH] Add support for Cron check-ins (#210) * Add support for Cron check-ins * Create heavy-hounds-love.md --------- Co-authored-by: Robert Cepa --- .changeset/heavy-hounds-love.md | 5 ++ packages/toucan-js/package.json | 8 +-- packages/toucan-js/src/client.ts | 4 +- packages/toucan-js/src/sdk.ts | 23 ++++++++- packages/toucan-js/test/index.spec.ts | 74 +++++++++++++++++++++++++++ yarn.lock | 42 +++++++-------- 6 files changed, 128 insertions(+), 28 deletions(-) create mode 100644 .changeset/heavy-hounds-love.md diff --git a/.changeset/heavy-hounds-love.md b/.changeset/heavy-hounds-love.md new file mode 100644 index 00000000..a98a60ea --- /dev/null +++ b/.changeset/heavy-hounds-love.md @@ -0,0 +1,5 @@ +--- +"toucan-js": minor +--- + +Add support for Cron check-ins diff --git a/packages/toucan-js/package.json b/packages/toucan-js/package.json index 946aaa7e..231ce54b 100644 --- a/packages/toucan-js/package.json +++ b/packages/toucan-js/package.json @@ -29,10 +29,10 @@ "serverless" ], "dependencies": { - "@sentry/core": "7.65.0", - "@sentry/utils": "7.65.0", - "@sentry/types": "7.65.0", - "@sentry/integrations": "7.65.0" + "@sentry/core": "7.69.0", + "@sentry/utils": "7.69.0", + "@sentry/types": "7.69.0", + "@sentry/integrations": "7.69.0" }, "devDependencies": { "@rollup/plugin-commonjs": "25.0.3", diff --git a/packages/toucan-js/src/client.ts b/packages/toucan-js/src/client.ts index adb73df7..2f9e46c4 100644 --- a/packages/toucan-js/src/client.ts +++ b/packages/toucan-js/src/client.ts @@ -1,5 +1,5 @@ import type { Scope } from '@sentry/core'; -import { BaseClient } from '@sentry/core'; +import { ServerRuntimeClient } from '@sentry/core'; import type { Event, EventHint, SeverityLevel } from '@sentry/types'; import { resolvedSyncPromise } from '@sentry/utils'; import { eventFromMessage, eventFromUnknownInput } from './eventBuilder'; @@ -11,7 +11,7 @@ import { setOnOptional } from './utils'; /** * The Cloudflare Workers SDK Client. */ -export class ToucanClient extends BaseClient { +export class ToucanClient extends ServerRuntimeClient { /** * Some functions need to access the Hub (Toucan instance) this client is bound to, * but calling 'getCurrentHub()' is unsafe because it uses globals. diff --git a/packages/toucan-js/src/sdk.ts b/packages/toucan-js/src/sdk.ts index b21750c2..d4ec5f0e 100644 --- a/packages/toucan-js/src/sdk.ts +++ b/packages/toucan-js/src/sdk.ts @@ -1,4 +1,4 @@ -import { getIntegrationsToSetup, Hub } from '@sentry/core'; +import { getIntegrationsToSetup, Hub, Scope } from '@sentry/core'; import { stackParserFromStackParserOptions } from '@sentry/utils'; import { ToucanClient } from './client'; import { LinkedErrors, RequestData } from './integrations'; @@ -6,6 +6,7 @@ import { defaultStackParser } from './stacktrace'; import { makeFetchTransport } from './transports'; import type { Options } from './types'; import { getSentryRelease } from './utils'; +import { CheckIn, MonitorConfig } from '@sentry/types'; /** * The Cloudflare Workers SDK. @@ -70,4 +71,24 @@ export class Toucan extends Hub { setEnabled(enabled: boolean): void { this.getClient()?.setEnabled(enabled); } + + /** + * 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. + */ + captureCheckIn( + checkIn: CheckIn, + monitorConfig?: MonitorConfig, + scope?: Scope, + ): string { + if (checkIn.status === 'in_progress') { + this.setContext('monitor', { slug: checkIn.monitorSlug }); + } + + const client = this.getClient() as ToucanClient; + return client.captureCheckIn(checkIn, monitorConfig, scope); + } } diff --git a/packages/toucan-js/test/index.spec.ts b/packages/toucan-js/test/index.spec.ts index f007723f..10e2acb3 100644 --- a/packages/toucan-js/test/index.spec.ts +++ b/packages/toucan-js/test/index.spec.ts @@ -565,6 +565,80 @@ describe('Toucan', () => { }); }); + describe('captureCheckIn', () => { + test(`is sent`, async () => { + const toucan = new Toucan({ + dsn: VALID_DSN, + context, + }); + + const checkInId = toucan.captureCheckIn({ + monitorSlug: 'my_job', + status: 'in_progress', + }); + + toucan.captureCheckIn({ + checkInId: checkInId, + monitorSlug: 'my_job', + status: 'error', + }); + + const waitUntilResults = await getMiniflareWaitUntil(context); + + expect(waitUntilResults.length).toBe(2); + expect(requests.length).toBe(2); + + const requestBody = await requests[0].envelopePayload(); + + expect(requestBody).toEqual({ + check_in_id: checkInId, + monitor_slug: 'my_job', + status: 'in_progress', + }); + + const requestBody2 = await requests[1].envelopePayload(); + + expect(requestBody2).toEqual({ + check_in_id: checkInId, + monitor_slug: 'my_job', + status: 'error', + }); + + expect(requestBody.check_in_id).toBe(requestBody2.check_in_id); + }); + + test(`is linked to errors`, async () => { + const toucan = new Toucan({ + dsn: VALID_DSN, + context, + }); + + const checkInId = toucan.captureCheckIn({ + monitorSlug: 'my_job', + status: 'in_progress', + }); + + toucan.captureMessage('test'); + + const waitUntilResults = await getMiniflareWaitUntil(context); + + expect(waitUntilResults.length).toBe(2); + expect(requests.length).toBe(2); + + const checkInRequestBody = await requests[0].envelopePayload(); + + expect(checkInRequestBody).toEqual({ + check_in_id: checkInId, + monitor_slug: 'my_job', + status: 'in_progress', + }); + + const errorRequestBody = await requests[1].envelopePayload(); + + expect(errorRequestBody.contexts.monitor).toEqual({ slug: 'my_job' }); + }); + }); + describe('addBreadcrumb', () => { test('captures last 100 breadcrumbs by default', async () => { const toucan = new Toucan({ diff --git a/yarn.lock b/yarn.lock index 96ee34a5..1e4b93c5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1610,13 +1610,13 @@ "@sentry/utils" "7.23.0" tslib "^1.9.3" -"@sentry/core@7.65.0": - version "7.65.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.65.0.tgz#01c1320b4e7c62ccf757258c1622d07cc743468a" - integrity sha512-EwZABW8CtAbRGXV69FqeCqcNApA+Jbq308dko0W+MFdFe+9t2RGubUkpPxpJcbWy/dN2j4LiuENu1T7nWn0ZAQ== +"@sentry/core@7.69.0": + version "7.69.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.69.0.tgz#ebbe01df573f438f8613107020a4e18eb9adca4d" + integrity sha512-V6jvK2lS8bhqZDMFUtvwe2XvNstFQf5A+2LMKCNBOV/NN6eSAAd6THwEpginabjet9dHsNRmMk7WNKvrUfQhZw== dependencies: - "@sentry/types" "7.65.0" - "@sentry/utils" "7.65.0" + "@sentry/types" "7.69.0" + "@sentry/utils" "7.69.0" tslib "^2.4.1 || ^1.9.3" "@sentry/esbuild-plugin@^0.2.3": @@ -1626,13 +1626,13 @@ dependencies: "@sentry/bundler-plugin-core" "0.2.3" -"@sentry/integrations@7.65.0": - version "7.65.0" - resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.65.0.tgz#aeae18b9faa7db3a1d52e74085eebe7e825aab72" - integrity sha512-9b54p0UrkWe9+RAWWTObJQ2k/uStqaUj7BkNFyuaxfKQ4IZViqc4Sa7d7zX2X1oynGNL3ic7iqcgVTh7NvNsAQ== +"@sentry/integrations@7.69.0": + version "7.69.0" + resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.69.0.tgz#04c0206d9436ec7b79971e3bde5d6e1e9194595f" + integrity sha512-FEFtFqXuCo9+L7bENZxFpEAlIODwHl6FyW/DwLfniy9jOXHU7BhP/oICLrFE5J7rh1gNY7N/8VlaiQr3hCnS/g== dependencies: - "@sentry/types" "7.65.0" - "@sentry/utils" "7.65.0" + "@sentry/types" "7.69.0" + "@sentry/utils" "7.69.0" localforage "^1.8.1" tslib "^2.4.1 || ^1.9.3" @@ -1671,10 +1671,10 @@ resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.23.0.tgz#5d2ce94d81d7c1fad702645306f3c0932708cad5" integrity sha512-fZ5XfVRswVZhKoCutQ27UpIHP16tvyc6ws+xq+njHv8Jg8gFBCoOxlJxuFhegD2xxylAn1aiSHNAErFWdajbpA== -"@sentry/types@7.65.0": - version "7.65.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.65.0.tgz#f0f4e6583c631408d15ee5fb46901fd195fa1cc4" - integrity sha512-YYq7IDLLhpSBTmHoyWFtq/5ZDaEJ01r7xGuhB0aSIq33cm2I7im/B3ipzoOP/ukGZSIhuYVW9t531xZEO0+6og== +"@sentry/types@7.69.0": + version "7.69.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.69.0.tgz#012b8d90d270a473cc2a5cf58a56870542739292" + integrity sha512-zPyCox0mzitzU6SIa1KIbNoJAInYDdUpdiA+PoUmMn2hFMH1llGU/cS7f4w/mAsssTlbtlBi72RMnWUCy578bw== "@sentry/utils@7.23.0": version "7.23.0" @@ -1684,12 +1684,12 @@ "@sentry/types" "7.23.0" tslib "^1.9.3" -"@sentry/utils@7.65.0": - version "7.65.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.65.0.tgz#a7929c5b019fa33e819b08a99744fa27cd38c85f" - integrity sha512-2JEBf4jzRSClhp+LJpX/E3QgHEeKvXqFMeNhmwQ07qqd6szhfH2ckYFj4gXk6YiGGY4Act3C6oxLfdZovG71bw== +"@sentry/utils@7.69.0": + version "7.69.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.69.0.tgz#b7594e4eb2a88b9b25298770b841dd3f81bd2aa4" + integrity sha512-4eBixe5Y+0EGVU95R4NxH3jkkjtkE4/CmSZD4In8SCkWGSauogePtq6hyiLsZuP1QHdpPb9Kt0+zYiBb2LouBA== dependencies: - "@sentry/types" "7.65.0" + "@sentry/types" "7.69.0" tslib "^2.4.1 || ^1.9.3" "@sentry/vite-plugin@^0.2.3":