Skip to content

Commit 0d9258e

Browse files
committed
Fix Analytics Engine telemetry fields
Keep WebUI Analytics Engine double fields within Cloudflare's 20-column limit and add a Pages check guard. Record APK filename and package name in bot worker usage analytics.
1 parent 82edc92 commit 0d9258e

5 files changed

Lines changed: 61 additions & 7 deletions

File tree

AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
- Keep runtime log export/share/download code lazy-loaded; it is not first-screen behavior and can tip the tight initial JS gzip budget.
103103
- For slow Web UI link analysis, inspect runtime log split timings (`client_duration_ms`, `server_duration_ms`, `fetch_headers_ms`, `response_text_ms`, `json_parse_ms`, `render_ms`) before blaming rendering, history writes, or remote parsing. Large reports can justify moving noncritical work off the visible-result path, but they are not evidence of multi-second stalls by themselves.
104104
- Static Web UI text should stay non-selectable for drag/long-press copy. Only application/report data values should opt into selection, using the existing `app-data-text` whitelist class or an equivalent narrowly scoped report-data selector.
105+
- Cloudflare Analytics Engine exposes only `blob1`-`blob20` and `double1`-`double20`. Keep Web UI `functions/analytics.js` blob/double key arrays at 20 entries or fewer, and let `npm run pages:check` catch budget overflows before deploy.
105106

106107
## Worker Notes
107108

packages/apk-webui/functions/analytics.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@ const ANALYTICS_DOUBLE_KEYS = [
4646
"client_time_offset_ms",
4747
"downloaded_bytes",
4848
"range_request_count",
49-
"reserved_1",
50-
"reserved_2",
5149
];
5250

5351
const PRIVATE_EVENT_KEYS = new Set([

packages/apk-webui/scripts/check.mjs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { spawn } from "node:child_process";
2-
import { readdir } from "node:fs/promises";
2+
import { readFile, readdir } from "node:fs/promises";
33
import { dirname, extname, relative, resolve } from "node:path";
44
import { fileURLToPath } from "node:url";
55

@@ -16,6 +16,7 @@ const extraSyntaxFiles = [
1616
];
1717

1818
await runNpm(["run", "i18n:check", "--workspace", "@tgbot/shared"], repoDir);
19+
await validateAnalyticsEngineKeyBudgets();
1920

2021
const syntaxFiles = (await collectSyntaxFiles(sourceRoots))
2122
.concat(extraSyntaxFiles)
@@ -78,6 +79,25 @@ function runNpm(args, cwd) {
7879
return run("cmd.exe", ["/d", "/s", "/c", ["npm", ...args].join(" ")], cwd);
7980
}
8081

82+
async function validateAnalyticsEngineKeyBudgets() {
83+
const analyticsPath = resolve(projectDir, "functions/analytics.js");
84+
const source = await readFile(analyticsPath, "utf8");
85+
for (const name of ["ANALYTICS_BLOB_KEYS", "ANALYTICS_DOUBLE_KEYS"]) {
86+
const values = readStringArray(source, name);
87+
if (values.length > 20) {
88+
throw new Error(`${name} has ${values.length} entries; Analytics Engine supports at most 20`);
89+
}
90+
}
91+
}
92+
93+
function readStringArray(source, name) {
94+
const match = source.match(new RegExp(`const ${name} = \\[([\\s\\S]*?)\\];`));
95+
if (!match) {
96+
throw new Error(`Missing ${name}`);
97+
}
98+
return [...match[1].matchAll(/"([^"]+)"/gu)].map((item) => item[1]);
99+
}
100+
81101
function formatCommand(command, args) {
82102
return [command, ...args].join(" ");
83103
}

packages/bot-worker/src/observability.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ const ANALYTICS_BLOB_KEYS = [
2121
"worker_version_tag",
2222
"error_name",
2323
"ui_mode",
24-
"operation",
25-
"input_source",
24+
"file_name",
25+
"package_name",
2626
];
2727

2828
const ANALYTICS_DOUBLE_KEYS = [
@@ -63,8 +63,6 @@ const ANALYTICS_PRIVATE_TELEMETRY_KEYS = new Set([
6363
...CONSOLE_PRIVATE_TELEMETRY_KEYS,
6464
"app_icon_path",
6565
"error_message",
66-
"file_name",
67-
"package_name",
6866
"report_path",
6967
"url_host",
7068
"url_path",
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import assert from "node:assert/strict";
2+
import test from "node:test";
3+
4+
import { logInfoEvent } from "../src/observability.js";
5+
6+
test("analytics datapoints include APK file and package identifiers", () => {
7+
const datapoints = [];
8+
const env = {
9+
USAGE_ANALYTICS: {
10+
writeDataPoint(point) {
11+
datapoints.push(point);
12+
},
13+
},
14+
};
15+
const originalLog = console.log;
16+
console.log = () => {};
17+
18+
try {
19+
logInfoEvent(
20+
env,
21+
{ request_id: "request-1", surface: "worker", route: "telegram_webhook" },
22+
"apk.analysis.succeeded",
23+
{
24+
result: "success",
25+
file_name: "sample.apk",
26+
package_name: "com.example.app",
27+
},
28+
);
29+
} finally {
30+
console.log = originalLog;
31+
}
32+
33+
assert.equal(datapoints.length, 1);
34+
assert.equal(datapoints[0].blobs.length, 20);
35+
assert.ok(datapoints[0].blobs.includes("sample.apk"));
36+
assert.ok(datapoints[0].blobs.includes("com.example.app"));
37+
});

0 commit comments

Comments
 (0)