@@ -645,32 +645,64 @@ function reportMacCrashes(): void {
645645 }
646646}
647647
648- function handleCrashFileRead ( err : NodeJS . ErrnoException , data : string ) : void {
648+ function logCrashTelemetry ( data : string ) : void {
649649 let crashObject : { [ key : string ] : string } = { } ;
650+ crashObject [ "CrashingThreadCallStack" ] = data ;
651+ telemetry . logLanguageServerEvent ( "MacCrash" , crashObject , null ) ;
652+ }
653+
654+ function handleCrashFileRead ( err : NodeJS . ErrnoException , data : string ) : void {
650655 if ( err ) {
651- crashObject [ "readFile: err.code" ] = err . code ;
652- telemetry . logLanguageServerEvent ( "MacCrash" , crashObject , null ) ;
653- return ;
656+ return logCrashTelemetry ( "readFile: " + err . code ) ;
654657 }
655- let startCrash : number = data . indexOf ( " Crashed:" ) ;
658+
659+ // Extract the crashing thread's call stack.
660+ const crashStart : string = " Crashed:" ;
661+ let startCrash : number = data . indexOf ( crashStart ) ;
656662 if ( startCrash < 0 ) {
657- startCrash = 0 ;
663+ return logCrashTelemetry ( "No crash start" ) ;
658664 }
665+ startCrash += crashStart . length + 1 ; // Skip past crashStart.
659666 let endCrash : number = data . indexOf ( "Thread " , startCrash ) ;
660- if ( endCrash < startCrash ) {
661- endCrash = data . length - 1 ;
667+ if ( endCrash < 0 ) {
668+ endCrash = data . length - 1 ; // Not expected, but just in case.
669+ }
670+ if ( endCrash <= startCrash ) {
671+ return logCrashTelemetry ( "No crash end" ) ;
662672 }
663673 data = data . substr ( startCrash , endCrash - startCrash ) ;
674+
675+ // Get rid of the memory addresses (which breaks being able get a hit count for each crash call stack).
676+ data = data . replace ( / 0 x ................ / g, "" ) ;
677+
678+ // Get rid of the process names on each line and just add it to the start.
679+ const process1 : string = "Microsoft.VSCode.CPP.IntelliSense.Msvc.darwin\t" ;
680+ const process2 : string = "Microsoft.VSCode.CPP.Extension.darwin\t" ;
681+ if ( data . includes ( process1 ) ) {
682+ data = data . replace ( new RegExp ( process1 , "g" ) , "" ) ;
683+ data = process1 + "\n" + data ;
684+ } else if ( data . includes ( process2 ) ) {
685+ data = data . replace ( new RegExp ( process2 , "g" ) , "" ) ;
686+ data = process2 + "\n" + data ;
687+ } else {
688+ return logCrashTelemetry ( "No process" ) ; // Not expected, but just in case.
689+ }
690+
691+ // Remove runtime lines because they can be different on different machines.
692+ let lines : string [ ] = data . split ( "\n" ) ;
693+ data = "" ;
694+ lines . forEach ( ( line : string ) => {
695+ if ( ! line . includes ( ".dylib" ) && ! line . includes ( "???" ) ) {
696+ data += ( line + "\n" ) ;
697+ }
698+ } ) ;
699+ data = data . trimRight ( ) ;
700+
664701 if ( data . length > 8192 ) { // The API has an 8k limit.
665702 data = data . substr ( 0 , 8189 ) + "..." ;
666703 }
667- if ( data . length < 2 ) {
668- return ; // Don't send telemetry if there's no call stack.
669- }
670- // Get rid of the memory addresses (which breaks being able get a hit count for each crash call stack).
671- data = data . replace ( / 0 x ................ / g, "" ) ;
672- crashObject [ "CrashingThreadCallStack" ] = data ;
673- telemetry . logLanguageServerEvent ( "MacCrash" , crashObject , null ) ;
704+
705+ logCrashTelemetry ( data ) ;
674706}
675707
676708export function deactivate ( ) : Thenable < void > {
0 commit comments