diff --git a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs index 96f7f0d54a..905919f4ce 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs @@ -25,10 +25,11 @@ open FSharp.Compiler.EditorServices open FSharp.Compiler.Text open FSharp.Compiler.Text.Range open FSharp.Compiler.Symbols -open FSharp.Compiler.Tokenization open System.Composition open System.Text.RegularExpressions open CancellableTasks +open Microsoft.VisualStudio.FSharp.Editor.Telemetry +open Microsoft.VisualStudio.Telemetry module private Symbol = let fullName (root: ISymbol) : string = @@ -679,6 +680,9 @@ type internal FSharpNavigation(metadataAsSource: FSharpMetadataAsSourceService, // Task.Wait throws an exception if the task is cancelled, so be sure to catch it. try // This call to Wait() is fine because we want to be able to provide the error message in the status bar. + use _ = + TelemetryReporter.ReportSingleEventWithDuration(TelemetryEvents.GoToDefinition, [||]) + gtdTask.Wait(cancellationToken) if gtdTask.Status = TaskStatus.RanToCompletion && gtdTask.Result.IsSome then @@ -695,6 +699,7 @@ type internal FSharpNavigation(metadataAsSource: FSharpMetadataAsSourceService, statusBar.TempMessage(SR.CannotDetermineSymbol()) false with exc -> + TelemetryReporter.ReportFault(TelemetryEvents.GoToDefinition, FaultSeverity.General, exc) statusBar.TempMessage(String.Format(SR.NavigateToFailed(), Exception.flattenMessage exc)) // Don't show the dialog box as it's most likely that the user cancelled. diff --git a/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs b/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs index 99a07f8fd1..ab7a4b6a29 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/NavigableSymbolsService.fs @@ -14,6 +14,8 @@ open Microsoft.VisualStudio.Language.Intellisense open Microsoft.VisualStudio.Text open Microsoft.VisualStudio.Text.Editor open Microsoft.VisualStudio.Utilities +open Microsoft.VisualStudio.FSharp.Editor.Telemetry +open Microsoft.VisualStudio.Telemetry [] type internal FSharpNavigableSymbol(item: FSharpNavigableItem, span: SnapshotSpan, gtd: GoToDefinition) = @@ -52,6 +54,9 @@ type internal FSharpNavigableSymbolSource(metadataAsSource) = // Task.Wait throws an exception if the task is cancelled, so be sure to catch it. try // This call to Wait() is fine because we want to be able to provide the error message in the status bar. + use _ = + TelemetryReporter.ReportSingleEventWithDuration(TelemetryEvents.GoToDefinitionGetSymbol, [||]) + gtdTask.Wait(cancellationToken) statusBar.Clear() @@ -88,6 +93,8 @@ type internal FSharpNavigableSymbolSource(metadataAsSource) = // The NavigableSymbols API accepts 'null' when there's nothing to navigate to. return null with exc -> + TelemetryReporter.ReportFault(TelemetryEvents.GoToDefinitionGetSymbol, FaultSeverity.General, exc) + statusBar.TempMessage(String.Format(SR.NavigateToFailed(), Exception.flattenMessage exc)) // The NavigableSymbols API accepts 'null' when there's nothing to navigate to. diff --git a/vsintegration/src/FSharp.Editor/Telemetry/TelemetryReporter.fs b/vsintegration/src/FSharp.Editor/Telemetry/TelemetryReporter.fs index 753274a26e..fae5dde779 100644 --- a/vsintegration/src/FSharp.Editor/Telemetry/TelemetryReporter.fs +++ b/vsintegration/src/FSharp.Editor/Telemetry/TelemetryReporter.fs @@ -25,10 +25,10 @@ module TelemetryEvents = let LanguageServiceStarted = "languageservicestarted" [] - let GetSymbolUsesInProjectsStarted = "getSymbolUsesInProjectsStarted" + let GetSymbolUsesInProjectsStarted = "getsymbolusesinprojectsstarted" [] - let GetSymbolUsesInProjectsFinished = "getSymbolUsesInProjectsFinished" + let GetSymbolUsesInProjectsFinished = "getsymbolusesinprojectsfinished" [] let AddSyntacticCalssifications = "addsyntacticclassifications" @@ -42,6 +42,12 @@ module TelemetryEvents = [] let ProvideCompletions = "providecompletions" + [] + let GoToDefinition = "gotodefinition" + + [] + let GoToDefinitionGetSymbol = "gotodefinition/getsymbol" + // TODO: needs to be something more sophisticated in future [] type TelemetryThrottlingStrategy = @@ -92,15 +98,36 @@ type TelemetryReporter private (name: string, props: (string * obj) array, stopw (let componentModel = Package.GetGlobalService(typeof) :?> ComponentModelHost.IComponentModel - if componentModel = null then + if isNull componentModel then TelemetryService.DefaultSession.IsUserMicrosoftInternal else let workspace = componentModel.GetService() - workspace.Services.GetService().Advanced.SendAdditionalTelemetry) + + TelemetryService.DefaultSession.IsUserMicrosoftInternal + || workspace.Services.GetService().Advanced.SendAdditionalTelemetry) + + static member ReportFault(name, ?severity: FaultSeverity, ?e: exn) = + if TelemetryReporter.SendAdditionalTelemetry.Value then + let faultName = String.Concat(name, "/fault") + + match severity, e with + | Some s, Some e -> TelemetryService.DefaultSession.PostFault(faultName, name, s, e) + | None, Some e -> TelemetryService.DefaultSession.PostFault(faultName, name, e) + | Some s, None -> TelemetryService.DefaultSession.PostFault(faultName, name, s) + | None, None -> TelemetryService.DefaultSession.PostFault(faultName, name) + |> ignore + + static member ReportCustomFailure(name, ?props) = + if TelemetryReporter.SendAdditionalTelemetry.Value then + let props = defaultArg props [||] + let name = String.Concat(name, "/failure") + let event = TelemetryReporter.createEvent name props + TelemetryService.DefaultSession.PostEvent event static member ReportSingleEvent(name, props) = - let event = TelemetryReporter.createEvent name props - TelemetryService.DefaultSession.PostEvent event + if TelemetryReporter.SendAdditionalTelemetry.Value then + let event = TelemetryReporter.createEvent name props + TelemetryService.DefaultSession.PostEvent event // A naïve implementation using stopwatch and returning an IDisposable // TODO: needs a careful review, since it will be a hot path when we are sending telemetry @@ -108,10 +135,7 @@ type TelemetryReporter private (name: string, props: (string * obj) array, stopw let additionalTelemetryEnabled = TelemetryReporter.SendAdditionalTelemetry.Value - let isUserMicrosoftInternal = - TelemetryService.DefaultSession.IsUserMicrosoftInternal - - if additionalTelemetryEnabled || isUserMicrosoftInternal then + if additionalTelemetryEnabled then let throttlingStrategy = defaultArg throttlingStrategy TelemetryThrottlingStrategy.Default