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

Commit da93fb7

Browse files
committed
Update metrics reporting.
Updates the metrics reporting: - Store the metrics in a different format, with separate Measures and Dimensions - Store reports for each day separately - Identify user by anonymous GUID.
1 parent 15802f5 commit da93fb7

File tree

10 files changed

+302
-280
lines changed

10 files changed

+302
-280
lines changed
Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,16 @@
11
using System;
2+
using System.Collections.Generic;
23

34
namespace GitHub.Models
45
{
56
/// <summary>
6-
/// Wraps a <see cref="UsageModel"/> with a <see cref="LastUpdated"/> field.
7+
/// Holds a collection of <see cref="UsageData"/> daily usage reports.
78
/// </summary>
89
public class UsageData
910
{
1011
/// <summary>
11-
/// Gets or sets the last update time.
12+
/// Gets a list of unsent daily usage reports.
1213
/// </summary>
13-
public DateTimeOffset LastUpdated { get; set; }
14-
15-
/// <summary>
16-
/// Gets the model containing the current usage data.
17-
/// </summary>
18-
public UsageModel Model { get; set; }
14+
public List<UsageModel> Reports { get; set; }
1915
}
2016
}
Lines changed: 47 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,61 @@
11
using System;
2-
using System.Reflection;
32

43
namespace GitHub.Models
54
{
65
public class UsageModel
76
{
8-
public bool IsGitHubUser { get; set; }
9-
public bool IsEnterpriseUser { get; set; }
10-
public string AppVersion { get; set; }
11-
public string VSVersion { get; set; }
12-
public string Lang { get; set; }
13-
public int NumberOfStartups { get; set; }
14-
public int NumberOfStartupsWeek { get; set; }
15-
public int NumberOfStartupsMonth { get; set; }
16-
public int NumberOfUpstreamPullRequests { get; set; }
17-
public int NumberOfClones { get; set; }
18-
public int NumberOfReposCreated { get; set; }
19-
public int NumberOfReposPublished { get; set; }
20-
public int NumberOfGists { get; set; }
21-
public int NumberOfOpenInGitHub { get; set; }
22-
public int NumberOfLinkToGitHub { get; set; }
23-
public int NumberOfLogins { get; set; }
24-
public int NumberOfPullRequestsOpened { get; set; }
25-
public int NumberOfLocalPullRequestsCheckedOut { get; set; }
26-
public int NumberOfLocalPullRequestPulls { get; set; }
27-
public int NumberOfLocalPullRequestPushes { get; set; }
28-
public int NumberOfForkPullRequestsCheckedOut { get; set; }
29-
public int NumberOfForkPullRequestPulls { get; set; }
30-
public int NumberOfForkPullRequestPushes { get; set; }
31-
public int NumberOfWelcomeDocsClicks { get; set; }
32-
public int NumberOfWelcomeTrainingClicks { get; set; }
33-
public int NumberOfGitHubPaneHelpClicks { get; set; }
34-
public int NumberOfPRDetailsViewChanges { get; set; }
35-
public int NumberOfPRDetailsViewFile { get; set; }
36-
public int NumberOfPRDetailsCompareWithSolution { get; set; }
37-
public int NumberOfPRDetailsOpenFileInSolution { get; set; }
38-
public int NumberOfPRReviewDiffViewInlineCommentOpen { get; set; }
39-
public int NumberOfPRReviewDiffViewInlineCommentPost { get; set; }
7+
public Guid Guid { get; set; }
8+
public DateTimeOffset Date { get; set; }
9+
public DimensionsModel Dimensions { get; set; }
10+
public MeasuresModel Measures { get; set; }
4011

41-
public UsageModel Clone(bool includeWeekly, bool includeMonthly)
12+
public static UsageModel Create(Guid guid)
4213
{
43-
var result = new UsageModel();
44-
var properties = result.GetType().GetRuntimeProperties();
45-
46-
foreach (var property in properties)
14+
return new UsageModel
4715
{
48-
var cloneValue = property.PropertyType == typeof(int);
49-
50-
if (property.Name == nameof(result.NumberOfStartupsWeek))
51-
cloneValue = includeWeekly;
52-
else if (property.Name == nameof(result.NumberOfStartupsMonth))
53-
cloneValue = includeMonthly;
16+
Guid = guid,
17+
Date = DateTime.Now,
18+
Dimensions = new DimensionsModel(),
19+
Measures = new MeasuresModel(),
20+
};
21+
}
5422

55-
if (cloneValue)
56-
{
57-
var value = property.GetValue(this);
58-
property.SetValue(result, value);
59-
}
60-
}
23+
public class DimensionsModel
24+
{
25+
public string AppVersion { get; set; }
26+
public string VSVersion { get; set; }
27+
public string Lang { get; set; }
28+
public bool IsGitHubUser { get; set; }
29+
public bool IsEnterpriseUser { get; set; }
30+
}
6131

62-
return result;
32+
public class MeasuresModel
33+
{
34+
public int NumberOfStartups { get; set; }
35+
public int NumberOfUpstreamPullRequests { get; set; }
36+
public int NumberOfClones { get; set; }
37+
public int NumberOfReposCreated { get; set; }
38+
public int NumberOfReposPublished { get; set; }
39+
public int NumberOfGists { get; set; }
40+
public int NumberOfOpenInGitHub { get; set; }
41+
public int NumberOfLinkToGitHub { get; set; }
42+
public int NumberOfLogins { get; set; }
43+
public int NumberOfPullRequestsOpened { get; set; }
44+
public int NumberOfLocalPullRequestsCheckedOut { get; set; }
45+
public int NumberOfLocalPullRequestPulls { get; set; }
46+
public int NumberOfLocalPullRequestPushes { get; set; }
47+
public int NumberOfForkPullRequestsCheckedOut { get; set; }
48+
public int NumberOfForkPullRequestPulls { get; set; }
49+
public int NumberOfForkPullRequestPushes { get; set; }
50+
public int NumberOfWelcomeDocsClicks { get; set; }
51+
public int NumberOfWelcomeTrainingClicks { get; set; }
52+
public int NumberOfGitHubPaneHelpClicks { get; set; }
53+
public int NumberOfPRDetailsViewChanges { get; set; }
54+
public int NumberOfPRDetailsViewFile { get; set; }
55+
public int NumberOfPRDetailsCompareWithSolution { get; set; }
56+
public int NumberOfPRDetailsOpenFileInSolution { get; set; }
57+
public int NumberOfPRReviewDiffViewInlineCommentOpen { get; set; }
58+
public int NumberOfPRReviewDiffViewInlineCommentPost { get; set; }
6359
}
6460
}
6561
}

