Skip to content
This repository was archived by the owner on Jun 21, 2023. It is now read-only.

Commit 47dcf03

Browse files
authored
Merge pull request #2424 from github/fixes/telemetry-on-VS2015
Only use Visual Studio Telemetry on VS 2017 and above
2 parents 28caef7 + 607bec2 commit 47dcf03

File tree

6 files changed

+114
-48
lines changed

6 files changed

+114
-48
lines changed

src/GitHub.VisualStudio.16/CompositionServices.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ internal static IUsageTracker CreateUsageTracker(CompositionContainer compositio
8282
var gitHubServiceProvider = compositionContainer.GetExportedValue<IGitHubServiceProvider>();
8383
var usageService = compositionContainer.GetExportedValue<IUsageService>();
8484
var joinableTaskContext = compositionContainer.GetExportedValue<JoinableTaskContext>();
85-
return new UsageTracker(gitHubServiceProvider, usageService, packageSettings, joinableTaskContext);
85+
return new UsageTracker(gitHubServiceProvider, usageService, packageSettings, joinableTaskContext, vsTelemetry: true);
8686
}
8787
}
8888

src/GitHub.VisualStudio/GitHub.VisualStudio.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@
129129
<Compile Include="Services\ShowDialogService.cs" />
130130
<Compile Include="Services\UsageService.cs" />
131131
<Compile Include="Services\UsageTracker.cs" />
132+
<Compile Include="Services\VisualStudioUsageTracker.cs" />
132133
<Compile Include="Services\VSGitExtFactory.cs" />
133134
<Compile Include="Settings\Constants.cs" />
134135
<Compile Include="Services\ConnectionManager.cs" />

