-
Notifications
You must be signed in to change notification settings - Fork 559
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
[Feat] #8386 Global Logging For API Request (DB Structure)
- Loading branch information
Showing
20 changed files
with
696 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { IBasePerTenantAndOrganizationEntityModel, ID, JsonData } from './base-entity.model'; | ||
import { IRelationalUser } from './user.model'; | ||
|
||
/** | ||
* Enum representing the HTTP method used in the request. | ||
*/ | ||
export enum RequestMethod { | ||
GET = 0, | ||
POST = 1, | ||
PUT = 2, | ||
DELETE = 3, | ||
PATCH = 4, | ||
ALL = 5, | ||
OPTIONS = 6, | ||
HEAD = 7, | ||
SEARCH = 8 | ||
} | ||
|
||
/** | ||
* Interface representing an API call log entry. | ||
*/ | ||
export interface IApiCallLog extends IBasePerTenantAndOrganizationEntityModel, IRelationalUser { | ||
correlationId: ID; // Correlation ID to track the request across services. | ||
url: string; // The request URL that was called. | ||
method: RequestMethod; // The HTTP method (GET, POST, etc.) used in the request. | ||
statusCode: number; // The HTTP status code returned from the request. | ||
requestHeaders: JsonData; // Request headers stored as JSON string. | ||
requestBody: JsonData; // Request body stored as JSON string. | ||
responseBody: JsonData; // Response body stored as JSON string. | ||
requestTime: Date; // The timestamp when the request was initiated. | ||
responseTime: Date; // The timestamp when the response was completed. | ||
ipAddress: string; // The IP address of the client making the request. | ||
protocol: string; // The protocol used in the request (HTTP, HTTPS). | ||
userAgent: string; // User-Agent string of the client making the request (could be a browser, desktop app, Postman, etc.). | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { Controller, Get, Query, UseGuards } from '@nestjs/common'; | ||
import { ApiOperation, ApiResponse } from '@nestjs/swagger'; | ||
import { Permissions } from '../shared/decorators'; | ||
import { PermissionGuard, TenantPermissionGuard } from '../shared/guards'; | ||
import { IApiCallLog, IPagination } from '@gauzy/contracts'; | ||
import { ApiCallLogService } from './api-call-log.service'; | ||
import { ApiCallLogFilterDTO } from './dto/api-call-log-filter.dto'; | ||
|
||
@UseGuards(TenantPermissionGuard, PermissionGuard) | ||
@Permissions() | ||
@Controller('/api-call-log') | ||
export class ApiCallLogController { | ||
constructor(private readonly _apiCallLogService: ApiCallLogService) {} | ||
|
||
/** | ||
* Retrieves a paginated and filtered list of all API call logs from the system. | ||
* | ||
* @param filters DTO containing filtering options like `organizationId`, `correlationId`, `url`, etc. | ||
* @returns A promise that resolves to a paginated list of `IApiCallLog` objects. | ||
*/ | ||
@ApiOperation({ summary: 'Get all API call logs with mandatory organizationId and optional filters' }) | ||
@ApiResponse({ | ||
status: 200, | ||
description: 'Returns a list of all API call logs with filters applied.' | ||
}) | ||
@ApiResponse({ status: 500, description: 'Internal server error.' }) | ||
@Get('/') | ||
async findAll(@Query() filters: ApiCallLogFilterDTO): Promise<IPagination<IApiCallLog>> { | ||
return this._apiCallLogService.findAllLogs(filters); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; | ||
import { EntityRepositoryType } from '@mikro-orm/core'; | ||
import { JoinColumn, RelationId } from 'typeorm'; | ||
import { IsEnum, IsNotEmpty, IsOptional, IsUUID } from 'class-validator'; | ||
import { isMySQL, isPostgres } from '@gauzy/config'; | ||
import { IApiCallLog, ID, IUser, JsonData, RequestMethod } from '@gauzy/contracts'; | ||
import { ColumnIndex, MultiORMColumn, MultiORMEntity, MultiORMManyToOne } from '../core/decorators/entity'; | ||
import { TenantOrganizationBaseEntity, User } from '../core/entities/internal'; | ||
import { MikroOrmApiCallLogRepository } from './repository/mikro-orm-api-call-log.repository'; | ||
|
||
@MultiORMEntity('api_call_log', { mikroOrmRepository: () => MikroOrmApiCallLogRepository }) | ||
export class ApiCallLog extends TenantOrganizationBaseEntity implements IApiCallLog { | ||
[EntityRepositoryType]?: MikroOrmApiCallLogRepository; | ||
|
||
/** | ||
* Correlation ID to track the request across services | ||
*/ | ||
@ApiProperty({ type: () => String }) | ||
@IsNotEmpty() | ||
@IsUUID() | ||
@ColumnIndex() | ||
@MultiORMColumn() | ||
correlationId: ID; | ||
|
||
/** | ||
* The request URL that was called | ||
*/ | ||
@ApiProperty({ type: () => String }) | ||
@IsNotEmpty() | ||
@ColumnIndex() | ||
@MultiORMColumn() | ||
url: string; | ||
|
||
/** | ||
* The HTTP method (GET, POST, etc.) used in the request | ||
*/ | ||
@ApiProperty({ enum: RequestMethod }) | ||
@IsNotEmpty() | ||
@IsEnum(RequestMethod) | ||
@ColumnIndex() | ||
@MultiORMColumn() | ||
method: RequestMethod; | ||
|
||
/** | ||
* Request headers stored as JSON string | ||
*/ | ||
@ApiProperty({ type: () => String }) | ||
@IsNotEmpty() | ||
@MultiORMColumn({ type: isPostgres() ? 'jsonb' : isMySQL() ? 'json' : 'text' }) | ||
requestHeaders: JsonData; | ||
|
||
/** | ||
* Request body stored as JSON string | ||
*/ | ||
@ApiProperty({ type: () => String }) | ||
@IsNotEmpty() | ||
@MultiORMColumn({ type: isPostgres() ? 'jsonb' : isMySQL() ? 'json' : 'text' }) | ||
requestBody: JsonData; | ||
|
||
/** | ||
* Response body stored as JSON string | ||
*/ | ||
@ApiProperty({ type: () => String }) | ||
@IsNotEmpty() | ||
@MultiORMColumn({ type: isPostgres() ? 'jsonb' : isMySQL() ? 'json' : 'text' }) | ||
responseBody: JsonData; | ||
|
||
/** | ||
* The HTTP status code returned from the request | ||
*/ | ||
@ApiProperty({ type: () => Number }) | ||
@IsNotEmpty() | ||
@ColumnIndex() | ||
@MultiORMColumn() | ||
statusCode: number; | ||
|
||
/** | ||
* The timestamp when the request was initiated | ||
*/ | ||
@ApiProperty({ type: () => Date }) | ||
@IsNotEmpty() | ||
@ColumnIndex() | ||
@MultiORMColumn() | ||
requestTime: Date; | ||
|
||
/** | ||
* The timestamp when the response was completed | ||
*/ | ||
@ApiProperty({ type: () => Date }) | ||
@IsNotEmpty() | ||
@ColumnIndex() | ||
@MultiORMColumn() | ||
responseTime: Date; | ||
|
||
/** | ||
* IP Address of the client making the request | ||
*/ | ||
@ApiPropertyOptional({ type: () => String }) | ||
@IsOptional() | ||
@ColumnIndex() | ||
@MultiORMColumn({ nullable: true }) | ||
ipAddress: string; | ||
|
||
/** | ||
* The protocol used in the request (HTTP, HTTPS) | ||
*/ | ||
@ApiProperty({ type: () => String }) | ||
@IsNotEmpty() | ||
@ColumnIndex() | ||
@MultiORMColumn() | ||
protocol: string; | ||
|
||
/** | ||
* User-Agent string of the client making the request. | ||
* This could be a browser, desktop app, Postman, or any other API client. | ||
*/ | ||
@ApiProperty({ type: () => String }) | ||
@IsNotEmpty() | ||
@MultiORMColumn() | ||
userAgent: string; | ||
|
||
/* | ||
|-------------------------------------------------------------------------- | ||
| @ManyToOne | ||
|-------------------------------------------------------------------------- | ||
*/ | ||
|
||
/** | ||
* User who performed the action, if applicable. | ||
* | ||
* This relationship is nullable and uses the User entity. | ||
*/ | ||
@MultiORMManyToOne(() => User, { | ||
/** Indicates if the relation column value can be nullable or not. */ | ||
nullable: true, | ||
|
||
/** Database cascade action on delete. */ | ||
onDelete: 'CASCADE' | ||
}) | ||
@JoinColumn() | ||
user?: IUser; | ||
|
||
/** | ||
* The ID of the user who performed the action. | ||
* This column stores the user ID as a foreign key, if applicable. | ||
*/ | ||
@ApiPropertyOptional({ type: () => String }) | ||
@IsOptional() | ||
@IsUUID() | ||
@RelationId((it: ApiCallLog) => it.user) | ||
@ColumnIndex() | ||
@MultiORMColumn({ nullable: true, relationId: true }) | ||
userId?: ID; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { Module } from '@nestjs/common'; | ||
import { MikroOrmModule } from '@mikro-orm/nestjs'; | ||
import { TypeOrmModule } from '@nestjs/typeorm'; | ||
import { RolePermissionModule } from '../role-permission/role-permission.module'; | ||
import { ApiCallLog } from './api-call-log.entity'; | ||
import { ApiCallLogService } from './api-call-log.service'; | ||
import { ApiCallLogController } from './api-call-log.controller'; | ||
import { TypeOrmApiCallLogRepository } from './repository/type-orm-api-call-log.repository'; | ||
|
||
@Module({ | ||
imports: [TypeOrmModule.forFeature([ApiCallLog]), MikroOrmModule.forFeature([ApiCallLog]), RolePermissionModule], | ||
controllers: [ApiCallLogController], | ||
providers: [ApiCallLogService, TypeOrmApiCallLogRepository], | ||
exports: [ApiCallLogService] | ||
}) | ||
export class ApiCallLogModule {} |
Oops, something went wrong.