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

Commit 4634099

Browse files
authored
Merge pull request #1267 from github/refactor/new-metrics-format
Functionality to easily add new metrics
2 parents 9f431b5 + 7adf529 commit 4634099

File tree

10 files changed

+254
-659
lines changed

10 files changed

+254
-659
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="UsageModel"/> 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
}

src/GitHub.Exports/Models/UsageModel.cs

Lines changed: 55 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -2,72 +2,68 @@
22

33
namespace GitHub.Models
44
{
5-
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes", Justification = "It'll use reflection by default and we're fine with that")]
6-
public struct UsageModel
5+
public class UsageModel
76
{
8-
public Guid Guid { get; set; }
9-
public bool IsGitHubUser { get; set; }
10-
public bool IsEnterpriseUser { get; set; }
11-
public string AppVersion { get; set; }
12-
public string VSVersion { get; set; }
13-
public string Lang { get; set; }
14-
public int NumberOfStartups { get; set; }
15-
public int NumberOfStartupsWeek { get; set; }
16-
public int NumberOfStartupsMonth { get; set; }
17-
public int NumberOfUpstreamPullRequests { get; set; }
18-
public int NumberOfClones { get; set; }
19-
public int NumberOfReposCreated { get; set; }
20-
public int NumberOfReposPublished { get; set; }
21-
public int NumberOfGists { get; set; }
22-
public int NumberOfOpenInGitHub { get; set; }
23-
public int NumberOfLinkToGitHub { get; set; }
24-
public int NumberOfLogins { get; set; }
25-
public int NumberOfOAuthLogins { get; set; }
26-
public int NumberOfTokenLogins { get; set; }
27-
public int NumberOfPullRequestsOpened { get; set; }
28-
public int NumberOfLocalPullRequestsCheckedOut { get; set; }
29-
public int NumberOfLocalPullRequestPulls { get; set; }
30-
public int NumberOfLocalPullRequestPushes { get; set; }
31-
public int NumberOfForkPullRequestsCheckedOut { get; set; }
32-
public int NumberOfForkPullRequestPulls { get; set; }
33-
public int NumberOfForkPullRequestPushes { get; set; }
34-
public int NumberOfSyncSubmodules { get; set; }
35-
public int NumberOfWelcomeDocsClicks { get; set; }
36-
public int NumberOfWelcomeTrainingClicks { get; set; }
37-
public int NumberOfGitHubPaneHelpClicks { get; set; }
38-
public int NumberOfPRDetailsViewChanges { get; set; }
39-
public int NumberOfPRDetailsViewFile { get; set; }
40-
public int NumberOfPRDetailsCompareWithSolution { get; set; }
41-
public int NumberOfPRDetailsOpenFileInSolution { get; set; }
42-
public int NumberOfPRDetailsNavigateToEditor { get; set; }
43-
public int NumberOfPRReviewDiffViewInlineCommentOpen { get; set; }
44-
public int NumberOfPRReviewDiffViewInlineCommentPost { get; set; }
45-
public int NumberOfShowCurrentPullRequest { get; set; }
7+
public DimensionsModel Dimensions { get; set; }
8+
public MeasuresModel Measures { get; set; }
469

47-
public UsageModel Clone(bool includeWeekly, bool includeMonthly)
10+
public static UsageModel Create(Guid guid)
4811
{
49-
var result = this;
50-
if (!includeWeekly)
51-
result.NumberOfStartupsWeek = 0;
52-
if (!includeMonthly)
53-
result.NumberOfStartupsMonth = 0;
54-
return result;
12+
return new UsageModel
13+
{
14+
Dimensions = new DimensionsModel
15+
{
16+
Guid = guid,
17+
Date = DateTime.Now,
18+
},
19+
Measures = new MeasuresModel(),
20+
};
5521
}
5622

57-
public UsageModel ClearCounters(bool clearWeekly, bool clearMonthly)
23+
public class DimensionsModel
5824
{
59-
var result = new UsageModel();
60-
if (!clearWeekly)
61-
result.NumberOfStartupsWeek = NumberOfStartupsWeek;
62-
if (!clearMonthly)
63-
result.NumberOfStartupsMonth = NumberOfStartupsMonth;
25+
public Guid Guid { get; set; }
26+
public DateTimeOffset Date { get; set; }
27+
public bool IsGitHubUser { get; set; }
28+
public bool IsEnterpriseUser { get; set; }
29+
public string AppVersion { get; set; }
30+
public string VSVersion { get; set; }
31+
public string Lang { get; set; }
32+
public string CurrentLang { get; set; }
33+
}
6434

65-
result.IsGitHubUser = IsGitHubUser;
66-
result.IsEnterpriseUser = IsEnterpriseUser;
67-
result.AppVersion = AppVersion;
68-
result.VSVersion = VSVersion;
69-
result.Lang = Lang;
70-
return result;
35+
public class MeasuresModel
36+
{
37+
public int NumberOfStartups { get; set; }
38+
public int NumberOfUpstreamPullRequests { get; set; }
39+
public int NumberOfClones { get; set; }
40+
public int NumberOfReposCreated { get; set; }
41+
public int NumberOfReposPublished { get; set; }
42+
public int NumberOfGists { get; set; }
43+
public int NumberOfOpenInGitHub { get; set; }
44+
public int NumberOfLinkToGitHub { get; set; }
45+
public int NumberOfLogins { get; set; }
46+
public int NumberOfOAuthLogins { get; set; }
47+
public int NumberOfTokenLogins { get; set; }
48+
public int NumberOfPullRequestsOpened { get; set; }
49+
public int NumberOfLocalPullRequestsCheckedOut { get; set; }
50+
public int NumberOfLocalPullRequestPulls { get; set; }
51+
public int NumberOfLocalPullRequestPushes { get; set; }
52+
public int NumberOfForkPullRequestsCheckedOut { get; set; }
53+
public int NumberOfForkPullRequestPulls { get; set; }
54+
public int NumberOfForkPullRequestPushes { get; set; }
55+
public int NumberOfSyncSubmodules { get; set; }
56+
public int NumberOfWelcomeDocsClicks { get; set; }
57+
public int NumberOfWelcomeTrainingClicks { get; set; }
58+
public int NumberOfGitHubPaneHelpClicks { get; set; }
59+
public int NumberOfPRDetailsViewChanges { get; set; }
60+
public int NumberOfPRDetailsViewFile { get; set; }
61+
public int NumberOfPRDetailsCompareWithSolution { get; set; }
62+
public int NumberOfPRDetailsOpenFileInSolution { get; set; }
63+
public int NumberOfPRDetailsNavigateToEditor { get; set; }
64+
public int NumberOfPRReviewDiffViewInlineCommentOpen { get; set; }
65+
public int NumberOfPRReviewDiffViewInlineCommentPost { get; set; }
66+
public int NumberOfShowCurrentPullRequest { get; set; }
7167
}
7268
}
7369
}

