feat(serviceworker): Enhance event and request logging with pagination support
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user