feat(serviceworker): Enhance event and request logging with pagination support

This commit is contained in:
2025-12-04 20:07:40 +00:00
parent 065987c854
commit 3baf171394
10 changed files with 394 additions and 357 deletions

View File

@@ -120,6 +120,7 @@ export class ServiceworkerBackend {
limit: reqArg.limit,
type: reqArg.type,
since: reqArg.since,
before: reqArg.before,
});
});
@@ -164,6 +165,7 @@ export class ServiceworkerBackend {
limit: reqArg.limit,
method: reqArg.method,
since: reqArg.since,
before: reqArg.before,
});
const totalCount = requestLogStore.getTotalCount({
method: reqArg.method,

View File

@@ -210,65 +210,27 @@ export class CacheManager {
fetchEventArg.respondWith(Promise.resolve(dashboard.serveDashboard()));
return;
}
// /sw-dash/metrics - THE initial seed endpoint (provides ALL data)
if (parsedUrl.pathname === '/sw-dash/metrics') {
const dashboard = getDashboardGenerator();
fetchEventArg.respondWith(Promise.resolve(dashboard.serveMetrics()));
fetchEventArg.respondWith(dashboard.serveMetrics());
return;
}
// /sw-dash/speedtest - user-triggered speedtest
if (parsedUrl.pathname === '/sw-dash/speedtest') {
const dashboard = getDashboardGenerator();
fetchEventArg.respondWith(dashboard.runSpeedtest());
return;
}
// /sw-dash/resources - resource data (kept for now, could be merged into metrics)
if (parsedUrl.pathname === '/sw-dash/resources') {
const dashboard = getDashboardGenerator();
fetchEventArg.respondWith(Promise.resolve(dashboard.serveResources()));
return;
}
if (parsedUrl.pathname === '/sw-dash/events') {
const dashboard = getDashboardGenerator();
fetchEventArg.respondWith(dashboard.serveEventLog(parsedUrl.searchParams));
return;
}
if (parsedUrl.pathname === '/sw-dash/events/count') {
const dashboard = getDashboardGenerator();
fetchEventArg.respondWith(dashboard.serveEventCount(parsedUrl.searchParams));
return;
}
if (parsedUrl.pathname === '/sw-dash/cumulative-metrics') {
const dashboard = getDashboardGenerator();
fetchEventArg.respondWith(dashboard.serveCumulativeMetrics());
return;
}
// DELETE method for clearing events
if (parsedUrl.pathname === '/sw-dash/events' && originalRequest.method === 'DELETE') {
const dashboard = getDashboardGenerator();
fetchEventArg.respondWith(dashboard.clearEventLog());
return;
}
// TypedRequest traffic monitoring endpoints
if (parsedUrl.pathname === '/sw-dash/requests' && originalRequest.method === 'GET') {
const dashboard = getDashboardGenerator();
fetchEventArg.respondWith(Promise.resolve(dashboard.serveTypedRequestLogs(parsedUrl.searchParams)));
return;
}
if (parsedUrl.pathname === '/sw-dash/requests/stats') {
const dashboard = getDashboardGenerator();
fetchEventArg.respondWith(Promise.resolve(dashboard.serveTypedRequestStats()));
return;
}
if (parsedUrl.pathname === '/sw-dash/requests/methods') {
const dashboard = getDashboardGenerator();
fetchEventArg.respondWith(Promise.resolve(dashboard.serveTypedRequestMethods()));
return;
}
// DELETE method for clearing TypedRequest logs
if (parsedUrl.pathname === '/sw-dash/requests' && originalRequest.method === 'DELETE') {
const dashboard = getDashboardGenerator();
fetchEventArg.respondWith(Promise.resolve(dashboard.clearTypedRequestLogs()));
return;
}
// All other /sw-dash/* routes removed - use DeesComms instead:
// - Events: via serviceworker_getEventLog, serviceworker_clearEventLog
// - Requests: via serviceworker_getTypedRequestLogs, serviceworker_clearTypedRequestLogs
// Block requests that we don't want the service worker to handle.
if (

View File

@@ -25,10 +25,52 @@ export class DashboardGenerator {
}
/**
* Serves the metrics JSON endpoint
* Serves the metrics JSON endpoint with ALL initial data
* This is the single HTTP seed request that provides:
* - Current metrics
* - Initial events (last 50)
* - Initial request logs (last 50)
* - Request stats and methods
* - Resource data
*/
public serveMetrics(): Response {
return new Response(this.generateMetricsJson(), {
public async serveMetrics(): Promise<Response> {
const metrics = getMetricsCollector();
const persistentStore = getPersistentStore();
await persistentStore.init();
const requestLogStore = getRequestLogStore();
// Get event data
const eventResult = await persistentStore.getEventLog({ limit: 50 });
const oneHourAgo = Date.now() - 3600000;
const eventCountLastHour = await persistentStore.getEventCount(oneHourAgo);
// Build comprehensive initial response
const data = {
// Core metrics
...metrics.getMetrics(),
cacheHitRate: metrics.getCacheHitRate(),
networkSuccessRate: metrics.getNetworkSuccessRate(),
resourceCount: metrics.getResourceCount(),
summary: metrics.getSummary(),
// Resources data
resources: metrics.getCachedResources(),
domains: metrics.getDomainStats(),
contentTypes: metrics.getContentTypeStats(),
// Events data (initial 50)
events: eventResult.events,
eventTotalCount: eventResult.totalCount,
eventCountLastHour,
// Request logs data (initial 50)
requestLogs: requestLogStore.getEntries({ limit: 50 }),
requestTotalCount: requestLogStore.getTotalCount(),
requestStats: requestLogStore.getStats(),
requestMethods: requestLogStore.getMethods(),
};
return new Response(JSON.stringify(data), {
headers: {
'Content-Type': 'application/json',
'Cache-Control': 'no-store',

View File

@@ -316,6 +316,7 @@ export class PersistentStore {
limit?: number;
type?: TEventType;
since?: number;
before?: number;
}): Promise<{ events: IEventLogEntry[]; totalCount: number }> {
try {
let events: IEventLogEntry[] = [];
@@ -336,6 +337,11 @@ export class PersistentStore {
events = events.filter(e => e.timestamp >= options.since);
}
// Filter by before timestamp (for pagination)
if (options?.before) {
events = events.filter(e => e.timestamp < options.before);
}
// Sort by timestamp (newest first)
events.sort((a, b) => b.timestamp - a.timestamp);

View File

@@ -103,6 +103,7 @@ export class RequestLogStore {
limit?: number;
method?: string;
since?: number;
before?: number;
}): interfaces.serviceworker.ITypedRequestLogEntry[] {
let result = [...this.logs];
@@ -111,11 +112,16 @@ export class RequestLogStore {
result = result.filter((e) => e.method === options.method);
}
// Filter by timestamp
// Filter by timestamp (since)
if (options?.since) {
result = result.filter((e) => e.timestamp >= options.since);
}
// Filter by timestamp (before - for pagination)
if (options?.before) {
result = result.filter((e) => e.timestamp < options.before);
}
// Sort by timestamp descending (newest first)
result.sort((a, b) => b.timestamp - a.timestamp);