src/GitHub.Exports/Services/IUsageService.cs

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,6 @@ namespace GitHub.Services
99
/// </summary>
1010
public interface IUsageService
1111
{
12-
/// <summary>
13-
/// Checks whether the last updated date is the same day as today.
14-
/// </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);
32-
3312
/// <summary>
3413
/// Gets a GUID that anonymously represents the user.
3514
/// </summary>

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.Exports/Services/MetricsService.cs

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -102,33 +102,40 @@ public Task SendOptIn()
102102
static StringContent SerializeRequest(UsageModel model)
103103
{
104104
var serializer = new SimpleJsonSerializer();
105-
var dictionary = ToModelDictionary(model);
105+
var dictionary = new Dictionary<string, object>
106+
{
107+
{ToJsonPropertyName("Dimensions"), ToStringDictionary(model.Dimensions) },
108+
{ToJsonPropertyName("Measures"), ToObjectDictionary(model.Measures) }
109+
};
106110
return new StringContent(serializer.Serialize(dictionary), Encoding.UTF8, "application/json");
107111
}
108112

109-
static Dictionary<string, object> ToModelDictionary(object model)
113+
static Dictionary<string, string> ToStringDictionary(object model)
110114
{
111-
var dict = new Dictionary<string, object>();
115+
var dict = new Dictionary<string, string>();
112116
var type = model.GetType();
113117

114118
foreach (var prop in type.GetProperties())
115119
{
116120
if (prop.PropertyType.IsValueType || prop.PropertyType == typeof(string))
117121
{
118-
dict.Add(ToJsonPropertyName(prop.Name), prop.GetValue(model));
122+
dict.Add(ToJsonPropertyName(prop.Name), prop.GetValue(model).ToString());
119123
}
120-
else
124+
}
125+
126+
return dict;
127+
}
128+
129+
static Dictionary<string, object> ToObjectDictionary(object model)
130+
{
131+
var dict = new Dictionary<string, object>();
132+
var type = model.GetType();
133+
134+
foreach (var prop in type.GetProperties())
135+
{
136+
if (prop.PropertyType.IsValueType || prop.PropertyType == typeof(string))
121137
{
122-
var value = prop.GetValue(model);
123-
124-
if (value == null)
125-
{
126-
dict.Add(ToJsonPropertyName(prop.Name), value);
127-
}
128-
else
129-
{
130-
dict.Add(ToJsonPropertyName(prop.Name), ToModelDictionary(value));
131-
}
138+
dict.Add(ToJsonPropertyName(prop.Name), prop.GetValue(model));
132139
}
133140
}
134141

src/GitHub.VisualStudio/Services/UsageService.cs

Lines changed: 5 additions & 41 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;
@@ -8,8 +9,8 @@
89
using GitHub.Helpers;
910
using GitHub.Logging;
1011
using GitHub.Models;
11-
using Rothko;
1212
using Serilog;
13+
using Rothko;
1314
using Environment = System.Environment;
1415
using Task = System.Threading.Tasks.Task;
1516

@@ -18,11 +19,9 @@ namespace GitHub.Services
1819
[Export(typeof(IUsageService))]
1920
public class UsageService : IUsageService
2021
{
21-
const string StoreFileName = "ghfvs.usage";
22+
const string StoreFileName = "metrics.json";
2223
const string UserStoreFileName = "user.json";
23-
2424
static readonly ILogger log = LogManager.ForContext<UsageService>();
25-
static readonly Calendar cal = CultureInfo.InvariantCulture.Calendar;
2625

2726
readonly IGitHubServiceProvider serviceProvider;
2827
readonly IEnvironment environment;
@@ -78,21 +77,6 @@ public async Task<Guid> GetUserGuid()
7877
return userGuid.Value;
7978
}
8079

81-
public bool IsSameDay(DateTimeOffset lastUpdated)
82-
{
83-
return lastUpdated.Date == DateTimeOffset.Now.Date;
84-
}
85-
86-
public bool IsSameWeek(DateTimeOffset lastUpdated)
87-
{
88-
return GetIso8601WeekOfYear(lastUpdated) == GetIso8601WeekOfYear(DateTimeOffset.Now) && lastUpdated.Year == DateTimeOffset.Now.Year;
89-
}
90-
91-
public bool IsSameMonth(DateTimeOffset lastUpdated)
92-
{
93-
return lastUpdated.Month == DateTimeOffset.Now.Month && lastUpdated.Year == DateTimeOffset.Now.Year;
94-
}
95-
9680
public IDisposable StartTimer(Func<Task> callback, TimeSpan dueTime, TimeSpan period)
9781
{
9882
return new Timer(
@@ -116,16 +100,12 @@ public async Task<UsageData> ReadLocalData()
116100
{
117101
return json != null ?
118102
SimpleJson.DeserializeObject<UsageData>(json) :
119-
new UsageData
120-
{
121-
Model = new UsageModel() ,
122-
LastUpdated = DateTimeOffset.Now.UtcDateTime
123-
};
103+
new UsageData { Reports = new List<UsageModel>() };
124104
}
125105
catch(Exception ex)
126106
{
127107
log.Error(ex, "Error deserializing usage");
128-
return new UsageData { Model = new UsageModel() };
108+
return new UsageData { Reports = new List<UsageModel>() };
129109
}
130110
}
131111

@@ -176,22 +156,6 @@ async Task WriteAllTextAsync(string path, string text)
176156
}
177157
}
178158

179-
// http://blogs.msdn.com/b/shawnste/archive/2006/01/24/iso-8601-week-of-year-format-in-microsoft-net.aspx
180-
static int GetIso8601WeekOfYear(DateTimeOffset time)
181-
{
182-
// Seriously cheat. If its Monday, Tuesday or Wednesday, then it'll
183-
// be the same week# as whatever Thursday, Friday or Saturday are,
184-
// and we always get those right
185-
DayOfWeek day = cal.GetDayOfWeek(time.UtcDateTime);
186-
if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
187-
{
188-
time = time.AddDays(3);
189-
}
190-
191-
// Return the week of our adjusted day
192-
return cal.GetWeekOfYear(time.UtcDateTime, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
193-
}
194-
195159
class UserData
196160
{
197161
public Guid UserGuid { get; set; }

0 commit comments

Comments
 (0)