feat(opsserver): add real-time log push to ops dashboard and recent DNS query tracking
This commit is contained in:
@@ -1,15 +1,16 @@
|
||||
import * as plugins from '../../plugins.js';
|
||||
import type { OpsServer } from '../classes.opsserver.js';
|
||||
import * as interfaces from '../../../ts_interfaces/index.js';
|
||||
import { logBuffer } from '../../logger.js';
|
||||
import { logBuffer, baseLogger } from '../../logger.js';
|
||||
|
||||
export class LogsHandler {
|
||||
public typedrouter = new plugins.typedrequest.TypedRouter();
|
||||
|
||||
|
||||
constructor(private opsServerRef: OpsServer) {
|
||||
// Add this handler's router to the parent
|
||||
this.opsServerRef.typedrouter.addTypedRouter(this.typedrouter);
|
||||
this.registerHandlers();
|
||||
this.setupLogPushDestination();
|
||||
}
|
||||
|
||||
private registerHandlers(): void {
|
||||
@@ -165,6 +166,50 @@ export class LogsHandler {
|
||||
return mapped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a log destination to the base logger that pushes entries
|
||||
* to all connected ops_dashboard TypedSocket clients.
|
||||
*/
|
||||
private setupLogPushDestination(): void {
|
||||
const opsServerRef = this.opsServerRef;
|
||||
|
||||
baseLogger.addLogDestination({
|
||||
async handleLog(logPackage: any) {
|
||||
// Access the TypedSocket server instance from OpsServer
|
||||
const typedsocket = opsServerRef.server?.typedserver?.typedsocket;
|
||||
if (!typedsocket) return;
|
||||
|
||||
let connections: any[];
|
||||
try {
|
||||
connections = await typedsocket.findAllTargetConnectionsByTag('role', 'ops_dashboard');
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
if (connections.length === 0) return;
|
||||
|
||||
const entry: interfaces.data.ILogEntry = {
|
||||
timestamp: logPackage.timestamp || Date.now(),
|
||||
level: LogsHandler.mapLogLevel(logPackage.level),
|
||||
category: LogsHandler.deriveCategory(logPackage.context?.zone, logPackage.message),
|
||||
message: logPackage.message,
|
||||
metadata: logPackage.data,
|
||||
};
|
||||
|
||||
for (const conn of connections) {
|
||||
try {
|
||||
const push = typedsocket.createTypedRequest<interfaces.requests.IReq_PushLogEntry>(
|
||||
'pushLogEntry',
|
||||
conn,
|
||||
);
|
||||
push.fire({ entry }).catch(() => {}); // fire-and-forget
|
||||
} catch {
|
||||
// connection may have closed
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private setupLogStream(
|
||||
virtualStream: plugins.typedrequest.VirtualStream<Uint8Array>,
|
||||
levelFilter?: string[],
|
||||
|
||||
@@ -241,6 +241,7 @@ export class StatsHandler {
|
||||
averageResponseTime: 0,
|
||||
queryTypes: stats.queryTypes,
|
||||
timeSeries,
|
||||
recentQueries: stats.recentQueries,
|
||||
};
|
||||
})
|
||||
);
|
||||
@@ -422,6 +423,7 @@ export class StatsHandler {
|
||||
count: number;
|
||||
}>;
|
||||
queryTypes: { [key: string]: number };
|
||||
recentQueries?: Array<{ timestamp: number; domain: string; type: string; answered: boolean; responseTimeMs: number }>;
|
||||
domainBreakdown?: { [domain: string]: interfaces.data.IDnsStats };
|
||||
}> {
|
||||
// Get metrics from MetricsManager if available
|
||||
@@ -435,9 +437,10 @@ export class StatsHandler {
|
||||
cacheHitRate: dnsStats.cacheHitRate,
|
||||
topDomains: dnsStats.topDomains,
|
||||
queryTypes: dnsStats.queryTypes,
|
||||
recentQueries: dnsStats.recentQueries,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// Fallback if MetricsManager not available
|
||||
return {
|
||||
queriesPerSecond: 0,
|
||||
|
||||
Reference in New Issue
Block a user