diff --git a/developer/src/common/web/utils/src/utils/KeymanSentry.ts b/developer/src/common/web/utils/src/utils/KeymanSentry.ts index 94409eafc8..dfe62bfa3d 100644 --- a/developer/src/common/web/utils/src/utils/KeymanSentry.ts +++ b/developer/src/common/web/utils/src/utils/KeymanSentry.ts @@ -64,11 +64,17 @@ export class KeymanSentry { } } - static async captureException(e: any): Promise { + /** + * capture an exception for Sentry; note that in local environments, this will normally + * throw the exception rather than sending to Sentry + * @param e + * @param force if true, reports to Sentry even in local environments + */ + static async captureException(e: any, force?: boolean): Promise { if(isInit) { // For local development, we don't want to bury the trace; we need the cast to avoid // TS2367 (comparison appears to be unintentional) - if((KEYMAN_VERSION.VERSION_ENVIRONMENT as string) == 'local') { + if(!force && (KEYMAN_VERSION.VERSION_ENVIRONMENT as string) == 'local') { throw e; } diff --git a/developer/src/kmc/src/util/TestKeymanSentry.ts b/developer/src/kmc/src/util/TestKeymanSentry.ts index 430ab73d68..b8572516bd 100644 --- a/developer/src/kmc/src/util/TestKeymanSentry.ts +++ b/developer/src/kmc/src/util/TestKeymanSentry.ts @@ -43,7 +43,7 @@ export class TestKeymanSentry { try { throw new Error('Test error from -sentry-client-test-exception event'); } catch(e: any) { - await KeymanSentry.captureException(e); + await KeymanSentry.captureException(e, true); } } } diff --git a/developer/src/kmc/src/util/kmcSentryOptions.ts b/developer/src/kmc/src/util/kmcSentryOptions.ts index bbb5c09a87..c6c47f732f 100644 --- a/developer/src/kmc/src/util/kmcSentryOptions.ts +++ b/developer/src/kmc/src/util/kmcSentryOptions.ts @@ -1,5 +1,19 @@ +import Sentry from "@sentry/node"; +import * as process from "node:process"; import { SentryNodeOptions } from "@keymanapp/developer-utils"; +Sentry.setContext('Command Line', { + // obfusate parameters with longer paths e.g. from 'c:/users/name/a/b' to + // '…/a/b' to minimize PII risk without losing all command line data. + // Also normalizes backslashes to slashes for simplicity. + argv: process.argv.map(param => { + const p = param.replaceAll('\\', '/').split('/'); + return (p.length < 3) + ? param + : ("…/" + p.slice(-2).join('/')); + }).join(' ') +}); + /** * Rewrites sourcemap paths for the esbuild distribution of kmc (as used in * Keyman Developer itself) //kmc.mjs to /dist/kmc.mjs, so that