@@ -236,6 +236,7 @@ export async function activate(
236236 const distributionConfigListener = new DistributionConfigListener ( ) ;
237237 await initializeLogging ( ctx ) ;
238238 await initializeTelemetry ( extension , ctx ) ;
239+ addUnhandledRejectionListener ( ) ;
239240 install ( ) ;
240241
241242 const codelensProvider = new QuickEvalCodeLensProvider ( ) ;
@@ -1529,6 +1530,33 @@ async function activateWithInstalledDistribution(
15291530 } ;
15301531}
15311532
1533+ function addUnhandledRejectionListener ( ) {
1534+ const handler = ( error : unknown ) => {
1535+ const message = redactableError (
1536+ asError ( error ) ,
1537+ ) `Unhandled error: ${ getErrorMessage ( error ) } ` ;
1538+ // Add a catch so that showAndLogExceptionWithTelemetry fails, we avoid
1539+ // triggering "unhandledRejection" and avoid an infinite loop
1540+ showAndLogExceptionWithTelemetry ( message ) . catch ( ( error : unknown ) => {
1541+ void extLogger . log (
1542+ `Failed to send error telemetry: ${ getErrorMessage ( error ) } ` ,
1543+ ) ;
1544+ void extLogger . log ( message . fullMessage ) ;
1545+ } ) ;
1546+ } ;
1547+
1548+ // "uncaughtException" will trigger whenever an exception reaches the top level.
1549+ // This covers extension initialization and any code within a `setTimeout`.
1550+ // Notably this does not include exceptions thrown when executing commands,
1551+ // because `commandRunner` wraps the command body and handles errors.
1552+ process . addListener ( "uncaughtException" , handler ) ;
1553+
1554+ // "unhandledRejection" will trigger whenever any promise is rejected and it is
1555+ // not handled by a "catch" somewhere in the promise chain. This includes when
1556+ // a promise is used with the "void" operator.
1557+ process . addListener ( "unhandledRejection" , handler ) ;
1558+ }
1559+
15321560async function createQueryServer (
15331561 qlConfigurationListener : QueryServerConfigListener ,
15341562 cliServer : CodeQLCliServer ,
0 commit comments