feat: add logging functionality with LoggerService; implement log entity and controller; enhance query processing with logging support

This commit is contained in:
lborv
2025-10-11 16:21:03 +03:00
parent 323fc6e817
commit 57e4a8b932
19 changed files with 328 additions and 24 deletions

View File

@ -0,0 +1,17 @@
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";
import { TLog } from "../logger.types";
@Entity()
export class Log {
@PrimaryGeneratedColumn("uuid")
id: string;
@Column({ type: "varchar", length: 255 })
traceId: string;
@Column({ type: "longtext" })
content: TLog;
@Column({ type: "timestamp", default: () => "CURRENT_TIMESTAMP" })
createdAt: Date;
}

View File

@ -0,0 +1,32 @@
import { Body, Controller, Get, Inject, Post, UseGuards } from "@nestjs/common";
import { LoggerService } from "./logger.service";
import { ApiTokenGuard } from "src/api/guards/api-token.guard";
@Controller("logger")
@UseGuards(ApiTokenGuard)
export class LoggerController {
constructor(
@Inject(LoggerService)
private readonly loggerService: LoggerService
) {}
@Get("/:traceId")
getByTraceId(@Inject("traceId") traceId: string) {
return this.loggerService.findByTraceId(traceId);
}
@Post("/find")
find(
@Body()
body: {
traceId?: string;
fromDate?: Date;
toDate?: Date;
url?: string;
limit: number;
offset: number;
}
) {
return this.loggerService.find(body);
}
}

View File

@ -0,0 +1,66 @@
import { Injectable } from "@nestjs/common";
import { Log } from "./entities/log.entity";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { TLog, TLogLine } from "./logger.types";
@Injectable()
export class LoggerService {
constructor(
@InjectRepository(Log)
private readonly logRepository: Repository<Log>
) {}
async create(traceId: string, content: TLog): Promise<Log> {
const log = this.logRepository.create({ traceId, content });
return await this.logRepository.save(log);
}
async findByTraceId(traceId: string): Promise<Log[]> {
return await this.logRepository.find({ where: { traceId } });
}
async find(data: {
traceId?: string;
fromDate?: Date;
toDate?: Date;
url?: string;
limit: number;
offset: number;
}): Promise<Log[]> {
const query = this.logRepository.createQueryBuilder("log");
if (data.traceId) {
query.andWhere("log.traceId = :traceId", { traceId: data.traceId });
}
if (data.fromDate) {
query.andWhere("log.createdAt >= :fromDate", { fromDate: data.fromDate });
}
if (data.toDate) {
query.andWhere("log.createdAt <= :toDate", { toDate: data.toDate });
}
if (data.url) {
query.andWhere("log.content LIKE :url", { url: `%${data.url}%` });
}
query.skip(data.offset).take(data.limit).orderBy("log.createdAt", "DESC");
return await query.getMany();
}
static log(logStack: TLog, log: TLog | TLogLine): TLog {
logStack.content.push(log);
return logStack;
}
static generateTraceId(): string {
return (
Date.now().toString(36) +
Math.random().toString(36).substring(2, 15) +
Math.random().toString(36).substring(2, 15)
);
}
}

View File

@ -0,0 +1,26 @@
import { QueryResponse } from "src/vm/vm.constants";
export enum TLogType {
info = "info",
error = "error",
debug = "debug",
warn = "warn",
}
export type TLogLine = {
content: string;
type: TLogType;
timeStamp: number;
};
export interface TLog {
traceId: string;
content: (TLogLine | TLog)[];
payload?: any;
headers: Record<string, string | string[] | undefined>;
cookies: Record<string, string>;
url: string;
response: QueryResponse | null;
startTime: number;
endTime?: number;
}