feat(opsserver): add real-time log push to ops dashboard and recent DNS query tracking

This commit is contained in:
2026-02-21 14:02:48 +00:00
parent 1337a4905a
commit ffc93eb9d3
16 changed files with 203 additions and 22 deletions

View File

@@ -29,6 +29,8 @@ export class OpsViewLogs extends DeesElement {
@state()
accessor filterLimit: number = 100;
private lastPushedCount = 0;
constructor() {
super();
const subscription = appstate.logStatePart
@@ -110,7 +112,11 @@ export class OpsViewLogs extends DeesElement {
async connectedCallback() {
super.connectedCallback();
this.fetchLogs();
this.lastPushedCount = 0;
// Only fetch if state is empty (streaming will handle new entries)
if (this.logState.recentLogs.length === 0) {
this.fetchLogs();
}
}
async updated(changedProperties: Map<string, any>) {
@@ -127,10 +133,16 @@ export class OpsViewLogs extends DeesElement {
// Ensure the chart element has finished its own initialization
await chartLog.updateComplete;
chartLog.clearLogs();
const entries = this.getMappedLogEntries();
if (entries.length > 0) {
chartLog.updateLog(entries);
const allEntries = this.getMappedLogEntries();
if (this.lastPushedCount === 0 && allEntries.length > 0) {
// Initial load: push all entries
chartLog.updateLog(allEntries);
this.lastPushedCount = allEntries.length;
} else if (allEntries.length > this.lastPushedCount) {
// Incremental: only push new entries
const newEntries = allEntries.slice(this.lastPushedCount);
chartLog.updateLog(newEntries);
this.lastPushedCount = allEntries.length;
}
}

View File

@@ -133,8 +133,8 @@ export class OpsViewOverview extends DeesElement {
.logEntries=${this.getRecentEventEntries()}
></dees-chart-log>
<dees-chart-log
.label=${'Security Alerts'}
.logEntries=${this.getSecurityAlertEntries()}
.label=${'DNS Queries'}
.logEntries=${this.getDnsQueryEntries()}
></dees-chart-log>
</div>
`}
@@ -395,6 +395,16 @@ export class OpsViewOverview extends DeesElement {
}));
}
private getDnsQueryEntries(): Array<{ timestamp: string; level: 'debug' | 'info' | 'warn' | 'error' | 'success'; message: string; source?: string }> {
const queries: any[] = (this.statsState.dnsStats as any)?.recentQueries || [];
return queries.map((q: any) => ({
timestamp: new Date(q.timestamp).toISOString(),
level: q.answered ? 'info' as const : 'warn' as const,
message: `${q.type} ${q.domain} (${q.responseTimeMs}ms)`,
source: 'dns',
}));
}
private getEmailTrafficSeries(): Array<{ name: string; color: string; data: Array<{ x: number; y: number }> }> {
const ts = this.statsState.emailStats?.timeSeries;
if (!ts) return [];