diff --git a/docker-compose.yml b/docker-compose.yml index bbcca62..9eef731 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,6 +9,7 @@ services: DATABASE_URL: ${DATABASE_URL} CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS} INGEST_API_KEY: ${INGEST_API_KEY} + INGEST_DEBUG_LOG: ${INGEST_DEBUG_LOG:-} CURRENT_EVENTS_POLL_MS: ${CURRENT_EVENTS_POLL_MS} expose: - "3101" diff --git a/src/ingest/ingest.controller.ts b/src/ingest/ingest.controller.ts index befcc55..72d1a58 100644 --- a/src/ingest/ingest.controller.ts +++ b/src/ingest/ingest.controller.ts @@ -1,4 +1,5 @@ -import { Body, Controller, Param, Post, UseGuards } from '@nestjs/common'; +import { Body, Controller, Logger, Param, Post, Req, UseGuards } from '@nestjs/common'; +import type { Request } from 'express'; import { IngestApiKeyGuard } from '../common/ingest-api-key.guard'; import { IngestEdgeValuesDto } from './dto/ingest-edge-values.dto'; import { IngestPointDto } from './dto/ingest-point.dto'; @@ -7,17 +8,37 @@ import { IngestService } from './ingest.service'; @Controller('ingest') @UseGuards(IngestApiKeyGuard) export class IngestController { + private readonly logger = new Logger(IngestController.name); + constructor(private readonly ingest: IngestService) {} - /** Принимает одну сырую точку и сохраняет ее как запись истории/current. */ @Post() - ingestPoint(@Body() point: IngestPointDto) { + ingestPoint(@Body() point: IngestPointDto, @Req() request: Request) { + this.logIngestRequest(request, { + kind: 'point', + edge: point.edge, + tag: point.tag, + timestamp: point.timestamp, + }); + return this.ingest.ingestPoint(point); } - /** Принимает компактное тело запроса по edge и сохраняет каждое значение построчно. */ @Post(':edge') - ingestEdgeValues(@Param('edge') edge: string, @Body() body: IngestEdgeValuesDto) { + ingestEdgeValues( + @Param('edge') edge: string, + @Body() body: IngestEdgeValuesDto, + @Req() request: Request, + ) { + const tags = Object.keys(body.values); + this.logIngestRequest(request, { + kind: 'edge-values', + edge, + tagCount: tags.length, + firstTags: tags.slice(0, 5), + timestamp: body.timestamp, + }); + const points = Object.entries(body.values).map(([tag, value]) => ({ edge, tag, @@ -27,4 +48,33 @@ export class IngestController { return this.ingest.ingestPoints(points); } + + private logIngestRequest( + request: Request, + payload: Record, + ): void { + if (!this.isDebugLogEnabled()) { + return; + } + + this.logger.log({ + event: 'ingest.received', + method: request.method, + url: request.originalUrl, + host: request.get('host'), + ip: request.ip, + remoteAddress: request.socket.remoteAddress, + forwardedFor: request.get('x-forwarded-for'), + realIp: request.get('x-real-ip'), + userAgent: request.get('user-agent'), + contentLength: request.get('content-length'), + ...payload, + }); + } + + private isDebugLogEnabled(): boolean { + return ['1', 'true', 'yes', 'on'].includes( + (process.env.INGEST_DEBUG_LOG ?? '').toLowerCase(), + ); + } }