diff --git a/eng/Versions.props b/eng/Versions.props
index 7ab37a7343..c70d7b69fb 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -110,6 +110,7 @@
$(MicrosoftVisualStudioShellPackagesVersion)
$(MicrosoftVisualStudioShellPackagesVersion)
17.3.3-alpha
+ 16.4.137
$(MicrosoftVisualStudioPackagesVersion)
$(MicrosoftVisualStudioPackagesVersion)
$(MicrosoftVisualStudioPackagesVersion)
diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer.Common/Microsoft.AspNetCore.Razor.LanguageServer.Common.csproj b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer.Common/Microsoft.AspNetCore.Razor.LanguageServer.Common.csproj
index 28787dee7a..485d28d874 100644
--- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer.Common/Microsoft.AspNetCore.Razor.LanguageServer.Common.csproj
+++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer.Common/Microsoft.AspNetCore.Razor.LanguageServer.Common.csproj
@@ -8,9 +8,10 @@
-
-
-
+
+
+
+
diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer.Common/Telemetry/ITelemetryReporter.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer.Common/Telemetry/ITelemetryReporter.cs
new file mode 100644
index 0000000000..e61476f8fa
--- /dev/null
+++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer.Common/Telemetry/ITelemetryReporter.cs
@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT license. See License.txt in the project root for license information.
+
+using Microsoft.VisualStudio.Telemetry;
+
+namespace Microsoft.AspNetCore.Razor.LanguageServer.Common.Telemetry
+{
+ internal interface ITelemetryReporter
+ {
+ void ReportEvent(string name, TelemetrySeverity severity);
+ }
+}
diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorLanguageServer.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorLanguageServer.cs
index 6ecb83e392..a4a9f20206 100644
--- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorLanguageServer.cs
+++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorLanguageServer.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT license. See License.txt in the project root for license information.
using System;
+using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Reflection;
@@ -10,6 +11,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.LanguageServer.AutoInsert;
using Microsoft.AspNetCore.Razor.LanguageServer.CodeActions;
using Microsoft.AspNetCore.Razor.LanguageServer.Common;
+using Microsoft.AspNetCore.Razor.LanguageServer.Common.Telemetry;
using Microsoft.AspNetCore.Razor.LanguageServer.Completion;
using Microsoft.AspNetCore.Razor.LanguageServer.Completion.Delegation;
using Microsoft.AspNetCore.Razor.LanguageServer.Debugging;
@@ -30,6 +32,7 @@ using Microsoft.AspNetCore.Razor.LanguageServer.Refactoring;
using Microsoft.AspNetCore.Razor.LanguageServer.Semantic;
using Microsoft.AspNetCore.Razor.LanguageServer.Serialization;
using Microsoft.AspNetCore.Razor.LanguageServer.SignatureHelp;
+using Microsoft.AspNetCore.Razor.LanguageServer.Telemetry;
using Microsoft.AspNetCore.Razor.LanguageServer.Tooltip;
using Microsoft.AspNetCore.Razor.LanguageServer.WrapWithTag;
using Microsoft.CodeAnalysis.Razor;
@@ -41,6 +44,7 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.VisualStudio.Editor.Razor;
+using Microsoft.VisualStudio.Telemetry;
using Newtonsoft.Json.Linq;
using OmniSharp.Extensions.JsonRpc;
using OmniSharp.Extensions.LanguageServer.Protocol.Serialization;
@@ -306,6 +310,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer
// Defaults: For when the caller hasn't provided them through the `configure` action.
services.TryAddSingleton();
+
+ // Get the DefaultSession for telemetry. This is set by VS with
+ // TelemetryService.SetDefaultSession and provides the correct
+ // appinsights keys etc
+ services.AddSingleton(provider =>
+ new TelemetryReporter(ImmutableArray.Create(TelemetryService.DefaultSession), provider.GetRequiredService()));
}));
try
diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Telemetry/TelemetryReporter.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Telemetry/TelemetryReporter.cs
new file mode 100644
index 0000000000..6c05d96f96
--- /dev/null
+++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Telemetry/TelemetryReporter.cs
@@ -0,0 +1,50 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT license. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Immutable;
+using Microsoft.AspNetCore.Razor.LanguageServer.Common.Telemetry;
+using Microsoft.Extensions.Logging;
+using Microsoft.VisualStudio.Telemetry;
+
+namespace Microsoft.AspNetCore.Razor.LanguageServer.Telemetry
+{
+ internal class TelemetryReporter : ITelemetryReporter
+ {
+ private readonly ImmutableArray _telemetrySessions;
+ private readonly ILogger _logger;
+
+ public TelemetryReporter(ImmutableArray telemetrySessions, ILoggerFactory loggerFactory)
+ {
+ _telemetrySessions = telemetrySessions;
+ _logger = loggerFactory.CreateLogger();
+ }
+
+ public void ReportEvent(string name, TelemetrySeverity severity)
+ {
+ var telemetryEvent = new TelemetryEvent(name, severity);
+ Report(telemetryEvent);
+ }
+
+ private void Report(TelemetryEvent telemetryEvent)
+ {
+ try
+ {
+ foreach (var session in _telemetrySessions)
+ {
+ session.PostEvent(telemetryEvent);
+ }
+ }
+ catch (OutOfMemoryException)
+ {
+ // Do we want to failfast like Roslyn here?
+ }
+ catch (Exception e)
+ {
+ // No need to do anything here. We failed to report telemetry
+ // which isn't good, but not catastrophic for a user
+ _logger.LogError(e, "Failed logging telemetry event");
+ }
+ }
+ }
+}