@@ -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,35 @@ 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 (
1541+ ( telemetryError : unknown ) => {
1542+ void extLogger . log (
1543+ `Failed to send error telemetry: ${ getErrorMessage ( telemetryError ) } ` ,
1544+ ) ;
1545+ void extLogger . log ( message . fullMessage ) ;
1546+ } ,
1547+ ) ;
1548+ } ;
1549+
1550+ // "uncaughtException" will trigger whenever an exception reaches the top level.
1551+ // This covers extension initialization and any code within a `setTimeout`.
1552+ // Notably this does not include exceptions thrown when executing commands,
1553+ // because `commandRunner` wraps the command body and handles errors.
1554+ process . addListener ( "uncaughtException" , handler ) ;
1555+
1556+ // "unhandledRejection" will trigger whenever any promise is rejected and it is
1557+ // not handled by a "catch" somewhere in the promise chain. This includes when
1558+ // a promise is used with the "void" operator.
1559+ process . addListener ( "unhandledRejection" , handler ) ;
1560+ }
1561+
15321562async function createQueryServer (
15331563 qlConfigurationListener : QueryServerConfigListener ,
15341564 cliServer : CodeQLCliServer ,
0 commit comments