Closed
Bug 983360
Opened 11 years ago
Closed 11 years ago
Telemetry experiments: add monitoring data to Telemetry payload
Categories
(Firefox Health Report Graveyard :: Client: Desktop, defect)
Firefox Health Report Graveyard
Client: Desktop
Tracking
(Not tracked)
RESOLVED
FIXED
Firefox 31
People
(Reporter: gfritzsche, Assigned: gfritzsche)
References
Details
Attachments
(1 file, 2 obsolete files)
|
36.35 KB,
patch
|
benjamin
:
review+
|
Details | Diff | Splinter Review |
Forking the telemetry part out from bug 974024, comment 2:
Telemetry payload:
* Log experiments that we considered: if a condition didn't match (or the JS function threw an exception) log the reason that the experiment was not accepted
* Log experiment install/success/failure.
* Log user-disable of an experiment.
* Log normal experiment termination (via script from the experiment itself, or via expiration of the experiment).
| Assignee | ||
Comment 1•11 years ago
|
||
We need to know which which experiments the events occurred for.
Example report:
> 1500 people installed experiment X yesterday, and 150000 people didn't because condition Foo didn't match
| Assignee | ||
Comment 2•11 years ago
|
||
So i think we will need two actual log events: activation success and termination.
"EXPERIMENT_ACTIVATION" can be one of: ACTIVATED=0, INSTALL_FAILURE=1, REJECTED=2.
It will use an additional field for details (rejection reason, failure details).
"EXPERIMENT_TERMINATION" can be one of: USERDISABLED=0, FROM_EXPERIMENT=1, EXPIRED=2, RECHECK=3.
| Assignee | ||
Comment 3•11 years ago
|
||
I'm wondering for this, if it actually makes a difference on the server-/analysis-side whether we submit:
> log("EXPERIMENT_ACTIVATION", [ACTIVATED, id]);
> log("EXPERIMENT_ACTIVATION", [REJECTED, id, "startTime"]);
> ...
... or say:
> log("EXPERIMENT_ACTIVATION_ACTIVATED", [id]);
> log("EXPERIMENT_ACTIVATION_REJECTED", [id, "startTime"]);
> ...
Flags: needinfo?(benjamin)
Comment 4•11 years ago
|
||
It doesn't make a difference at the moment, no. I'll pick the first form. (Although I'd expect "reason" and not "startTime").
Flags: needinfo?(benjamin)
| Assignee | ||
Comment 5•11 years ago
|
||
Rejection examples:
log("EXPERIMENT_ACTIVATION", [REJECTED, id, "startTime"])
log("EXPERIMENT_ACTIVATION", [REJECTED, id, "jsfilter-false"])
log("EXPERIMENT_ACTIVATION", [REJECTED, id, "jsfilter-threw", expection.message])
| Assignee | ||
Comment 6•11 years ago
|
||
I need to finish up tests tomorrow, but this looks reasonable so far.
It required some fixup for the rejection reason propagation and the tests.
Attachment #8394371 -
Flags: review?(benjamin)
| Assignee | ||
Comment 7•11 years ago
|
||
Attachment #8394371 -
Attachment is obsolete: true
Attachment #8394371 -
Flags: review?(benjamin)
Attachment #8394835 -
Flags: review?(benjamin)
| Assignee | ||
Comment 8•11 years ago
|
||
Open question: how to actually tell that an experiment disabled itself?
The only thing i can use at the moment is expecting it to do:
> Experiments.instance().disableExperiment(id, false)
Comment 9•11 years ago
|
||
Yes, that's what they will do. Although I wonder if we shouldn't make .disableExperiment not take the ID, since there's only one experiment at a time...
| Assignee | ||
Comment 10•11 years ago
|
||
That sounds better, i'll file a follow-up.
Comment 11•11 years ago
|
||
Comment on attachment 8394835 [details] [diff] [review]
Experiments telemetry, test coverage, small fixes
>+const TELEMETRY_LOG = Object.freeze({
>+ // log(key, [kind, experimentId, details])
>+ ACTIVATION: Object.freeze({
>+ key: "EXPERIMENT_ACTIVATION",
>+ kind: Object.freeze({
>+ ACTIVATED: 0, // successfully activated
>+ INSTALL_FAILURE: 1, // failed to install the extension
>+ REJECTED: 2, // experiment was rejected because of it's conditions.
>+ }),
>+ }),
>+
>+ // log(key, [kind, experimentId, details])
>+ TERMINATION: Object.freeze({
>+ key: "EXPERIMENT_TERMINATION",
>+ kind: Object.freeze({
>+ USERDISABLED: 0, // the user disabled this experiment
>+ FROM_EXPERIMENT: 1, // the experiment disabled itself
>+ EXPIRED: 2, // experiment expired e.g. by exceeding the end-date
>+ RECHECK: 3, // disabled after re-evaluating conditions
Will the RECHECK case have the condition which failed as REJECTED does?
>+ }),
>+ }),
>+});
Let's not freeze any of this: it's complicated and unnecessary. But also using this below as TELEMETRY_LOG.TERMINATION.kind.USERDISABLED seems verbose. Maybe shorten this structure to:
TLOG.TERMINATION.USER_DISABLED ?
> let active = this._getActiveExperiment();
> let promise = Promise.resolve();
> if (active) {
>- promise = active.stop();
>+ promise = active.stop(-1);
Need constants for this and elsewhere. It's really unclear at the call site what "-1" means here.
>+ let terminationKind = TELEMETRY_LOG.TERMINATION.kind.USERDISABLED;
>+ if (!userDisabled) {
>+ // assuming this comes from the experiment, but how would we tell?
>+ terminationKind = TELEMETRY_LOG.TERMINATION.kind.FROM_EXPERIMENT;
Maybe instead of FROM_EXPERIMENT this should just be "FROM_API"?
> /*
> * Stop running the experiment if it is active.
>- * @param userDisabled (optional) Whether this is disabled by user action, defaults to false.
>+ * @param terminationKind The termination kind, e.g. USERDISABLED or EXPIRED.
> * @return Promise<> Resolved when the operation is complete.
> */
>- stop: function (userDisabled=false) {
>- gLogger.trace("ExperimentEntry::stop() - id=" + this.id + ", userDisabled=" + userDisabled);
>+ stop: function (terminationKind) {
>+ gLogger.trace("ExperimentEntry::stop() - id=" + this.id + ", terminationKind=" + terminationKind);
> if (!this._enabled) {
> gLogger.warning("ExperimentEntry::stop() - experiment not enabled: " + id);
> return Promise.reject();
> }
>
> this._enabled = false;
> let deferred = Promise.defer();
> let updateDates = () => {
>@@ -1328,63 +1379,76 @@ Experiments.ExperimentEntry.prototype =
> let listener = {};
> let handler = addon => {
> if (addon.id !== this._addonId) {
> return;
> }
>
> updateDates();
>
>+ let desc = TELEMETRY_LOG.TERMINATION;
>+ let values = [desc.kind[key] for (key of Object.keys(desc.kind))];
>+ if (values.indexOf(terminationKind) != -1) {
This is very strange, we're basically going string -> int -> string and this is very hard to read. Why don't we just make these string constants to begin with, so:
TELEMETRY_LOG.TERMINATION.EXPIRED = "EXPIRED" and then you can just use the string directly?
Also I see what the -1 is doing above. You should just leave it out by passing stop() and here terminationKind === undefined.
>diff --git a/browser/experiments/test/xpcshell/test_telemetry.js b/browser/experiments/test/xpcshell/test_telemetry.js
>+const TELEMETRY_LOG = Object.freeze({
I don't think you need this in the test: you could just hardcode the values we expect.
Attachment #8394835 -
Flags: review?(benjamin) → review-
| Assignee | ||
Comment 12•11 years ago
|
||
Addressed the review comments. Would like something shorter than TELEMETRY_LOG, but TLOG seems a little cryptic and brevity seems reasonable now.
Attachment #8394835 -
Attachment is obsolete: true
Attachment #8394899 -
Flags: review?(benjamin)
Comment 13•11 years ago
|
||
Comment on attachment 8394899 [details] [diff] [review]
Experiments telemetry, incorporating review comments
>
> let active = this._getActiveExperiment();
> let promise = Promise.resolve();
> if (active) {
>- promise = active.stop();
>+ promise = active.stop(-1);
Forgot a -1?
>+ if (!applicable && reason && reason[0] != "was-active") {
>+ // Report this from here to avoid over-reporting.
>+ let desc = TELEMETRY_LOG.ACTIVATION;
>+ let data = [TELEMETRY_LOG.ACTIVATION.REJECTED, id];
>+ reason.forEach(a => data.push(a));
Not .concat? Push is probably faster, but it's a little hard to read. (And below).
r=me with nits
Attachment #8394899 -
Flags: review?(benjamin) → review+
| Assignee | ||
Comment 14•11 years ago
|
||
Status: NEW → ASSIGNED
Comment 15•11 years ago
|
||
Status: ASSIGNED → RESOLVED
Closed: 11 years ago
Resolution: --- → FIXED
Target Milestone: --- → Firefox 31
Updated•7 years ago
|
Product: Firefox Health Report → Firefox Health Report Graveyard
You need to log in
before you can comment on or make changes to this bug.
Description
•