Compare commits

...

2 Commits

Author SHA1 Message Date
DmitriyA 926ea01235 added clickhouse service 2025-07-24 08:26:19 -04:00
Vladislav Drozdov 8466aa1f93 Merge pull request 'adding filter for metrics' (#30) from swagger into rc
test-org/trust-module-backend/pipeline/pr-main Build succeeded
Reviewed-on: http://git.enode/deployer3000/trust-module-backend/pulls/30
Reviewed-by: Vladislav Drozdov <ya2@ya.ru>
2025-07-21 13:15:54 +03:00
16 changed files with 179 additions and 33 deletions

9
.env
View File

@ -27,3 +27,12 @@
# Для меню # Для меню
#RANGES_API_URL=http://192.168.2.39:9999 #RANGES_API_URL=http://192.168.2.39:9999
#RANGES_API_ENDPOINT=/api/ranges/9999 #RANGES_API_ENDPOINT=/api/ranges/9999
# ClickHouse
#CLICKHOUSE_HOST=http://192.168.2.37:8123
#CLICKHOUSE_USER=vlad
#CLICKHOUSE_PASSWORD=vlad
#CLICKHOUSE_DB=zvks
# Для ai api
#ANALYSIS_API_URL=http://192.168.2.39:5134/models/api/metrics/rest

View File

@ -44,7 +44,10 @@
"@types/cookie-parser": "^1.4.8", "@types/cookie-parser": "^1.4.8",
"@nestjs/jwt": "^11.0.0", "@nestjs/jwt": "^11.0.0",
"@nestjs/passport": "^11.0.5", "@nestjs/passport": "^11.0.5",
"@nestjs/swagger": "11.1.4" "@nestjs/swagger": "11.1.4",
"@clickhouse/client": "^1.11.2",
"date-fns": "4.1.0",
"@clickhouse/client-web": "^1.11.2"
}, },
"devDependencies": { "devDependencies": {
"@eslint/eslintrc": "^3.2.0", "@eslint/eslintrc": "^3.2.0",

0
src/ai/ai.service.ts Normal file
View File

View File

@ -4,7 +4,9 @@ import { HttpModule } from '@nestjs/axios';
import { ConfigModule } from '@nestjs/config'; import { ConfigModule } from '@nestjs/config';
import { AuthModule } from './auth/auth.module'; import { AuthModule } from './auth/auth.module';
import { MenuModule } from './menu/menu.module'; import { MenuModule } from './menu/menu.module';
import { PrometheusModule } from './prometheus.module'; import { PrometheusModule } from './prometheus/prometheus.module';
import { ClickHouseModule } from './clickhouse/clickhouse.module';
import { ClickHouseController } from './clickhouse/clickhouse.controller';
@Module({ @Module({
imports: [ imports: [
@ -27,6 +29,8 @@ import { PrometheusModule } from './prometheus.module';
AuthModule, AuthModule,
PrometheusModule, PrometheusModule,
MenuModule, MenuModule,
ClickHouseModule,
], ],
controllers: [ClickHouseController],
}) })
export class AppModule { } export class AppModule { }

View File

@ -0,0 +1,35 @@
import { Controller, Get } from '@nestjs/common';
import { ClickHouseService } from './clickhouse.service';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
@ApiTags('Clickhouse')
@Controller('clickhouse')
export class ClickHouseController {
constructor(private readonly clickhouseService: ClickHouseService) { }
@Get()
@ApiOperation({ summary: 'Get metrics from ClickHouse' })
@ApiResponse({
status: 200,
description: 'Metrics data',
schema: {
type: 'array',
items: {
type: 'object',
properties: {
description: { type: 'string' },
device: { type: 'number' },
id: { type: 'string' },
name: { type: 'string' },
source: { type: 'string' },
status: { type: 'number' },
timestamp: { type: 'number' },
value: { type: 'string' },
},
},
},
})
async getClckhouse() {
return this.clickhouseService.getClckhouse();
}
}

View File

@ -0,0 +1,23 @@
import { Module, Global } from '@nestjs/common';
import { createClient, ClickHouseClient } from '@clickhouse/client';
import { ClickHouseService } from './clickhouse.service';
@Global()
@Module({
providers: [
{
provide: 'CLICKHOUSE_CLIENT',
useFactory: (): ClickHouseClient => {
return createClient({
host: process.env.CLICKHOUSE_HOST || 'http://localhost:8123',
username: process.env.CLICKHOUSE_USER || 'default',
password: process.env.CLICKHOUSE_PASSWORD || '',
database: process.env.CLICKHOUSE_DB || 'default',
});
},
},
ClickHouseService,
],
exports: ['CLICKHOUSE_CLIENT', ClickHouseService],
})
export class ClickHouseModule { }

View File

@ -0,0 +1,72 @@
import { Injectable, Inject } from '@nestjs/common';
import { ClickHouseClient } from '@clickhouse/client';
interface ClickHouseRow {
EventDataTime: string;
ParameterBody: string;
CreateDataTime: string;
}
interface MetricData {
id: string;
name: string;
type: string;
addr?: string;
value: number | string | null;
description: string;
status: number;
device: number;
source: string;
}
interface ParameterBody {
service_name: string;
metrics: MetricData[];
}
@Injectable()
export class ClickHouseService {
constructor(
@Inject('CLICKHOUSE_CLIENT')
private readonly clickhouseClient: ClickHouseClient,
) { }
async getClckhouse() {
const query = `
SELECT
EventDataTime,
ParameterBody,
CreateDataTime
FROM zvks.complex_parameters
ORDER BY EventDataTime DESC
LIMIT 100
`;
const result = await this.clickhouseClient.query({
query,
format: 'JSONEachRow',
});
const rows = await result.json<ClickHouseRow>();
// Парсинг данных
return rows.flatMap((row: ClickHouseRow) => {
try {
const parameterBody: ParameterBody = JSON.parse(row.ParameterBody);
return parameterBody.metrics.map((metric: MetricData) => ({
id: metric.id,
name: metric.name,
value: metric.value !== null ? metric.value.toString() : 'null',
description: metric.description,
status: metric.status,
device: metric.device,
source: metric.source,
timestamp: new Date(row.EventDataTime).getTime(),
}));
} catch (e) {
console.error('Error parsing metric:', e);
return [];
}
});
}
}

View File

@ -2,7 +2,7 @@ import { Module } from '@nestjs/common';
import { MenuController } from './menu.controller'; import { MenuController } from './menu.controller';
import { HttpModule } from '@nestjs/axios'; import { HttpModule } from '@nestjs/axios';
import { MenuService } from './menu.service'; import { MenuService } from './menu.service';
import { PrometheusModule } from '../prometheus.module'; import { PrometheusModule } from '../prometheus/prometheus.module';
import { RangeService } from './range.service'; import { RangeService } from './range.service';
import { RangeController } from './range.controller'; import { RangeController } from './range.controller';

View File

@ -1,5 +1,5 @@
import { Injectable, HttpException, HttpStatus } from '@nestjs/common'; import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { PrometheusService } from '../prometheus.service'; import { PrometheusService } from '../prometheus/prometheus.service';
import { MenuItem } from './menu.interface'; import { MenuItem } from './menu.interface';
import * as fs from 'fs/promises'; import * as fs from 'fs/promises';
import * as path from 'path'; import * as path from 'path';

View File

View File

@ -3,7 +3,7 @@ import { HttpService } from '@nestjs/axios';
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config';
import { lastValueFrom } from 'rxjs'; import { lastValueFrom } from 'rxjs';
import { PrometheusMetric } from './prometheus-metric.interface'; import { PrometheusMetric } from './prometheus-metric.interface';
import { MenuItem } from './menu/menu.interface'; import { MenuItem } from '../menu/menu.interface';
@Injectable() @Injectable()
export class PrometheusService { export class PrometheusService {