feat: add metrics, observability, test fixtures, and scaling playbook artifacts
This commit is contained in:
1 parent
926a663c23
commit
f9aba11b90
32 files changed
+1788
-124
No files matched your search
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const apiToken = process.env.CLOUDFLARE_API_TOKEN;
|
||||
const zoneTag = process.env.CLOUDFLARE_ZONE_TAG;
|
||||
const hostname = process.env.CLOUDFLARE_HOSTNAME || "linearvoid.tv";
|
||||
const windowMinutes = Number.parseInt(process.env.CLOUDFLARE_CACHE_HIT_RATIO_WINDOW_MINUTES || "60", 10);
|
||||
const endpoint = process.env.CLOUDFLARE_GRAPHQL_ENDPOINT || "https://api.cloudflare.com/client/v4/graphql";
|
||||
|
||||
if (!apiToken || !zoneTag) {
|
||||
console.error("Missing required environment variables: CLOUDFLARE_API_TOKEN, CLOUDFLARE_ZONE_TAG");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const end = new Date();
|
||||
const start = new Date(end.getTime() - windowMinutes * 60 * 1000);
|
||||
|
||||
const iso = (value) => value.toISOString();
|
||||
|
||||
const query = `
|
||||
query CacheHitRatio($zoneTag: string, $start: Time, $end: Time, $hostname: String) {
|
||||
viewer {
|
||||
zones(filter: { zoneTag: $zoneTag }) {
|
||||
requests: httpRequestsAdaptiveGroups(
|
||||
limit: 1000
|
||||
filter: {
|
||||
datetime_geq: $start
|
||||
datetime_lt: $end
|
||||
clientRequestHTTPHost: $hostname
|
||||
requestSource: "eyeball"
|
||||
}
|
||||
) {
|
||||
count
|
||||
dimensions {
|
||||
cacheStatus
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
async function main() {
|
||||
const response = await fetch(endpoint, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: `Bearer ${apiToken}`,
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
query,
|
||||
variables: {
|
||||
zoneTag,
|
||||
hostname,
|
||||
start: iso(start),
|
||||
end: iso(end),
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const payload = await response.json();
|
||||
if (!response.ok || payload.errors) {
|
||||
const message = payload.errors ? JSON.stringify(payload.errors) : `HTTP ${response.status}`;
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
const groups = payload?.data?.viewer?.zones?.[0]?.requests || [];
|
||||
let totalRequests = 0;
|
||||
let hitRequests = 0;
|
||||
|
||||
for (const group of groups) {
|
||||
const count = Number(group?.count || 0);
|
||||
const status = String(group?.dimensions?.cacheStatus || "").toUpperCase();
|
||||
totalRequests += count;
|
||||
if (status === "HIT") {
|
||||
hitRequests += count;
|
||||
}
|
||||
}
|
||||
|
||||
const ratio = totalRequests > 0 ? hitRequests / totalRequests : 0;
|
||||
|
||||
console.log(
|
||||
`# HELP linearvoid_cache_hit_ratio Cloudflare cache hit ratio for the selected hostname and time window.`,
|
||||
);
|
||||
console.log(`# TYPE linearvoid_cache_hit_ratio gauge`);
|
||||
console.log(
|
||||
`linearvoid_cache_hit_ratio{zone="${zoneTag}",hostname="${hostname}",window_minutes="${windowMinutes}"} ${ratio.toFixed(6)}`,
|
||||
);
|
||||
console.log(`# HELP linearvoid_cache_hit_requests_total Cloudflare cache HIT requests counted in the time window.`);
|
||||
console.log(`# TYPE linearvoid_cache_hit_requests_total counter`);
|
||||
console.log(
|
||||
`linearvoid_cache_hit_requests_total{zone="${zoneTag}",hostname="${hostname}",window_minutes="${windowMinutes}"} ${hitRequests}`,
|
||||
);
|
||||
console.log(
|
||||
`# HELP linearvoid_cache_total_requests_total Cloudflare total eyeball requests counted in the time window.`,
|
||||
);
|
||||
console.log(`# TYPE linearvoid_cache_total_requests_total counter`);
|
||||
console.log(
|
||||
`linearvoid_cache_total_requests_total{zone="${zoneTag}",hostname="${hostname}",window_minutes="${windowMinutes}"} ${totalRequests}`,
|
||||
);
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error(error instanceof Error ? error.message : String(error));
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in new issue
Block a user