feat(metrics): Add metrics gathering. #1146
Conversation
| @@ -80,6 +80,7 @@ function ( | |||
|
|
|||
| this._window = options.window || window; | |||
| this._window.router = this._router = options.router || new Router(); | |||
|
|
|||
shane-tomlinson
May 21, 2014
Author
Member
What's this all about?
What's this all about?
| return this._send(data, url, false); | ||
| }, | ||
|
|
||
| getAllData: function () { |
shane-tomlinson
May 21, 2014
Author
Member
Data doesn't really provide anything useful. Getting rid of it seems worse.
Getting rid of it seems worse.Data doesn't really provide anything useful.
| @@ -111,6 +135,9 @@ function ( | |||
| }, | |||
|
|
|||
| showView: function (viewToShow) { | |||
| var url = this.window.location.pathname; | |||
| this.metrics.events.capture('screen:' + urlToScreenName(url)); | |||
shane-tomlinson
May 21, 2014
Author
Member
This needs a test
This needs a test
| }; | ||
| } | ||
|
|
||
| function urlToScreenName(url) { |
shane-tomlinson
May 21, 2014
Author
Member
This needs a test. Move to app/scripts/lib/url.
This needs a test. Move to app/scripts/lib/url.
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
|
||
|
|
||
| (function(define){ define(function (require,exports,module,undefined){ |
shane-tomlinson
May 21, 2014
Author
Member
It would be awesome to move this to bower and out of this repo.
It would be awesome to move this to bower and out of this repo.
| @@ -287,6 +298,7 @@ function (_, Backbone, $, p, Session, AuthErrors, FxaClient, Url, Strings, Ephem | |||
| this.hideSuccess(); | |||
| this.$('.spinner').hide(); | |||
|
|
|||
| this.metrics.events.capture('error:' + this.errorCode(err)); | |||
shane-tomlinson
May 21, 2014
Author
Member
Add a test.
Add a test.
| @@ -317,6 +329,7 @@ function (_, Backbone, $, p, Session, AuthErrors, FxaClient, Url, Strings, Ephem | |||
| this.hideSuccess(); | |||
| this.$('.spinner').hide(); | |||
|
|
|||
| this.metrics.events.capture('error:' + this.errorCode(err)); | |||
shane-tomlinson
May 21, 2014
Author
Member
Add a test.
Add a test.
| @@ -258,6 +265,10 @@ function (_, Backbone, $, p, Session, AuthErrors, FxaClient, Url, Strings, Ephem | |||
| return !!this._isSuccessVisible; | |||
| }, | |||
|
|
|||
| errorCode: function (err) { | |||
shane-tomlinson
May 21, 2014
Author
Member
This should be in auth-errors.js
This should be in auth-errors.js
| var msg = t('Unknown account. <a href="/signup">Sign up</a>'); | ||
| return self.displayErrorUnsafe(msg); | ||
| err.forceMessage = t('Unknown account. <a href="/signup">Sign up</a>'); | ||
| return self.displayErrorUnsafe(err); | ||
| } else if (AuthErrors.is(err, 'USER_CANCELED_LOGIN')) { | ||
| // if user canceled login, just stop |
shane-tomlinson
May 21, 2014
Author
Member
Log cancellations.
Log cancellations.
| var roundedDate = new Date(); | ||
| roundedDate.setTime(roundedTime); | ||
|
|
||
| return roundedDate; |
pdehaan
May 21, 2014
Contributor
I'm mildly lost. What are we doing here?
You just want the current date sans time?
Couldn't we just stomp the time bits using something like setHours(), or am I missing some edge cases?
var today = new Date();
today.setHours(0, 0, 0, 0);
console.log(today); // Wed May 21 2014 00:00:00 GMT-0700 (PDT)
I'm mildly lost. What are we doing here?
You just want the current date sans time?
Couldn't we just stomp the time bits using something like setHours(), or am I missing some edge cases?
var today = new Date();
today.setHours(0, 0, 0, 0);
console.log(today); // Wed May 21 2014 00:00:00 GMT-0700 (PDT)
shane-tomlinson
May 21, 2014
Author
Member
We could, this is largely copy/paste code from Persona.
We could, this is largely copy/paste code from Persona.
| this._date = getDate(); | ||
|
|
||
| this._context = Url.searchParam('context'); | ||
| this._service = Url.searchParam('sync'); |
pdehaan
May 21, 2014
Contributor
Sorry, I had to read this a couple times and I should probably know the answer, but should the searchParam be "sync" here? Will this support other services in the future?
Sorry, I had to read this a couple times and I should probably know the answer, but should the searchParam be "sync" here? Will this support other services in the future?
shane-tomlinson
May 21, 2014
Author
Member
No, you are right! that points out a missing test.
No, you are right! that points out a missing test.
| return filteredData; | ||
| }, | ||
|
|
||
| toErrorEvent: function (err) { |
shane-tomlinson
May 21, 2014
Author
Member
This needs a better name. We aren't creating an event, but rather creating an error event identifier.
This needs a better name. We aren't creating an event, but rather creating an error event identifier.
shane-tomlinson
May 21, 2014
Author
Member
Where is this better, here or in AuthErrors?
Where is this better, here or in AuthErrors?
| @@ -53,7 +57,17 @@ function ( | |||
|
|
|||
| function showView(View, options) { | |||
| return function () { | |||
| this.showView(new View(options || {})); | |||
| options = options || {}; | |||
shane-tomlinson
May 21, 2014
Author
Member
This line isn't needed since we are effectively repeating ourselves a few lines down.
This line isn't needed since we are effectively repeating ourselves a few lines down.
|
@kparlante - here is the initial client side work, and a dumb metrics endpoint on the server side that just logs the metrics to the console. Could you have a look and see what you think? The format is similar to yesterday, but with the changes I wrote to you about. This is an example: Any time a screen is diaplayed, an entry is added to the event log. I went through each screen and hooked up other interesting events:
I think that is a full list. @zaach, @pdehaan, @ckarlof - could you do an initial review? It'd be nice to have the client side reporting results before I leave, if possible! |
| @@ -111,6 +133,9 @@ function ( | |||
| }, | |||
|
|
|||
| showView: function (viewToShow) { | |||
| var path = this.window.location.pathname; | |||
| this.metrics.events.capture('screen:' + Url.pathToScreenName(path)); | |||
shane-tomlinson
May 21, 2014
Author
Member
Should this be done here or in view instantiation?
Should this be done here or in view instantiation?
| return router.showView(signUpView); | ||
| }) | ||
| .then(function () { | ||
| assert.ok($('#fxa-signup-header').length); | ||
| // if there is a back button, it can be shown now. | ||
| assert.equal(Session.canGoBack, true); | ||
|
|
||
| var events = metrics.getFilteredData().events; |
shane-tomlinson
May 21, 2014
Author
Member
Use TestHelpers.isEventLogged here.
Use TestHelpers.isEventLogged here.
| @@ -19,9 +19,11 @@ | |||
| <script data-main="main" src="/bower_components/requirejs/require.js"></script> | |||
| <script> | |||
| // Avoid caching files that are loaded with Require.JS | |||
| /* | |||
shane-tomlinson
May 21, 2014
Author
Member
This is because of #1145 and can be reverted until we decide how to handle caching in dev.
This is because of #1145 and can be reverted until we decide how to handle caching in dev.
|
@shane-tomlinson I looked through the code and it looked good (although I have no idea what I'm doing). |
|
|
||
| route.process = function(req, res) { | ||
|
|
||
| logger.error('metrics: %s', JSON.stringify(req.body, null, 2)); |
pdehaan
May 21, 2014
Contributor
Curious, why error (aka: server.metrics.ERROR) here?
I usually think of error as "OMG, SOMETHING IS WRONG" versus "hey, have some stats".
Curious, why error (aka: server.metrics.ERROR) here?
I usually think of error as "OMG, SOMETHING IS WRONG" versus "hey, have some stats".
shane-tomlinson
May 22, 2014
Author
Member
@pdehaan - The reason is pretty mundane. I permanently turn on iterm2's search to see the ERROR highlighted as it goes by. I could just as easily search for another keyword, but I'm lazy and didn't think of it until you brought it up. This will be removed.
@pdehaan - The reason is pretty mundane. I permanently turn on iterm2's search to see the ERROR highlighted as it goes by. I could just as easily search for another keyword, but I'm lazy and didn't think of it until you brought it up. This will be removed.
|
So far, so good. I'm seeing this in my stdout: |
|
Sorry, more fun and noise for @shane-tomlinson's amusement: {
"date": "2014-05-21T00:00:00.000Z",
"navigationTiming": {
"navigationStart": 0,
"unloadEventStart": 21,
"unloadEventEnd": 26,
"redirectStart": null,
"redirectEnd": null,
"fetchStart": 0,
"domainLookupStart": 0,
"domainLookupEnd": 0,
"connectStart": 0,
"connectEnd": 0,
"secureConnectionStart": null,
"requestStart": 11,
"responseStart": 19,
"responseEnd": 20,
"domLoading": 29,
"domInteractive": 49,
"domContentLoadedEventStart": 49,
"domContentLoadedEventEnd": 49,
"domComplete": 90,
"loadEventStart": 90,
"loadEventEnd": 90
},
"duration": 117353,
"timers": {},
"events": [
{
"type": "screen:settings",
"offset": 271
},
{
"type": "screen:signin",
"offset": 273
},
{
"type": "error:Session expired. Sign in to continue.",
"offset": 279
},
{
"type": "screen:settings",
"offset": 12021
},
{
"type": "screen:change_password",
"offset": 14395
},
{
"type": "screen:settings",
"offset": 25467
},
{
"type": "screen:change_password",
"offset": 31495
},
{
"type": "screen:settings",
"offset": 33307
},
{
"type": "screen:signin",
"offset": 39628
},
{
"type": "error:103",
"offset": 77301
},
{
"type": "screen:settings",
"offset": 82187
},
{
"type": "screen:delete_account",
"offset": 90479
},
{
"type": "error:103",
"offset": 98151
},
{
"type": "error:103",
"offset": 105475
},
{
"type": "screen:signup",
"offset": 111997
}
]
}Verified my account locally and doing a bit of password changing, signing out, signing back in, deleting accounts, etc. {
"type": "error:Session expired. Sign in to continue.",
"offset": 279
}Other things we can argue/hug-out are underscores-vs-dashes: {
"type": "screen:change_password",
"offset": 1986
},
{
"type": "confirm:too-many-attempts",
"offset": 46420
},
{
"type": "screen:delete_account",
"offset": 90479
}, |
Awesome, you found a case I missed. |
I made this error code 1002 |
|
@pdehaan - I have normalized event names to use |
|
This gets a @zaach, @ckarlof - Can you two take a quick look at this Uber PR before @shane-tomlinson scampers off on holidays? |
|
I should probably squash these commits before we merge. |
|
If it's ready for final review, let's get the WIP stuff off of it. |
|
@ckarlof - wip removed. |
|
Renaming title to "feat" (was "feature"), per #1123 |
Yeah, "feature" won't make it in the changelog. |
|
@shane-tomlinson Yeah, thinking from the perspective of the changelog it doesn't seem right to mark a commit as a (also, we have |
| }; | ||
|
|
||
| var CODE_TO_MESSAGES = { | ||
| // errors returned by the auth server | ||
| 999: t('Unexpected error'), | ||
| 110: t('Invalid authentication token in request signature'), | ||
| 110: t('Invalid token'), |
zaach
May 22, 2014
Contributor
I've added the strings label to this PR. 😎
I've added the strings label to this PR.
shane-tomlinson
May 22, 2014
Author
Member
This is a string we already had, so there shouldn't need to be any new ones.
This is a string we already had, so there shouldn't need to be any new ones.
zaach
May 22, 2014
Contributor
Ah, indeed it is.
Ah, indeed it is.
| setTimeout(function () { | ||
| self.logEvent('inactivity:flush'); | ||
| self.flush(); | ||
| // self.logEvent('inactivity:continuation'); |
zaach
May 22, 2014
Contributor
👀 Should this be removed or uncommented?
shane-tomlinson
May 22, 2014
Author
Member
removed. will do.
removed. will do.
|
@zaach - about the commit log - I wasn't sure what to do there. Should we squash into one commit? |
| @@ -134,6 +142,13 @@ function () { | |||
| }, | |||
|
|
|||
| /** | |||
| * Return a metrics log identifier for the error. | |||
zaach
May 22, 2014
Contributor
Kind of a high level code organization question, but would it better to have this as a method in the metrics module? Seems like it would be more cohesive.
Kind of a high level code organization question, but would it better to have this as a method in the metrics module? Seems like it would be more cohesive.
|
Fixes #1119? |
|
@shane-tomlinson : Looks like a great start -- looking forward to poking around the data. A few comments/questions:
|
|
@kparlante - Thanks for the feedback - responses to your questions.
Great point, I'll add it today.
Screen transitions are all done client side, so only one set of navigation timing data. More on navigation timing can be found on MDN. Basically, it's page load performance data, from the client's perspective.
I have the |
* Use SpeedTrap to collect client side metrics * Add screen views and errors to an event stream. * Metrics are sent to the `/metrics` endpoint on document unload or after 10 minutes of inactivity. * Data that is sent to the backend is filtered - only data we expect is sent. * Data collection sample rate is set by server configuration. Other logged events: * users who cancel login from the browser. * complete_reset_password:link_damaged * complete_reset_password:link_expired * complete_signn_up:link_damaged * confirm:too_many_attempts * confirm:resend * confirm_reset_password_resend * login:canceled Others changes: * AuthErrors.toMessage now accepts `forceMessage` * Change AuthErrors.toCode to accept an error object. * Give `Session expired` an error code of 1002. issue #1119
|
I see this adds a fair bit of noise in das Travis Logs (see https://travis-ci.org/mozilla/fxa-content-server/builds/25912446)... Acceptable? Should metrics be disabled for Travis runs? |
|
Do we need to specify a metrics sample rate in the fxa-content-server puppet-config's default.json.erb file for stage/prod? I noticed we added one in server/config/local.json-dist:17-19 and server/config/awsbox.json:9-11 (although the sampleRate is set to "1", which I believe means "log everything" -- I couldn't easily see if the default was "0" which means "log nothing" once this lands on Stage). |
|
Actually, it looks like the default is 0 when I tested locally w/:
Removing this from my server/config/local.json stopped any metrics data from getting logged to my console: |

/metricsendpoint on document unload.forceMessage