src/GitHub.VisualStudio/GitHubPackage.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,13 @@ async Task<object> CreateService(IAsyncServiceContainer container, CancellationT
393393
Assumes.Present(serviceProvider);
394394
Assumes.Present(settings);
395395

396-
return new UsageTracker(serviceProvider, usageService, settings, ThreadHelper.JoinableTaskContext);
396+
// Only use Visual Studio Telemetry on VS 2017 and above
397+
await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
398+
var dte = await GetServiceAsync(typeof(EnvDTE.DTE)) as EnvDTE.DTE;
399+
Assumes.Present(dte);
400+
var vsTelemetry = new Version(dte.Version) >= new Version(15, 0);
401+
402+
return new UsageTracker(serviceProvider, usageService, settings, ThreadHelper.JoinableTaskContext, vsTelemetry);
397403
}
398404
else if (serviceType == typeof(IVSGitExt))
399405
{

src/GitHub.VisualStudio/Services/UsageTracker.cs

Lines changed: 18 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
using GitHub.Logging;
88
using GitHub.Models;
99
using GitHub.Settings;
10-
using Microsoft.VisualStudio.Telemetry;
11-
using Microsoft.VisualStudio.Text.Editor;
1210
using Microsoft.VisualStudio.Threading;
1311
using Serilog;
1412
using Task = System.Threading.Tasks.Task;
@@ -17,25 +15,6 @@ namespace GitHub.Services
1715
{
1816
public sealed class UsageTracker : IUsageTracker, IDisposable
1917
{
20-
private const int TelemetryVersion = 1; // Please update the version every time you want to indicate a change in telemetry logic when the extension itself is updated
21-
22-
private const string EventNamePrefix = "vs/github/usagetracker/";
23-
private const string PropertyPrefix = "vs.github.";
24-
25-
static class Event
26-
{
27-
public const string UsageTracker = EventNamePrefix + "increment-counter";
28-
}
29-
30-
static class Property
31-
{
32-
public const string TelemetryVersion = PropertyPrefix + nameof(TelemetryVersion);
33-
public const string CounterName = PropertyPrefix + nameof(CounterName);
34-
public const string ExtensionVersion = PropertyPrefix + nameof(ExtensionVersion);
35-
public const string IsGitHubUser = PropertyPrefix + nameof(IsGitHubUser);
36-
public const string IsEnterpriseUser = PropertyPrefix + nameof(IsEnterpriseUser);
37-
}
38-
3918
static readonly ILogger log = LogManager.ForContext<UsageTracker>();
4019
readonly IGitHubServiceProvider gitHubServiceProvider;
4120

@@ -44,20 +23,25 @@ static class Property
4423
readonly IUsageService service;
4524
IConnectionManager connectionManager;
4625
readonly IPackageSettings userSettings;
26+
readonly bool vsTelemetry;
4727
IVSServices vsservices;
28+
IUsageTracker visualStudioUsageTracker;
4829
IDisposable timer;
4930
bool firstTick = true;
5031

5132
public UsageTracker(
5233
IGitHubServiceProvider gitHubServiceProvider,
5334
IUsageService service,
5435
IPackageSettings settings,
55-
JoinableTaskContext joinableTaskContext)
36+
JoinableTaskContext joinableTaskContext,
37+
bool vsTelemetry)
5638
{
5739
this.gitHubServiceProvider = gitHubServiceProvider;
5840
this.service = service;
5941
this.userSettings = settings;
6042
JoinableTaskContext = joinableTaskContext;
43+
this.vsTelemetry = vsTelemetry;
44+
6145
timer = StartTimer();
6246
}
6347

@@ -77,27 +61,13 @@ public async Task IncrementCounter(Expression<Func<UsageModel.MeasuresModel, int
7761

7862
var updateTask = UpdateUsageMetrics(propertyInfo);
7963

80-
LogTelemetryEvent(counterName);
81-
82-
await updateTask;
83-
}
84-
85-
void LogTelemetryEvent(string counterName)
86-
{
87-
const string numberOfPrefix = "numberof";
88-
if (counterName.StartsWith(numberOfPrefix, StringComparison.OrdinalIgnoreCase))
64+
if (visualStudioUsageTracker != null)
8965
{
90-
counterName = counterName.Substring(numberOfPrefix.Length);
66+
// Not available on Visual Studio 2015
67+
await visualStudioUsageTracker.IncrementCounter(counter);
9168
}
9269

93-
var operation = new TelemetryEvent(Event.UsageTracker);
94-
operation.Properties[Property.TelemetryVersion] = TelemetryVersion;
95-
operation.Properties[Property.CounterName] = counterName;
96-
operation.Properties[Property.ExtensionVersion] = AssemblyVersionInformation.Version;
97-
operation.Properties[Property.IsGitHubUser] = IsGitHubUser;
98-
operation.Properties[Property.IsEnterpriseUser] = IsEnterpriseUser;
99-
100-
TelemetryService.DefaultSession.PostEvent(operation);
70+
await updateTask;
10171
}
10272

10373
bool IsEnterpriseUser =>
@@ -111,7 +81,7 @@ async Task UpdateUsageMetrics(PropertyInfo propertyInfo)
11181
var data = await service.ReadLocalData();
11282
var usage = await GetCurrentReport(data);
11383

114-
var value = (int) propertyInfo.GetValue(usage.Measures);
84+
var value = (int)propertyInfo.GetValue(usage.Measures);
11585
propertyInfo.SetValue(usage.Measures, value + 1);
11686

11787
await service.WriteLocalData(data);
@@ -134,6 +104,13 @@ async Task Initialize()
134104
client = gitHubServiceProvider.TryGetService<IMetricsService>();
135105
connectionManager = gitHubServiceProvider.GetService<IConnectionManager>();
136106
vsservices = gitHubServiceProvider.GetService<IVSServices>();
107+
108+
if (vsTelemetry)
109+
{
110+
log.Verbose("Creating VisualStudioUsageTracker");
111+
visualStudioUsageTracker = new VisualStudioUsageTracker(connectionManager);
112+
}
113+
137114
initialized = true;
138115
}
139116

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
using System;
2+
using System.Linq;
3+
using System.Linq.Expressions;
4+
using System.Reflection;
5+
using GitHub.Models;
6+
using Microsoft.VisualStudio.Telemetry;
7+
using Task = System.Threading.Tasks.Task;
8+
9+
namespace GitHub.Services
10+
{
11+
/// <summary>
12+
/// Implementation of <see cref="IUsageTracker" /> that uses the built in Visual Studio telemetry.
13+
/// </summary>
14+
/// <remarks>
15+
/// This should only be created on Visual Studio 2017 and above.
16+
/// </remarks>
17+
public sealed class VisualStudioUsageTracker : IUsageTracker
18+
{
19+
const int TelemetryVersion = 1; // Please update the version every time you want to indicate a change in telemetry logic when the extension itself is updated
20+
21+
const string EventNamePrefix = "vs/github/usagetracker/";
22+
const string PropertyPrefix = "vs.github.";
23+
24+
readonly IConnectionManager connectionManager;
25+
26+
public VisualStudioUsageTracker(IConnectionManager connectionManager)
27+
{
28+
this.connectionManager = connectionManager;
29+
}
30+
31+
public Task IncrementCounter(Expression<Func<UsageModel.MeasuresModel, int>> counter)
32+
{
33+
var property = (MemberExpression)counter.Body;
34+
var propertyInfo = (PropertyInfo)property.Member;
35+
var counterName = propertyInfo.Name;
36+
LogTelemetryEvent(counterName);
37+
38+
return Task.CompletedTask;
39+
}
40+
41+
void LogTelemetryEvent(string counterName)
42+
{
43+
const string numberOfPrefix = "numberof";
44+
if (counterName.StartsWith(numberOfPrefix, StringComparison.OrdinalIgnoreCase))
45+
{
46+
counterName = counterName.Substring(numberOfPrefix.Length);
47+
}
48+
49+
var operation = new TelemetryEvent(Event.UsageTracker);
50+
operation.Properties[Property.TelemetryVersion] = TelemetryVersion;
51+
operation.Properties[Property.CounterName] = counterName;
52+
operation.Properties[Property.ExtensionVersion] = AssemblyVersionInformation.Version;
53+
operation.Properties[Property.IsGitHubUser] = IsGitHubUser;
54+
operation.Properties[Property.IsEnterpriseUser] = IsEnterpriseUser;
55+
56+
TelemetryService.DefaultSession.PostEvent(operation);
57+
}
58+
59+
bool IsEnterpriseUser =>
60+
connectionManager?.Connections.Any(x => !x.HostAddress.IsGitHubDotCom()) ?? false;
61+
62+
bool IsGitHubUser =>
63+
connectionManager?.Connections.Any(x => x.HostAddress.IsGitHubDotCom()) ?? false;
64+
65+
static class Event
66+
{
67+
public const string UsageTracker = EventNamePrefix + "increment-counter";
68+
}
69+
70+
static class Property
71+
{
72+
public const string TelemetryVersion = PropertyPrefix + nameof(TelemetryVersion);
73+
public const string CounterName = PropertyPrefix + nameof(CounterName);
74+
public const string ExtensionVersion = PropertyPrefix + nameof(ExtensionVersion);
75+
public const string IsGitHubUser = PropertyPrefix + nameof(IsGitHubUser);
76+
public const string IsEnterpriseUser = PropertyPrefix + nameof(IsEnterpriseUser);
77+
}
78+
}
79+
}

test/GitHub.VisualStudio.UnitTests/Services/MetricsTests.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public class UsageTrackerTests : TestBaseClass
2424
public void ShouldStartTimer()
2525
{
2626
var service = Substitute.For<IUsageService>();
27-
var target = new UsageTracker(CreateServiceProvider(), service, CreatePackageSettings(), new JoinableTaskContext());
27+
var target = new UsageTracker(CreateServiceProvider(), service, CreatePackageSettings(), new JoinableTaskContext(), vsTelemetry: false);
2828

2929
service.Received(1).StartTimer(Arg.Any<Func<Task>>(), TimeSpan.FromMinutes(3), TimeSpan.FromDays(1));
3030
}
@@ -111,7 +111,8 @@ public async Task ShouldIncrementCounter()
111111
CreateServiceProvider(),
112112
usageService,
113113
CreatePackageSettings(),
114-
new JoinableTaskContext());
114+
new JoinableTaskContext(),
115+
vsTelemetry: false);
115116

