added a garbage filter

pull/17/head
DmitriyA 2025-05-26 08:53:22 -04:00
parent 1a63f20bb0
commit 319e2cdd69
2 changed files with 99 additions and 52 deletions

View File

@ -0,0 +1,5 @@
export interface MetricMetadata {
metric: string;
type: string;
help: string;
}

View File

@ -1,15 +1,12 @@
import { Injectable, Inject } from '@nestjs/common';
import { Injectable } from '@nestjs/common';
import { PrometheusService } from '../prometheus.service';
import { MenuItem } from './menu.interface';
@Injectable()
export class MenuService {
constructor(
private readonly prometheusService: PrometheusService // Просто объявляем зависимость
) {}
constructor(private readonly prometheusService: PrometheusService) {}
async getFullMenu(): Promise<MenuItem> {
// Реализация остается прежней
const dynamicItems = await this.generateDynamicItems();
return this.injectDynamicItems(this.getStaticStructure(), dynamicItems);
}
@ -37,7 +34,9 @@ export class MenuService {
private async generateDynamicItems(): Promise<MenuItem[]> {
const metricNames = await this.prometheusService.fetchAllMetrics();
const allSeries = await Promise.all(
// Получаем все серии для каждой метрики
const allSeries = (
await Promise.all(
metricNames.map(async name => {
const series = await this.prometheusService.fetchMetricSeries(name);
return series.map(s => ({
@ -45,20 +44,53 @@ export class MenuService {
labels: s
}));
})
)
).flat();
// Загружаем мета-информацию по каждой метрике
const metadataMap = new Map<string, string>(); // metric -> help
await Promise.all(
metricNames.map(async metric => {
try {
const meta = await this.prometheusService.fetchMetricMetadata(metric);
if (meta?.help) {
metadataMap.set(metric, meta.help);
}
} catch (e) {
console.warn(`No metadata for metric ${metric}`);
}
})
);
const flatSeries = allSeries.flat();
const isGarbageDevice = (device: string) =>
device.startsWith('/dev') ||
device.startsWith('/proc') ||
device.startsWith('/sys') ||
device.startsWith('/rootfs') ||
device.startsWith('/var') ||
device.startsWith('overlay') ||
device.startsWith('br') ||
device.startsWith('docker0') ||
device.startsWith('ens18') ||
device.startsWith('sda') ||
device.startsWith('sr0') ||
device.startsWith('tmpfs') ||
device.startsWith('veth') ||
device.startsWith('gvfsd') ||
device.startsWith('lo') ||
device.startsWith('/run');
const devices = this.extractUniqueEntities(flatSeries, 'device');
const devices = this.extractUniqueEntities(allSeries, 'device')
.filter(device => !isGarbageDevice(device));
return devices.map(device => ({
id: `device_${device}`,
title: `Graviton S2082I (${device})`,
items: this.generateModuleItems(device, flatSeries),
items: this.generateModuleItems(device, allSeries, metadataMap),
isDynamic: true
}));
}
}
private extractUniqueEntities(metrics: any[], field: string): string[] {
const entities = new Set<string>();
@ -70,7 +102,11 @@ export class MenuService {
return Array.from(entities);
}
private generateModuleItems(device: string, seriesData: { metric: string, labels: Record<string, string> }[]): MenuItem[] {
private generateModuleItems(
device: string,
seriesData: { metric: string; labels: Record<string, string> }[],
metadataMap: Map<string, string>
): MenuItem[] {
const modules = new Set<string>();
seriesData.forEach(({ labels }) => {
@ -80,34 +116,41 @@ export class MenuService {
});
return Array.from(modules).map(module => ({
id: `module_${module.replace('module$', '')}`,
title: `OS Linux АО (${module})`,
items: this.generateMetricItems(device, module, seriesData),
id: `module_${device}_${module}`,
title: `Module ${module.replace('module$', '')}`,
items: this.generateMetricItems(device, module, seriesData, metadataMap),
isDynamic: true
}));
}
private generateMetricItems(device: string, module: string, seriesData: { metric: string, labels: Record<string, string> }[]): MenuItem[] {
private generateMetricItems(
device: string,
module: string,
seriesData: { metric: string; labels: Record<string, string> }[],
metadataMap: Map<string, string>
): MenuItem[] {
const filtered = seriesData.filter(
({ labels }) => labels.device === device && labels.source_id === module
);
const uniqueMetrics = new Set(filtered.map(entry => entry.metric));
return Array.from(uniqueMetrics).map(metric => ({
return Array.from(uniqueMetrics).map(metric => {
const description = metadataMap.get(metric) || metric;
return {
id: `metric_${device}_${module}_${metric}`,
title: metric, // или запрашивать описание отдельно
title: description,
metric,
filters: {
device,
source_id: module
},
isDynamic: true
}));
};
});
}
private injectDynamicItems(menu: MenuItem, dynamicItems: MenuItem[]): MenuItem {
if (menu.id === 'media_servers') {
return { ...menu, items: dynamicItems };
@ -119,7 +162,6 @@ export class MenuService {
};
}
async updateMenuItem(id: string, update: Partial<MenuItem>): Promise<MenuItem> {
const fullMenu = await this.getFullMenu();
const item = this.findMenuItem(fullMenu, id);