src/GitHub.Exports/Services/IUsageService.cs

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,9 @@ namespace GitHub.Services
1010
public interface IUsageService
1111
{
1212
/// <summary>
13-
/// Checks whether the last updated date is the same day as today.
13+
/// Gets a GUID that anonymously represents the user.
1414
/// </summary>
15-
/// <param name="lastUpdated">The last updated date.</param>
16-
/// <returns>True if the last updated date is the same day as today; otherwise false.</returns>
17-
bool IsSameDay(DateTimeOffset lastUpdated);
18-
19-
/// <summary>
20-
/// Checks whether the last updated date is the same week as today.
21-
/// </summary>
22-
/// <param name="lastUpdated">The last updated date.</param>
23-
/// <returns>True if the last updated date is the same week as today; otherwise false.</returns>
24-
bool IsSameWeek(DateTimeOffset lastUpdated);
25-
26-
/// <summary>
27-
/// Checks whether the last updated date is the same month as today.
28-
/// </summary>
29-
/// <param name="lastUpdated">The last updated date.</param>
30-
/// <returns>True if the last updated date is the same month as today; otherwise false.</returns>
31-
bool IsSameMonth(DateTimeOffset lastUpdated);
15+
Task<Guid> GetUserGuid();
3216

3317
/// <summary>
3418
/// Starts a timer.

src/GitHub.Exports/Services/IUsageTracker.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ namespace GitHub.Services
1010
[Guid(Guids.UsageTrackerId)]
1111
public interface IUsageTracker
1212
{
13-
Task IncrementCounter(Expression<Func<UsageModel, int>> counter);
13+
Task IncrementCounter(Expression<Func<UsageModel.MeasuresModel, int>> counter);
1414
}
1515
}

src/GitHub.VisualStudio/Services/UsageService.cs