116117
await target.IncrementCounter(x => x.NumberOfClones);
117118
UsageData result = usageService.ReceivedCalls().First(x => x.GetMethodInfo().Name == "WriteLocalData").GetArguments()[0] as UsageData;
@@ -128,7 +129,8 @@ public async Task ShouldWriteData()
128129
CreateServiceProvider(),
129130
service,
130131
CreatePackageSettings(),
131-
new JoinableTaskContext());
132+
new JoinableTaskContext(),
133+
vsTelemetry: false);
132134

133135
await target.IncrementCounter(x => x.NumberOfClones);
134136
await service.Received(1).WriteLocalData(Arg.Is<UsageData>(data =>
@@ -155,7 +157,8 @@ public async Task ShouldWriteUpdatedData()
155157
CreateServiceProvider(),
156158
service,
157159
CreatePackageSettings(),
158-
new JoinableTaskContext());
160+
new JoinableTaskContext(),
161+
vsTelemetry: false);
159162

160163
await target.IncrementCounter(x => x.NumberOfClones);
161164
await service.Received(1).WriteLocalData(Arg.Is<UsageData>(data =>
@@ -177,7 +180,7 @@ static Tuple<UsageTracker, Func<Task>> CreateTargetAndGetTick(
177180
service.WhenForAnyArgs(x => x.StartTimer(null, new TimeSpan(), new TimeSpan()))
178181
.Do(x => tick = x.ArgAt<Func<Task>>(0));
179182

180-
var target = new UsageTracker(serviceProvider, service, CreatePackageSettings(), new JoinableTaskContext());
183+
var target = new UsageTracker(serviceProvider, service, CreatePackageSettings(), new JoinableTaskContext(), vsTelemetry: false);
181184

182185
return Tuple.Create(target, tick);
183186
}

0 commit comments

Comments
 (0)