public async Task AnalyzeDocumentAsync(Document document, SyntaxNode bodyOpt, CancellationToken cancellationToken) { try { // do nothing if this document is not currently open. // to prevent perf from getting too poor for large projects, only examine open documents. if (!document.IsOpen()) { return; } // Only analyzing C# for now if (document.Project.Language != LanguageNames.CSharp) { return; } List<CompilationErrorDetails> errorDetails = await _errorDetailDiscoverer.GetCompilationErrorDetails(document, bodyOpt, cancellationToken).ConfigureAwait(false); var errorsToReport = _errorDetailCache.GetErrorsToReportAndRecordErrors(document.Id, errorDetails); if (errorsToReport != null) { using (var hashProvider = new SHA256CryptoServiceProvider()) { foreach (CompilationErrorDetails errorDetail in errorsToReport) { var telemetryEvent = TelemetryHelper.TelemetryService.CreateEvent(TelemetryEventPath); telemetryEvent.SetStringProperty(TelemetryErrorId, errorDetail.ErrorId); string projectGuid = _projectGuidCache.GetProjectGuidFromProjectPath(document.Project.FilePath); telemetryEvent.SetStringProperty(TelemetryProjectGuid, string.IsNullOrEmpty(projectGuid) ? UnspecifiedProjectGuid : projectGuid.ToString()); if (!string.IsNullOrEmpty(errorDetail.UnresolvedMemberName)) { telemetryEvent.SetStringProperty(TelemetryUnresolvedMemberName, GetHashedString(errorDetail.UnresolvedMemberName, hashProvider)); } if (!string.IsNullOrEmpty(errorDetail.LeftExpressionDocId)) { telemetryEvent.SetStringProperty(TelemetryLeftExpressionDocId, GetHashedString(errorDetail.LeftExpressionDocId, hashProvider)); } if (!IsArrayNullOrEmpty(errorDetail.LeftExpressionBaseTypeDocIds)) { string telemetryBaseTypes = string.Join(";", errorDetail.LeftExpressionBaseTypeDocIds.Select(docId => GetHashedString(docId, hashProvider))); telemetryEvent.SetStringProperty(TelemetryBaseTypes, telemetryBaseTypes); } if (!IsArrayNullOrEmpty(errorDetail.GenericArguments)) { string telemetryGenericArguments = string.Join(";", errorDetail.GenericArguments.Select(docId => GetHashedString(docId, hashProvider))); telemetryEvent.SetStringProperty(TelemetryGenericArguments, telemetryGenericArguments); } if (!string.IsNullOrEmpty(errorDetail.MethodName)) { telemetryEvent.SetStringProperty(TelemetryMethodName, GetHashedString(errorDetail.MethodName, hashProvider)); } if (!IsArrayNullOrEmpty(errorDetail.ArgumentTypes)) { string telemetryMisMatchedArgumentTypeDocIds = string.Join(";", errorDetail.ArgumentTypes.Select(docId => GetHashedString(docId, hashProvider))); telemetryEvent.SetStringProperty(TelemetryMismatchedArgumentTypeDocIds, telemetryMisMatchedArgumentTypeDocIds); } TelemetryHelper.DefaultTelemetrySession.PostEvent(telemetryEvent); } } } } catch (Exception e) { // The telemetry service itself can throw. // So, to be very careful, put this in a try/catch too. try { var exceptionEvent = TelemetryHelper.TelemetryService.CreateEvent(TelemetryExceptionEventPath); exceptionEvent.SetStringProperty("Type", e.GetTypeDisplayName()); exceptionEvent.SetStringProperty("Message", e.Message); exceptionEvent.SetStringProperty("StackTrace", e.StackTrace); TelemetryHelper.DefaultTelemetrySession.PostEvent(exceptionEvent); } catch { } } }
private static string GetHashedString(string unhashedString, SHA256CryptoServiceProvider hashProvider) { // The point of hashing here is to obscure customer data. // So, if we get any empty values (noone knows why this happens for certain... has only been observed in dumps) // an empty string is fine. It will appear as an extra semicolon in the MD value. if (string.IsNullOrEmpty(unhashedString)) { return string.Empty; } if (TelemetryHelper.DefaultTelemetrySession.CanCollectPrivateInformation()) { return unhashedString; } byte[] theHash = hashProvider.ComputeHash(Encoding.UTF8.GetBytes(unhashedString)); StringBuilder sb = new StringBuilder(theHash.Length); for (int i = 0; i < theHash.Length; i++) { sb.AppendFormat("{0:X}", theHash[i]); } return sb.ToString(); }