@hot-updater/plugin-insights 1.0.0-rc.32 → 1.0.0-rc.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/index.cjs +2 -4
- package/dist/client/index.mjs +2 -4
- package/dist/server/contract.cjs +1 -1
- package/dist/server/contract.mjs +1 -1
- package/dist/server/domain.d.cts +1 -11
- package/dist/server/domain.d.mts +1 -11
- package/dist/server/eventInput.cjs +7 -31
- package/dist/server/eventInput.mjs +7 -31
- package/dist/server/eventRow.cjs +2 -2
- package/dist/server/eventRow.d.cts +0 -4
- package/dist/server/eventRow.d.mts +0 -4
- package/dist/server/eventRow.mjs +2 -2
- package/dist/server/index.cjs +1 -1
- package/dist/server/index.d.cts +3 -3
- package/dist/server/index.d.mts +3 -3
- package/dist/server/index.mjs +1 -1
- package/dist/server/modelTypes.d.cts +4 -1
- package/dist/server/modelTypes.d.mts +4 -1
- package/dist/server/overview.cjs +14 -16
- package/dist/server/overview.mjs +14 -16
- package/dist/server/provider.cjs +3 -5
- package/dist/server/provider.mjs +3 -5
- package/dist/server/reads.cjs +32 -47
- package/dist/server/reads.d.cts +0 -11
- package/dist/server/reads.d.mts +0 -11
- package/dist/server/reads.mjs +32 -47
- package/dist/server/recordEvent.cjs +1 -19
- package/dist/server/recordEvent.mjs +1 -19
- package/dist/server/schema.cjs +35 -24
- package/dist/server/schema.d.cts +6 -6
- package/dist/server/schema.d.mts +6 -6
- package/dist/server/schema.mjs +35 -24
- package/package.json +5 -5
package/dist/server/reads.cjs
CHANGED
|
@@ -365,7 +365,7 @@ const lifetimeMetrics = async (db, release) => {
|
|
|
365
365
|
})).rows;
|
|
366
366
|
return {
|
|
367
367
|
downloads: lifetime?.downloads ?? 0,
|
|
368
|
-
|
|
368
|
+
applies: lifetime?.applies ?? 0,
|
|
369
369
|
failedLaunches: lifetime?.failed_launches ?? 0
|
|
370
370
|
};
|
|
371
371
|
};
|
|
@@ -474,21 +474,18 @@ const isText = (value, maxLength) => typeof value === "string" && value.length >
|
|
|
474
474
|
const failed = (...rows) => (0, _hot_updater_plugin_core.countDistinct)((0, _hot_updater_plugin_core.mergeDistinct)(rows.flat().map((row) => row.failed_users)));
|
|
475
475
|
/** Entries of a count map, most first, then in key order. */
|
|
476
476
|
const mostFirst = (counts) => [...counts].sort(([leftKey, left], [rightKey, right]) => right.events - left.events || (0, _hot_updater_plugin_core.compareUtf8)(leftKey, rightKey)).map(([, entry]) => entry);
|
|
477
|
-
/**
|
|
477
|
+
/** The stages a failure row records: where an update failed. */
|
|
478
|
+
const FAILURE_STAGES = /* @__PURE__ */ new Set([
|
|
479
|
+
"check",
|
|
480
|
+
"download",
|
|
481
|
+
"install",
|
|
482
|
+
"unknown"
|
|
483
|
+
]);
|
|
484
|
+
/** Failure rows as their breakdown by stage, reason, and detail. */
|
|
478
485
|
const breakdownOf = (rows) => {
|
|
479
486
|
const failures = /* @__PURE__ */ new Map();
|
|
480
|
-
const exits = /* @__PURE__ */ new Map();
|
|
481
487
|
for (const { stage, reason, detail, events } of rows) {
|
|
482
488
|
if (events <= 0) continue;
|
|
483
|
-
if (stage === "launch") {
|
|
484
|
-
const exit = exits.get(reason) ?? {
|
|
485
|
-
value: reason,
|
|
486
|
-
events: 0
|
|
487
|
-
};
|
|
488
|
-
exit.events += events;
|
|
489
|
-
exits.set(reason, exit);
|
|
490
|
-
continue;
|
|
491
|
-
}
|
|
492
489
|
const key = JSON.stringify([stage, reason]);
|
|
493
490
|
const entry = failures.get(key) ?? {
|
|
494
491
|
value: {
|
|
@@ -507,37 +504,30 @@ const breakdownOf = (rows) => {
|
|
|
507
504
|
entry.details.set(detail, known);
|
|
508
505
|
failures.set(key, entry);
|
|
509
506
|
}
|
|
510
|
-
return {
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
}),
|
|
528
|
-
byExitReason: mostFirst(exits).map(({ value, events }) => ({
|
|
529
|
-
exitReason: value,
|
|
530
|
-
events
|
|
531
|
-
}))
|
|
532
|
-
};
|
|
507
|
+
return mostFirst(failures).map(({ value, events }) => {
|
|
508
|
+
const { details } = failures.get(JSON.stringify([value.stage, value.reason]));
|
|
509
|
+
return {
|
|
510
|
+
...value,
|
|
511
|
+
events,
|
|
512
|
+
details: mostFirst(details).map(({ value: detail, events }) => {
|
|
513
|
+
const [resource, httpStatus, originCode, transport] = JSON.parse(detail);
|
|
514
|
+
return {
|
|
515
|
+
resource,
|
|
516
|
+
httpStatus,
|
|
517
|
+
originCode,
|
|
518
|
+
transport,
|
|
519
|
+
events
|
|
520
|
+
};
|
|
521
|
+
})
|
|
522
|
+
};
|
|
523
|
+
});
|
|
533
524
|
};
|
|
534
525
|
/**
|
|
535
526
|
* A release's or a channel's update failures. Since a release's first
|
|
536
527
|
* report: its lifetime counters and failed installations. Over a time range
|
|
537
|
-
* of at most 30 days: failures, failed checks, the breakdown by stage,
|
|
538
|
-
* reason, and detail,
|
|
539
|
-
*
|
|
540
|
-
* failed installations from their sketches. A release reads hourly rows, a
|
|
528
|
+
* of at most 30 days: failures, failed checks, and the breakdown by stage,
|
|
529
|
+
* reason, and detail, all summed from the breakdown's hourly rows; downloads
|
|
530
|
+
* from the counters; failed installations from their sketches. A release reads hourly rows, a
|
|
541
531
|
* channel daily rows past 48 hours like its activity; the breakdown's rows
|
|
542
532
|
* are hourly, so its coverage is the raw period's.
|
|
543
533
|
*/
|
|
@@ -624,13 +614,12 @@ const getUpdateFailures = async (db, input, now, retention) => {
|
|
|
624
614
|
}))
|
|
625
615
|
]);
|
|
626
616
|
const total = (field) => counters.reduce((sum, row) => sum + row[field], 0);
|
|
627
|
-
const scoped =
|
|
617
|
+
const scoped = rows.filter((row) => FAILURE_STAGES.has(row.stage) && (releaseId === void 0 || row.release_id === releaseId));
|
|
628
618
|
const failuresAt = (counted) => scoped.reduce((sum, row) => sum + (counted(row.stage) ? Math.max(0, row.events) : 0), 0);
|
|
629
|
-
const { breakdown, byExitReason } = breakdownOf(scoped);
|
|
630
619
|
return {
|
|
631
620
|
coverage: coverageOf(timeRange.start, kept.hour),
|
|
632
621
|
measuredAtMs: at,
|
|
633
|
-
failedUpdates: failuresAt((stage) => stage !== "check"
|
|
622
|
+
failedUpdates: failuresAt((stage) => stage !== "check"),
|
|
634
623
|
failedInstallations: failed(failures),
|
|
635
624
|
downloads: total("downloads"),
|
|
636
625
|
patchDownloads: total("patch_downloads"),
|
|
@@ -640,11 +629,7 @@ const getUpdateFailures = async (db, input, now, retention) => {
|
|
|
640
629
|
failedInstallations: failed(checks),
|
|
641
630
|
activeInstallations: (0, _hot_updater_plugin_core.countDistinct)((0, _hot_updater_plugin_core.mergeDistinct)(active.map((row) => row.activity_users)))
|
|
642
631
|
} } : {},
|
|
643
|
-
breakdown
|
|
644
|
-
recoveries: {
|
|
645
|
-
failedLaunches: total("failed_launches"),
|
|
646
|
-
byExitReason
|
|
647
|
-
}
|
|
632
|
+
breakdown: breakdownOf(scoped)
|
|
648
633
|
};
|
|
649
634
|
};
|
|
650
635
|
//#endregion
|
package/dist/server/reads.d.cts
CHANGED
|
@@ -44,17 +44,6 @@ interface InsightsUpdateFailures {
|
|
|
44
44
|
};
|
|
45
45
|
/** Over a time range: failures by stage and reason, most first. */
|
|
46
46
|
readonly breakdown?: readonly InsightsFailureBreakdown[];
|
|
47
|
-
/**
|
|
48
|
-
* Over a time range: failed launches, and the recoveries whose crashed
|
|
49
|
-
* process exited for a reason Android 11+ reported, by reason, most first.
|
|
50
|
-
*/
|
|
51
|
-
readonly recoveries?: {
|
|
52
|
-
readonly failedLaunches: number;
|
|
53
|
-
readonly byExitReason: readonly {
|
|
54
|
-
readonly exitReason: string;
|
|
55
|
-
readonly events: number;
|
|
56
|
-
}[];
|
|
57
|
-
};
|
|
58
47
|
}
|
|
59
48
|
//#endregion
|
|
60
49
|
export { InsightsFailureBreakdown, InsightsUpdateFailures, InsightsUpdateFailuresInput };
|
package/dist/server/reads.d.mts
CHANGED
|
@@ -44,17 +44,6 @@ interface InsightsUpdateFailures {
|
|
|
44
44
|
};
|
|
45
45
|
/** Over a time range: failures by stage and reason, most first. */
|
|
46
46
|
readonly breakdown?: readonly InsightsFailureBreakdown[];
|
|
47
|
-
/**
|
|
48
|
-
* Over a time range: failed launches, and the recoveries whose crashed
|
|
49
|
-
* process exited for a reason Android 11+ reported, by reason, most first.
|
|
50
|
-
*/
|
|
51
|
-
readonly recoveries?: {
|
|
52
|
-
readonly failedLaunches: number;
|
|
53
|
-
readonly byExitReason: readonly {
|
|
54
|
-
readonly exitReason: string;
|
|
55
|
-
readonly events: number;
|
|
56
|
-
}[];
|
|
57
|
-
};
|
|
58
47
|
}
|
|
59
48
|
//#endregion
|
|
60
49
|
export { InsightsFailureBreakdown, InsightsUpdateFailures, InsightsUpdateFailuresInput };
|
package/dist/server/reads.mjs
CHANGED
|
@@ -365,7 +365,7 @@ const lifetimeMetrics = async (db, release) => {
|
|
|
365
365
|
})).rows;
|
|
366
366
|
return {
|
|
367
367
|
downloads: lifetime?.downloads ?? 0,
|
|
368
|
-
|
|
368
|
+
applies: lifetime?.applies ?? 0,
|
|
369
369
|
failedLaunches: lifetime?.failed_launches ?? 0
|
|
370
370
|
};
|
|
371
371
|
};
|
|
@@ -474,21 +474,18 @@ const isText = (value, maxLength) => typeof value === "string" && value.length >
|
|
|
474
474
|
const failed = (...rows) => countDistinct(mergeDistinct(rows.flat().map((row) => row.failed_users)));
|
|
475
475
|
/** Entries of a count map, most first, then in key order. */
|
|
476
476
|
const mostFirst = (counts) => [...counts].sort(([leftKey, left], [rightKey, right]) => right.events - left.events || compareUtf8(leftKey, rightKey)).map(([, entry]) => entry);
|
|
477
|
-
/**
|
|
477
|
+
/** The stages a failure row records: where an update failed. */
|
|
478
|
+
const FAILURE_STAGES = /* @__PURE__ */ new Set([
|
|
479
|
+
"check",
|
|
480
|
+
"download",
|
|
481
|
+
"install",
|
|
482
|
+
"unknown"
|
|
483
|
+
]);
|
|
484
|
+
/** Failure rows as their breakdown by stage, reason, and detail. */
|
|
478
485
|
const breakdownOf = (rows) => {
|
|
479
486
|
const failures = /* @__PURE__ */ new Map();
|
|
480
|
-
const exits = /* @__PURE__ */ new Map();
|
|
481
487
|
for (const { stage, reason, detail, events } of rows) {
|
|
482
488
|
if (events <= 0) continue;
|
|
483
|
-
if (stage === "launch") {
|
|
484
|
-
const exit = exits.get(reason) ?? {
|
|
485
|
-
value: reason,
|
|
486
|
-
events: 0
|
|
487
|
-
};
|
|
488
|
-
exit.events += events;
|
|
489
|
-
exits.set(reason, exit);
|
|
490
|
-
continue;
|
|
491
|
-
}
|
|
492
489
|
const key = JSON.stringify([stage, reason]);
|
|
493
490
|
const entry = failures.get(key) ?? {
|
|
494
491
|
value: {
|
|
@@ -507,37 +504,30 @@ const breakdownOf = (rows) => {
|
|
|
507
504
|
entry.details.set(detail, known);
|
|
508
505
|
failures.set(key, entry);
|
|
509
506
|
}
|
|
510
|
-
return {
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
}),
|
|
528
|
-
byExitReason: mostFirst(exits).map(({ value, events }) => ({
|
|
529
|
-
exitReason: value,
|
|
530
|
-
events
|
|
531
|
-
}))
|
|
532
|
-
};
|
|
507
|
+
return mostFirst(failures).map(({ value, events }) => {
|
|
508
|
+
const { details } = failures.get(JSON.stringify([value.stage, value.reason]));
|
|
509
|
+
return {
|
|
510
|
+
...value,
|
|
511
|
+
events,
|
|
512
|
+
details: mostFirst(details).map(({ value: detail, events }) => {
|
|
513
|
+
const [resource, httpStatus, originCode, transport] = JSON.parse(detail);
|
|
514
|
+
return {
|
|
515
|
+
resource,
|
|
516
|
+
httpStatus,
|
|
517
|
+
originCode,
|
|
518
|
+
transport,
|
|
519
|
+
events
|
|
520
|
+
};
|
|
521
|
+
})
|
|
522
|
+
};
|
|
523
|
+
});
|
|
533
524
|
};
|
|
534
525
|
/**
|
|
535
526
|
* A release's or a channel's update failures. Since a release's first
|
|
536
527
|
* report: its lifetime counters and failed installations. Over a time range
|
|
537
|
-
* of at most 30 days: failures, failed checks, the breakdown by stage,
|
|
538
|
-
* reason, and detail,
|
|
539
|
-
*
|
|
540
|
-
* failed installations from their sketches. A release reads hourly rows, a
|
|
528
|
+
* of at most 30 days: failures, failed checks, and the breakdown by stage,
|
|
529
|
+
* reason, and detail, all summed from the breakdown's hourly rows; downloads
|
|
530
|
+
* from the counters; failed installations from their sketches. A release reads hourly rows, a
|
|
541
531
|
* channel daily rows past 48 hours like its activity; the breakdown's rows
|
|
542
532
|
* are hourly, so its coverage is the raw period's.
|
|
543
533
|
*/
|
|
@@ -624,13 +614,12 @@ const getUpdateFailures = async (db, input, now, retention) => {
|
|
|
624
614
|
}))
|
|
625
615
|
]);
|
|
626
616
|
const total = (field) => counters.reduce((sum, row) => sum + row[field], 0);
|
|
627
|
-
const scoped =
|
|
617
|
+
const scoped = rows.filter((row) => FAILURE_STAGES.has(row.stage) && (releaseId === void 0 || row.release_id === releaseId));
|
|
628
618
|
const failuresAt = (counted) => scoped.reduce((sum, row) => sum + (counted(row.stage) ? Math.max(0, row.events) : 0), 0);
|
|
629
|
-
const { breakdown, byExitReason } = breakdownOf(scoped);
|
|
630
619
|
return {
|
|
631
620
|
coverage: coverageOf(timeRange.start, kept.hour),
|
|
632
621
|
measuredAtMs: at,
|
|
633
|
-
failedUpdates: failuresAt((stage) => stage !== "check"
|
|
622
|
+
failedUpdates: failuresAt((stage) => stage !== "check"),
|
|
634
623
|
failedInstallations: failed(failures),
|
|
635
624
|
downloads: total("downloads"),
|
|
636
625
|
patchDownloads: total("patch_downloads"),
|
|
@@ -640,11 +629,7 @@ const getUpdateFailures = async (db, input, now, retention) => {
|
|
|
640
629
|
failedInstallations: failed(checks),
|
|
641
630
|
activeInstallations: countDistinct(mergeDistinct(active.map((row) => row.activity_users)))
|
|
642
631
|
} } : {},
|
|
643
|
-
breakdown
|
|
644
|
-
recoveries: {
|
|
645
|
-
failedLaunches: total("failed_launches"),
|
|
646
|
-
byExitReason
|
|
647
|
-
}
|
|
632
|
+
breakdown: breakdownOf(scoped)
|
|
648
633
|
};
|
|
649
634
|
};
|
|
650
635
|
//#endregion
|
|
@@ -112,7 +112,7 @@ const countEvent = (tx, event) => {
|
|
|
112
112
|
const counters = {
|
|
113
113
|
...Object.fromEntries([
|
|
114
114
|
["downloads", delta.downloads],
|
|
115
|
-
["
|
|
115
|
+
["applies", delta.applies],
|
|
116
116
|
["failed_launches", delta.failedLaunches]
|
|
117
117
|
].filter(([, value]) => value !== 0)),
|
|
118
118
|
...delta.downloads === 0 ? {} : patchCounters(event)
|
|
@@ -235,23 +235,6 @@ const countFailure = (tx, event) => {
|
|
|
235
235
|
detail: failureDetail(failure)
|
|
236
236
|
}, { events: 1 }, { shardBy });
|
|
237
237
|
};
|
|
238
|
-
/**
|
|
239
|
-
* A recovery's exit reason, which Android 11+ reports, in the breakdown of
|
|
240
|
-
* the release whose launch failed: stage `launch`, the reason as its reason.
|
|
241
|
-
*/
|
|
242
|
-
const countExit = (tx, event) => {
|
|
243
|
-
const exit = event.metadata.previous_process_exit;
|
|
244
|
-
if (event.type !== "RECOVERED" || exit === void 0) return;
|
|
245
|
-
tx.aggregate("insights_failures", {
|
|
246
|
-
platform: event.platform,
|
|
247
|
-
channel: event.channel,
|
|
248
|
-
bucket_start_ms: hourOf(event.received_at_ms),
|
|
249
|
-
release_id: event.from_release_id ?? "",
|
|
250
|
-
stage: "launch",
|
|
251
|
-
reason: exit,
|
|
252
|
-
detail: ""
|
|
253
|
-
}, { events: 1 }, { shardBy: event.install_id });
|
|
254
|
-
};
|
|
255
238
|
const isNewer = (event, head) => event.received_at_ms !== head.received_at_ms ? event.received_at_ms > head.received_at_ms : (0, _hot_updater_plugin_core.compareUtf8)(event.id, head.id) > 0;
|
|
256
239
|
/** What an UNCHANGED report must share with its installation's head to repeat it. */
|
|
257
240
|
const REPEATED_FIELDS = [
|
|
@@ -296,7 +279,6 @@ const recordEvent = (db, event) => {
|
|
|
296
279
|
return;
|
|
297
280
|
}
|
|
298
281
|
countEvent(tx, event);
|
|
299
|
-
countExit(tx, event);
|
|
300
282
|
if (previous !== null && !isNewer(event, previous)) return;
|
|
301
283
|
if (previous === null) tx.create("bundle_event_heads", event);
|
|
302
284
|
else {
|
|
@@ -112,7 +112,7 @@ const countEvent = (tx, event) => {
|
|
|
112
112
|
const counters = {
|
|
113
113
|
...Object.fromEntries([
|
|
114
114
|
["downloads", delta.downloads],
|
|
115
|
-
["
|
|
115
|
+
["applies", delta.applies],
|
|
116
116
|
["failed_launches", delta.failedLaunches]
|
|
117
117
|
].filter(([, value]) => value !== 0)),
|
|
118
118
|
...delta.downloads === 0 ? {} : patchCounters(event)
|
|
@@ -235,23 +235,6 @@ const countFailure = (tx, event) => {
|
|
|
235
235
|
detail: failureDetail(failure)
|
|
236
236
|
}, { events: 1 }, { shardBy });
|
|
237
237
|
};
|
|
238
|
-
/**
|
|
239
|
-
* A recovery's exit reason, which Android 11+ reports, in the breakdown of
|
|
240
|
-
* the release whose launch failed: stage `launch`, the reason as its reason.
|
|
241
|
-
*/
|
|
242
|
-
const countExit = (tx, event) => {
|
|
243
|
-
const exit = event.metadata.previous_process_exit;
|
|
244
|
-
if (event.type !== "RECOVERED" || exit === void 0) return;
|
|
245
|
-
tx.aggregate("insights_failures", {
|
|
246
|
-
platform: event.platform,
|
|
247
|
-
channel: event.channel,
|
|
248
|
-
bucket_start_ms: hourOf(event.received_at_ms),
|
|
249
|
-
release_id: event.from_release_id ?? "",
|
|
250
|
-
stage: "launch",
|
|
251
|
-
reason: exit,
|
|
252
|
-
detail: ""
|
|
253
|
-
}, { events: 1 }, { shardBy: event.install_id });
|
|
254
|
-
};
|
|
255
238
|
const isNewer = (event, head) => event.received_at_ms !== head.received_at_ms ? event.received_at_ms > head.received_at_ms : compareUtf8(event.id, head.id) > 0;
|
|
256
239
|
/** What an UNCHANGED report must share with its installation's head to repeat it. */
|
|
257
240
|
const REPEATED_FIELDS = [
|
|
@@ -296,7 +279,6 @@ const recordEvent = (db, event) => {
|
|
|
296
279
|
return;
|
|
297
280
|
}
|
|
298
281
|
countEvent(tx, event);
|
|
299
|
-
countExit(tx, event);
|
|
300
282
|
if (previous !== null && !isNewer(event, previous)) return;
|
|
301
283
|
if (previous === null) tx.create("bundle_event_heads", event);
|
|
302
284
|
else {
|
package/dist/server/schema.cjs
CHANGED
|
@@ -206,29 +206,42 @@ const window = {
|
|
|
206
206
|
eq: ["identity"],
|
|
207
207
|
sort: ["bucket_start_ms"]
|
|
208
208
|
};
|
|
209
|
+
/** What a release or channel row counts in every period kind. */
|
|
210
|
+
const WINDOW_COUNTERS = [
|
|
211
|
+
"downloads",
|
|
212
|
+
"failed_launches",
|
|
213
|
+
"patch_downloads",
|
|
214
|
+
"patch_fallbacks"
|
|
215
|
+
];
|
|
209
216
|
/**
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
* lifetime row counts launches, which the bundle list reads and no windowed
|
|
214
|
-
* read sums. It also counts the release's failed updates (`failed_updates`),
|
|
215
|
-
* since no breakdown row outlives the raw period; windowed reads sum
|
|
216
|
-
* `insights_failures` instead.
|
|
217
|
+
* Hourly or daily counters: a release or channel row counts downloads,
|
|
218
|
+
* launches that crashed and recovered (`failed_launches`), and downloads a
|
|
219
|
+
* patch delivered and those that fell back from one.
|
|
217
220
|
*/
|
|
218
221
|
const counters = (retention) => (0, _hot_updater_plugin_core.defineAggregate)(identityFields, {
|
|
222
|
+
key: ["identity", "bucket_start_ms"],
|
|
223
|
+
counters: WINDOW_COUNTERS,
|
|
224
|
+
shards: COUNTER_SHARDS,
|
|
225
|
+
batched: true,
|
|
226
|
+
indexes: { window },
|
|
227
|
+
retention
|
|
228
|
+
});
|
|
229
|
+
/**
|
|
230
|
+
* A release's counters since its first report, at bucket 0: the windowed
|
|
231
|
+
* counters, its applies, which the bundle list reads, and its failed updates
|
|
232
|
+
* (`failed_updates`), since no breakdown row outlives the raw period; windowed
|
|
233
|
+
* reads sum `insights_failures` instead.
|
|
234
|
+
*/
|
|
235
|
+
const lifetimeCounters = () => (0, _hot_updater_plugin_core.defineAggregate)(identityFields, {
|
|
219
236
|
key: ["identity", "bucket_start_ms"],
|
|
220
237
|
counters: [
|
|
221
|
-
|
|
222
|
-
"
|
|
223
|
-
"
|
|
224
|
-
"failed_updates",
|
|
225
|
-
"patch_downloads",
|
|
226
|
-
"patch_fallbacks"
|
|
238
|
+
...WINDOW_COUNTERS,
|
|
239
|
+
"applies",
|
|
240
|
+
"failed_updates"
|
|
227
241
|
],
|
|
228
242
|
shards: COUNTER_SHARDS,
|
|
229
243
|
batched: true,
|
|
230
|
-
indexes: { window }
|
|
231
|
-
...retention === void 0 ? {} : { retention }
|
|
244
|
+
indexes: { window }
|
|
232
245
|
});
|
|
233
246
|
/**
|
|
234
247
|
* Unique-installation sketches of one period kind: a usage row's active
|
|
@@ -252,14 +265,12 @@ const lifetimeSketches = () => (0, _hot_updater_plugin_core.defineAggregate)(ide
|
|
|
252
265
|
indexes: { window }
|
|
253
266
|
});
|
|
254
267
|
/**
|
|
255
|
-
* Update failures by what failed,
|
|
256
|
-
*
|
|
257
|
-
*
|
|
258
|
-
*
|
|
259
|
-
*
|
|
260
|
-
*
|
|
261
|
-
* `launch` and its reason the exit reason, with an empty detail. Every index
|
|
262
|
-
* is in key order, so its counters stay blind increments.
|
|
268
|
+
* Update failures by what failed, a row an hour. `release_id` is the failed
|
|
269
|
+
* update's target release, or empty for a failed check or an unknown target.
|
|
270
|
+
* `stage` and `reason` say where and why it failed, and `detail` what else
|
|
271
|
+
* the client knew, as the JSON array `[resource, httpStatus, originCode,
|
|
272
|
+
* transport]`. Every index is in key order, so its counters stay blind
|
|
273
|
+
* increments.
|
|
263
274
|
*/
|
|
264
275
|
const insightsFailures = (retention) => (0, _hot_updater_plugin_core.defineAggregate)({
|
|
265
276
|
platform: {
|
|
@@ -459,7 +470,7 @@ const createInsightsSchema = ({ rawDays, dailyDays } = DEFAULT_INSIGHTS_RETENTIO
|
|
|
459
470
|
insights_overview_daily: counters(daily),
|
|
460
471
|
insights_sketches_daily: sketches(daily),
|
|
461
472
|
/** A release's counters since its first event, and its failed installations: kept. */
|
|
462
|
-
insights_overview_lifetime:
|
|
473
|
+
insights_overview_lifetime: lifetimeCounters(),
|
|
463
474
|
insights_sketches_lifetime: lifetimeSketches(),
|
|
464
475
|
insights_distribution: insightsDistribution(daily),
|
|
465
476
|
insights_latest_by_bundle: insightsLatestByBundle(daily),
|
package/dist/server/schema.d.cts
CHANGED
|
@@ -153,7 +153,7 @@ declare const createInsightsSchema: ({ rawDays, dailyDays }?: InsightsRetention)
|
|
|
153
153
|
readonly bucket_start_ms: {
|
|
154
154
|
readonly type: "integer";
|
|
155
155
|
};
|
|
156
|
-
}, "downloads" | "
|
|
156
|
+
}, "downloads" | "failed_launches" | "patch_downloads" | "patch_fallbacks", {
|
|
157
157
|
readonly window: {
|
|
158
158
|
readonly eq: readonly ["identity"];
|
|
159
159
|
readonly sort: readonly ["bucket_start_ms"];
|
|
@@ -182,7 +182,7 @@ declare const createInsightsSchema: ({ rawDays, dailyDays }?: InsightsRetention)
|
|
|
182
182
|
readonly bucket_start_ms: {
|
|
183
183
|
readonly type: "integer";
|
|
184
184
|
};
|
|
185
|
-
}, "downloads" | "
|
|
185
|
+
}, "downloads" | "failed_launches" | "patch_downloads" | "patch_fallbacks", {
|
|
186
186
|
readonly window: {
|
|
187
187
|
readonly eq: readonly ["identity"];
|
|
188
188
|
readonly sort: readonly ["bucket_start_ms"];
|
|
@@ -211,7 +211,7 @@ declare const createInsightsSchema: ({ rawDays, dailyDays }?: InsightsRetention)
|
|
|
211
211
|
readonly bucket_start_ms: {
|
|
212
212
|
readonly type: "integer";
|
|
213
213
|
};
|
|
214
|
-
}, "downloads" | "
|
|
214
|
+
}, "downloads" | "failed_launches" | "patch_downloads" | "patch_fallbacks" | "applies" | "failed_updates", {
|
|
215
215
|
readonly window: {
|
|
216
216
|
readonly eq: readonly ["identity"];
|
|
217
217
|
readonly sort: readonly ["bucket_start_ms"];
|
|
@@ -488,7 +488,7 @@ declare const insightsSchema: {
|
|
|
488
488
|
readonly bucket_start_ms: {
|
|
489
489
|
readonly type: "integer";
|
|
490
490
|
};
|
|
491
|
-
}, "downloads" | "
|
|
491
|
+
}, "downloads" | "failed_launches" | "patch_downloads" | "patch_fallbacks", {
|
|
492
492
|
readonly window: {
|
|
493
493
|
readonly eq: readonly ["identity"];
|
|
494
494
|
readonly sort: readonly ["bucket_start_ms"];
|
|
@@ -517,7 +517,7 @@ declare const insightsSchema: {
|
|
|
517
517
|
readonly bucket_start_ms: {
|
|
518
518
|
readonly type: "integer";
|
|
519
519
|
};
|
|
520
|
-
}, "downloads" | "
|
|
520
|
+
}, "downloads" | "failed_launches" | "patch_downloads" | "patch_fallbacks", {
|
|
521
521
|
readonly window: {
|
|
522
522
|
readonly eq: readonly ["identity"];
|
|
523
523
|
readonly sort: readonly ["bucket_start_ms"];
|
|
@@ -546,7 +546,7 @@ declare const insightsSchema: {
|
|
|
546
546
|
readonly bucket_start_ms: {
|
|
547
547
|
readonly type: "integer";
|
|
548
548
|
};
|
|
549
|
-
}, "downloads" | "
|
|
549
|
+
}, "downloads" | "failed_launches" | "patch_downloads" | "patch_fallbacks" | "applies" | "failed_updates", {
|
|
550
550
|
readonly window: {
|
|
551
551
|
readonly eq: readonly ["identity"];
|
|
552
552
|
readonly sort: readonly ["bucket_start_ms"];
|
package/dist/server/schema.d.mts
CHANGED
|
@@ -153,7 +153,7 @@ declare const createInsightsSchema: ({ rawDays, dailyDays }?: InsightsRetention)
|
|
|
153
153
|
readonly bucket_start_ms: {
|
|
154
154
|
readonly type: "integer";
|
|
155
155
|
};
|
|
156
|
-
}, "downloads" | "
|
|
156
|
+
}, "downloads" | "failed_launches" | "patch_downloads" | "patch_fallbacks", {
|
|
157
157
|
readonly window: {
|
|
158
158
|
readonly eq: readonly ["identity"];
|
|
159
159
|
readonly sort: readonly ["bucket_start_ms"];
|
|
@@ -182,7 +182,7 @@ declare const createInsightsSchema: ({ rawDays, dailyDays }?: InsightsRetention)
|
|
|
182
182
|
readonly bucket_start_ms: {
|
|
183
183
|
readonly type: "integer";
|
|
184
184
|
};
|
|
185
|
-
}, "downloads" | "
|
|
185
|
+
}, "downloads" | "failed_launches" | "patch_downloads" | "patch_fallbacks", {
|
|
186
186
|
readonly window: {
|
|
187
187
|
readonly eq: readonly ["identity"];
|
|
188
188
|
readonly sort: readonly ["bucket_start_ms"];
|
|
@@ -211,7 +211,7 @@ declare const createInsightsSchema: ({ rawDays, dailyDays }?: InsightsRetention)
|
|
|
211
211
|
readonly bucket_start_ms: {
|
|
212
212
|
readonly type: "integer";
|
|
213
213
|
};
|
|
214
|
-
}, "downloads" | "
|
|
214
|
+
}, "downloads" | "failed_launches" | "patch_downloads" | "patch_fallbacks" | "applies" | "failed_updates", {
|
|
215
215
|
readonly window: {
|
|
216
216
|
readonly eq: readonly ["identity"];
|
|
217
217
|
readonly sort: readonly ["bucket_start_ms"];
|
|
@@ -488,7 +488,7 @@ declare const insightsSchema: {
|
|
|
488
488
|
readonly bucket_start_ms: {
|
|
489
489
|
readonly type: "integer";
|
|
490
490
|
};
|
|
491
|
-
}, "downloads" | "
|
|
491
|
+
}, "downloads" | "failed_launches" | "patch_downloads" | "patch_fallbacks", {
|
|
492
492
|
readonly window: {
|
|
493
493
|
readonly eq: readonly ["identity"];
|
|
494
494
|
readonly sort: readonly ["bucket_start_ms"];
|
|
@@ -517,7 +517,7 @@ declare const insightsSchema: {
|
|
|
517
517
|
readonly bucket_start_ms: {
|
|
518
518
|
readonly type: "integer";
|
|
519
519
|
};
|
|
520
|
-
}, "downloads" | "
|
|
520
|
+
}, "downloads" | "failed_launches" | "patch_downloads" | "patch_fallbacks", {
|
|
521
521
|
readonly window: {
|
|
522
522
|
readonly eq: readonly ["identity"];
|
|
523
523
|
readonly sort: readonly ["bucket_start_ms"];
|
|
@@ -546,7 +546,7 @@ declare const insightsSchema: {
|
|
|
546
546
|
readonly bucket_start_ms: {
|
|
547
547
|
readonly type: "integer";
|
|
548
548
|
};
|
|
549
|
-
}, "downloads" | "
|
|
549
|
+
}, "downloads" | "failed_launches" | "patch_downloads" | "patch_fallbacks" | "applies" | "failed_updates", {
|
|
550
550
|
readonly window: {
|
|
551
551
|
readonly eq: readonly ["identity"];
|
|
552
552
|
readonly sort: readonly ["bucket_start_ms"];
|
package/dist/server/schema.mjs
CHANGED
|
@@ -206,29 +206,42 @@ const window = {
|
|
|
206
206
|
eq: ["identity"],
|
|
207
207
|
sort: ["bucket_start_ms"]
|
|
208
208
|
};
|
|
209
|
+
/** What a release or channel row counts in every period kind. */
|
|
210
|
+
const WINDOW_COUNTERS = [
|
|
211
|
+
"downloads",
|
|
212
|
+
"failed_launches",
|
|
213
|
+
"patch_downloads",
|
|
214
|
+
"patch_fallbacks"
|
|
215
|
+
];
|
|
209
216
|
/**
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
* lifetime row counts launches, which the bundle list reads and no windowed
|
|
214
|
-
* read sums. It also counts the release's failed updates (`failed_updates`),
|
|
215
|
-
* since no breakdown row outlives the raw period; windowed reads sum
|
|
216
|
-
* `insights_failures` instead.
|
|
217
|
+
* Hourly or daily counters: a release or channel row counts downloads,
|
|
218
|
+
* launches that crashed and recovered (`failed_launches`), and downloads a
|
|
219
|
+
* patch delivered and those that fell back from one.
|
|
217
220
|
*/
|
|
218
221
|
const counters = (retention) => defineAggregate(identityFields, {
|
|
222
|
+
key: ["identity", "bucket_start_ms"],
|
|
223
|
+
counters: WINDOW_COUNTERS,
|
|
224
|
+
shards: COUNTER_SHARDS,
|
|
225
|
+
batched: true,
|
|
226
|
+
indexes: { window },
|
|
227
|
+
retention
|
|
228
|
+
});
|
|
229
|
+
/**
|
|
230
|
+
* A release's counters since its first report, at bucket 0: the windowed
|
|
231
|
+
* counters, its applies, which the bundle list reads, and its failed updates
|
|
232
|
+
* (`failed_updates`), since no breakdown row outlives the raw period; windowed
|
|
233
|
+
* reads sum `insights_failures` instead.
|
|
234
|
+
*/
|
|
235
|
+
const lifetimeCounters = () => defineAggregate(identityFields, {
|
|
219
236
|
key: ["identity", "bucket_start_ms"],
|
|
220
237
|
counters: [
|
|
221
|
-
|
|
222
|
-
"
|
|
223
|
-
"
|
|
224
|
-
"failed_updates",
|
|
225
|
-
"patch_downloads",
|
|
226
|
-
"patch_fallbacks"
|
|
238
|
+
...WINDOW_COUNTERS,
|
|
239
|
+
"applies",
|
|
240
|
+
"failed_updates"
|
|
227
241
|
],
|
|
228
242
|
shards: COUNTER_SHARDS,
|
|
229
243
|
batched: true,
|
|
230
|
-
indexes: { window }
|
|
231
|
-
...retention === void 0 ? {} : { retention }
|
|
244
|
+
indexes: { window }
|
|
232
245
|
});
|
|
233
246
|
/**
|
|
234
247
|
* Unique-installation sketches of one period kind: a usage row's active
|
|
@@ -252,14 +265,12 @@ const lifetimeSketches = () => defineAggregate(identityFields, {
|
|
|
252
265
|
indexes: { window }
|
|
253
266
|
});
|
|
254
267
|
/**
|
|
255
|
-
* Update failures by what failed,
|
|
256
|
-
*
|
|
257
|
-
*
|
|
258
|
-
*
|
|
259
|
-
*
|
|
260
|
-
*
|
|
261
|
-
* `launch` and its reason the exit reason, with an empty detail. Every index
|
|
262
|
-
* is in key order, so its counters stay blind increments.
|
|
268
|
+
* Update failures by what failed, a row an hour. `release_id` is the failed
|
|
269
|
+
* update's target release, or empty for a failed check or an unknown target.
|
|
270
|
+
* `stage` and `reason` say where and why it failed, and `detail` what else
|
|
271
|
+
* the client knew, as the JSON array `[resource, httpStatus, originCode,
|
|
272
|
+
* transport]`. Every index is in key order, so its counters stay blind
|
|
273
|
+
* increments.
|
|
263
274
|
*/
|
|
264
275
|
const insightsFailures = (retention) => defineAggregate({
|
|
265
276
|
platform: {
|
|
@@ -459,7 +470,7 @@ const createInsightsSchema = ({ rawDays, dailyDays } = DEFAULT_INSIGHTS_RETENTIO
|
|
|
459
470
|
insights_overview_daily: counters(daily),
|
|
460
471
|
insights_sketches_daily: sketches(daily),
|
|
461
472
|
/** A release's counters since its first event, and its failed installations: kept. */
|
|
462
|
-
insights_overview_lifetime:
|
|
473
|
+
insights_overview_lifetime: lifetimeCounters(),
|
|
463
474
|
insights_sketches_lifetime: lifetimeSketches(),
|
|
464
475
|
insights_distribution: insightsDistribution(daily),
|
|
465
476
|
insights_latest_by_bundle: insightsLatestByBundle(daily),
|