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

Commit 9df7918

Browse files
authored
Merge pull request #1441 from github/enhancements/add-user-guid-to-metrics
Adding a user guid to to UsageModel
2 parents 797d1b8 + fd0527d commit 9df7918

File tree

6 files changed

+281
-24
lines changed

6 files changed

+281
-24
lines changed

src/GitHub.Exports/Models/UsageModel.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
namespace GitHub.Models
1+
using System;
2+
3+
namespace GitHub.Models
24
{
35
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes", Justification = "It'll use reflection by default and we're fine with that")]
46
public struct UsageModel
57
{
8+
public Guid Guid { get; set; }
69
public bool IsGitHubUser { get; set; }
710
public bool IsEnterpriseUser { get; set; }
811
public string AppVersion { get; set; }

src/GitHub.Exports/Services/IUsageService.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ public interface IUsageService
2929
/// <param name="lastUpdated">The last updated date.</param>
3030
/// <returns>True if the last updated date is the same month as today; otherwise false.</returns>
3131
bool IsSameMonth(DateTimeOffset lastUpdated);
32+
33+
/// <summary>
34+
/// Gets a GUID that anonymously represents the user.
35+
/// </summary>
36+
Task<Guid> GetUserGuid();
3237

3338
/// <summary>
3439
/// Starts a timer.

src/GitHub.VisualStudio/GitHubPackage.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,8 @@ async Task<object> CreateService(IAsyncServiceContainer container, CancellationT
249249
else if (serviceType == typeof(IUsageService))
250250
{
251251
var sp = await GetServiceAsync(typeof(IGitHubServiceProvider)) as IGitHubServiceProvider;
252-
return new UsageService(sp);
252+
var environment = new Rothko.Environment();
253+
return new UsageService(sp, environment);
253254
}
254255
else if (serviceType == typeof(IUsageTracker))
255256
{

src/GitHub.VisualStudio/Services/UsageService.cs

Lines changed: 71 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,76 @@
66
using System.Threading;
77
using System.Threading.Tasks;
88
using GitHub.Helpers;
9-
using GitHub.Models;
10-
using Task = System.Threading.Tasks.Task;
119
using GitHub.Logging;
10+
using GitHub.Models;
11+
using Rothko;
1212
using Serilog;
13+
using Environment = System.Environment;
14+
using Task = System.Threading.Tasks.Task;
1315

1416
namespace GitHub.Services
1517
{
1618
[Export(typeof(IUsageService))]
1719
public class UsageService : IUsageService
1820
{
19-
static readonly ILogger log = LogManager.ForContext<UsageService>();
2021
const string StoreFileName = "ghfvs.usage";
22+
const string UserStoreFileName = "user.json";
23+
24+
static readonly ILogger log = LogManager.ForContext<UsageService>();
2125
static readonly Calendar cal = CultureInfo.InvariantCulture.Calendar;
26+
2227
readonly IGitHubServiceProvider serviceProvider;
28+
readonly IEnvironment environment;
29+
2330
string storePath;
31+
string userStorePath;
32+
Guid? userGuid;
2433

2534
[ImportingConstructor]
26-
public UsageService(IGitHubServiceProvider serviceProvider)
35+
public UsageService(IGitHubServiceProvider serviceProvider, IEnvironment environment)
2736
{
2837
this.serviceProvider = serviceProvider;
38+
this.environment = environment;
39+
}
40+
41+
public async Task<Guid> GetUserGuid()
42+
{
43+
await Initialize();
44+
45+
if (!userGuid.HasValue)
46+
{
47+
try
48+
{
49+
if (File.Exists(userStorePath))
50+
{
51+
var json = await ReadAllTextAsync(userStorePath);
52+
var data = SimpleJson.DeserializeObject<UserData>(json);
53+
userGuid = data.UserGuid;
54+
}
55+
}
56+
catch (Exception ex)
57+
{
58+
log.Error(ex, "Failed reading user metrics GUID");
59+
}
60+
}
61+
62+
if (!userGuid.HasValue || userGuid.Value == Guid.Empty)
63+
{
64+
userGuid = Guid.NewGuid();
65+
66+
try
67+
{
68+
var data = new UserData { UserGuid = userGuid.Value };
69+
var json = SimpleJson.SerializeObject(data);
70+
await WriteAllTextAsync(userStorePath, json);
71+
}
72+
catch (Exception ex)
73+
{
74+
log.Error(ex, "Failed writing user metrics GUID");
75+
}
76+
}
77+
78+
return userGuid.Value;
2979
}
3080

3181
public bool IsSameDay(DateTimeOffset lastUpdated)
@@ -49,7 +99,7 @@ public IDisposable StartTimer(Func<Task> callback, TimeSpan dueTime, TimeSpan pe
4999
async _ =>
50100
{
51101
try { await callback(); }
52-
catch { /* log.Warn("Failed submitting usage data", ex); */ }
102+
catch (Exception ex) { log.Warning(ex, "Failed submitting usage data"); }
53103
},
54104
null,
55105
dueTime,
@@ -66,7 +116,11 @@ public async Task<UsageData> ReadLocalData()
66116
{
67117
return json != null ?
68118
SimpleJson.DeserializeObject<UsageData>(json) :
69-
new UsageData { Model = new UsageModel() };
119+
new UsageData
120+
{
121+
Model = new UsageModel() ,
122+
LastUpdated = DateTimeOffset.Now.UtcDateTime
123+
};
70124
}
71125
catch(Exception ex)
72126
{
@@ -83,7 +137,7 @@ public async Task WriteLocalData(UsageData data)
83137
var json = SimpleJson.SerializeObject(data);
84138
await WriteAllTextAsync(storePath, json);
85139
}
86-
catch(Exception ex)
140+
catch (Exception ex)
87141
{
88142
log.Error(ex,"Failed to write usage data");
89143
}
@@ -96,10 +150,11 @@ async Task Initialize()
96150
await ThreadingHelper.SwitchToMainThreadAsync();
97151

98152
var program = serviceProvider.GetService<IProgram>();
99-
storePath = Path.Combine(
100-
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
101-
program.ApplicationName,
102-
StoreFileName);
153+
154+
var localApplicationDataPath = environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
155+
156+
storePath = Path.Combine(localApplicationDataPath, program.ApplicationName, StoreFileName);
157+
userStorePath = Path.Combine(localApplicationDataPath, program.ApplicationName, UserStoreFileName);
103158
}
104159
}
105160

@@ -136,5 +191,10 @@ static int GetIso8601WeekOfYear(DateTimeOffset time)
136191
// Return the week of our adjusted day
137192
return cal.GetWeekOfYear(time.UtcDateTime, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
138193
}
194+
195+
class UserData
196+
{
197+
public Guid UserGuid { get; set; }
198+
}
139199
}
140200
}

src/GitHub.VisualStudio/Services/UsageTracker.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ async Task TimerTick()
127127
// Only send stats once a day.
128128
if (!service.IsSameDay(usage.LastUpdated))
129129
{
130-
usage.Model = UpdateModelUserData(usage.Model);
130+
usage.Model = await UpdateModelUserData(usage.Model);
131131

132132
await SendUsage(usage.Model, includeWeekly, includeMonthly);
133133

@@ -148,8 +148,10 @@ async Task SendUsage(UsageModel usage, bool includeWeekly, bool includeMonthly)
148148
await client.PostUsage(model);
149149
}
150150

151-
UsageModel UpdateModelUserData(UsageModel model)
151+
async Task<UsageModel> UpdateModelUserData(UsageModel model)
152152
{
153+
model.Guid = await service.GetUserGuid();
154+
153155
if (connectionManager.Connections.Any(x => x.HostAddress.IsGitHubDotCom()))
154156
{
155157
model.IsGitHubUser = true;
@@ -159,6 +161,7 @@ UsageModel UpdateModelUserData(UsageModel model)
159161
{
160162
model.IsEnterpriseUser = true;
161163
}
164+
162165
return model;
163166
}
164167
}

0 commit comments

Comments
 (0)