Lines changed: 55 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.ComponentModel.Composition;
34
using System.Globalization;
45
using System.IO;
@@ -14,30 +15,63 @@ namespace GitHub.Services
1415
[Export(typeof(IUsageService))]
1516
public class UsageService : IUsageService
1617
{
17-
const string StoreFileName = "ghfvs.usage";
18-
static readonly Calendar cal = CultureInfo.InvariantCulture.Calendar;
18+
const string StoreFileName = "metrics.json";
19+
const string UserStoreFileName = "user.json";
20+
static readonly NLog.Logger log = NLog.LogManager.GetCurrentClassLogger();
1921
readonly IGitHubServiceProvider serviceProvider;
2022
string storePath;
23+
string userStorePath;
24+
Guid? userGuid;
2125

2226
[ImportingConstructor]
2327
public UsageService(IGitHubServiceProvider serviceProvider)
2428
{
2529
this.serviceProvider = serviceProvider;
2630
}
2731

28-
public bool IsSameDay(DateTimeOffset lastUpdated)
32+
public async Task<Guid> GetUserGuid()
2933
{
30-
return lastUpdated.Date == DateTimeOffset.Now.Date;
31-
}
34+
await Initialize();
3235

33-
public bool IsSameWeek(DateTimeOffset lastUpdated)
34-
{
35-
return GetIso8601WeekOfYear(lastUpdated) == GetIso8601WeekOfYear(DateTimeOffset.Now);
36+
if (!userGuid.HasValue)
37+
{
38+
try
39+
{
40+
if (File.Exists(userStorePath))
41+
{
42+
var json = await ReadAllTextAsync(userStorePath);
43+
var data = SimpleJson.DeserializeObject<UserData>(json);
44+
userGuid = data.UserGuid;
45+
}
46+
}
47+
catch (Exception ex)
48+
{
49+
log.Error("Failed reading user metrics GUID", ex);
50+
}
51+
}
52+
53+
if (!userGuid.HasValue || userGuid.Value == Guid.Empty)
54+
{
55+
userGuid = Guid.NewGuid();
56+
57+
try
58+
{
59+
var data = new UserData { UserGuid = userGuid.Value };
60+
var json = SimpleJson.SerializeObject(data);
61+
await WriteAllTextAsync(userStorePath, json);
62+
}
63+
catch (Exception ex)
64+
{
65+
log.Error("Failed reading writing metrics GUID", ex);
66+
}
67+
}
68+
69+
return userGuid.Value;
3670
}
3771

38-
public bool IsSameMonth(DateTimeOffset lastUpdated)
72+
public bool IsToday(DateTimeOffset date)
3973
{
40-
return lastUpdated.Month == DateTimeOffset.Now.Month;
74+
return date.Date == DateTimeOffset.Now.Date;
4175
}
4276

4377
public IDisposable StartTimer(Func<Task> callback, TimeSpan dueTime, TimeSpan period)
@@ -46,7 +80,7 @@ public IDisposable StartTimer(Func<Task> callback, TimeSpan dueTime, TimeSpan pe
4680
async _ =>
4781
{
4882
try { await callback(); }
49-
catch { /* log.Warn("Failed submitting usage data", ex); */ }
83+
catch (Exception ex) { log.Warn("Failed submitting usage data", ex); }
5084
},
5185
null,
5286
dueTime,
@@ -63,11 +97,11 @@ public async Task<UsageData> ReadLocalData()
6397
{
6498
return json != null ?
6599
SimpleJson.DeserializeObject<UsageData>(json) :
66-
new UsageData { Model = new UsageModel() };
100+
new UsageData { Reports = new List<UsageModel>() };
67101
}
68102
catch
69103
{
70-
return new UsageData { Model = new UsageModel() };
104+
return new UsageData { Reports = new List<UsageModel>() };
71105
}
72106
}
73107

@@ -79,9 +113,9 @@ public async Task WriteLocalData(UsageData data)
79113
var json = SimpleJson.SerializeObject(data);
80114
await WriteAllTextAsync(storePath, json);
81115
}
82-
catch
116+
catch (Exception ex)
83117
{
84-
// log.Warn("Failed to write usage data", ex);
118+
log.Warn("Failed to write usage data", ex);
85119
}
86120
}
87121

@@ -96,6 +130,10 @@ async Task Initialize()
96130
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
97131
program.ApplicationName,
98132
StoreFileName);
133+
userStorePath = Path.Combine(
134+
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
135+
program.ApplicationName,
136+
UserStoreFileName);
99137
}
100138
}
101139

@@ -117,20 +155,9 @@ async Task WriteAllTextAsync(string path, string text)
117155
}
118156
}
119157

120-
// http://blogs.msdn.com/b/shawnste/archive/2006/01/24/iso-8601-week-of-year-format-in-microsoft-net.aspx
121-
static int GetIso8601WeekOfYear(DateTimeOffset time)
158+
class UserData
122159
{
123-
// Seriously cheat. If its Monday, Tuesday or Wednesday, then it'll
124-
// be the same week# as whatever Thursday, Friday or Saturday are,
125-
// and we always get those right
126-
DayOfWeek day = cal.GetDayOfWeek(time.UtcDateTime);
127-
if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
128-
{
129-
time = time.AddDays(3);
130-
}
131-
132-
// Return the week of our adjusted day
133-
return cal.GetWeekOfYear(time.UtcDateTime, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
160+
public Guid UserGuid { get; set; }
134161
}
135162
}
136163
}

0 commit comments

Comments
 (0)