File tree Expand file tree Collapse file tree 9 files changed +71
-0
lines changed Expand file tree Collapse file tree 9 files changed +71
-0
lines changed Original file line number Diff line number Diff line change @@ -6,6 +6,7 @@ import { ToolsModule } from './mcp/tools/tools.module';
6
6
import { GlobalProvidersModule } from './shared/global/globalProviders.module' ;
7
7
import { ResourcesModule } from './mcp/resources/resources.module' ;
8
8
import { randomUUID } from 'crypto' ;
9
+ import { TimingInterceptorMiddleware } from './shared/global/timingInterceptor' ;
9
10
10
11
@Module ( {
11
12
imports : [
@@ -28,5 +29,6 @@ import { randomUUID } from 'crypto';
28
29
export class AppModule implements NestModule {
29
30
configure ( consumer : MiddlewareConsumer ) {
30
31
consumer . apply ( TokenValidatorMiddleware ) . forRoutes ( '*' ) ;
32
+ consumer . apply ( TimingInterceptorMiddleware ) . forRoutes ( '*' ) ;
31
33
}
32
34
}
Original file line number Diff line number Diff line change @@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common';
2
2
import { Resource } from '@tc/mcp-nest' ;
3
3
import axios from 'axios' ;
4
4
import { Logger } from 'src/shared/global' ;
5
+ import { LogTime } from 'src/shared/global/logTime.decorator' ;
5
6
6
7
const SPEC_URL =
7
8
'https://raw.githubusercontent.com/topcoder-platform/challenge-api-v6/refs/heads/develop/docs/swagger.yaml' ;
@@ -16,6 +17,7 @@ export class ChallengesApiSwaggerResource {
16
17
description : 'Swagger documentation for the Challenges V6 API' ,
17
18
mimeType : 'text/yaml' ,
18
19
} )
20
+ @LogTime ( 'ChallengesApiSwaggerResource' )
19
21
async getChallengesApiSwagger ( ) {
20
22
this . logger . debug ( 'Fetching Challenges V6 API Swagger' ) ;
21
23
// Fetch the content from the URI and return it.
Original file line number Diff line number Diff line change @@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common';
2
2
import { Resource } from '@tc/mcp-nest' ;
3
3
import axios from 'axios' ;
4
4
import { Logger } from 'src/shared/global' ;
5
+ import { LogTime } from 'src/shared/global/logTime.decorator' ;
5
6
6
7
const SPEC_URL =
7
8
'https://raw.githubusercontent.com/topcoder-platform/identity-api-v6/refs/heads/develop/doc/swagger.yaml' ;
@@ -16,6 +17,7 @@ export class IdentityApiSwaggerResource {
16
17
description : 'Swagger documentation for the Identity V6 API' ,
17
18
mimeType : 'text/yaml' ,
18
19
} )
20
+ @LogTime ( 'IdentityApiSwaggerResource' )
19
21
async getIdentityApiSwagger ( ) {
20
22
this . logger . debug ( 'Fetching Identity V6 API Swagger' ) ;
21
23
// Fetch the content from the URI and return it.
Original file line number Diff line number Diff line change @@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common';
2
2
import { Resource } from '@tc/mcp-nest' ;
3
3
import axios from 'axios' ;
4
4
import { Logger } from 'src/shared/global' ;
5
+ import { LogTime } from 'src/shared/global/logTime.decorator' ;
5
6
6
7
const SPEC_URL =
7
8
'https://raw.githubusercontent.com/topcoder-platform/member-api-v6/refs/heads/develop/docs/swagger.yaml' ;
@@ -16,6 +17,7 @@ export class MemberApiSwaggerResource {
16
17
description : 'Swagger documentation for the Member V6 API' ,
17
18
mimeType : 'text/yaml' ,
18
19
} )
20
+ @LogTime ( 'MemberApiSwaggerResource' )
19
21
async getMemberApiSwagger ( ) {
20
22
this . logger . debug ( 'Fetching Member V6 API Swagger' ) ;
21
23
// Fetch the content from the URI and return it.
Original file line number Diff line number Diff line change @@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common';
2
2
import { Resource } from '@tc/mcp-nest' ;
3
3
import axios from 'axios' ;
4
4
import { Logger } from 'src/shared/global' ;
5
+ import { LogTime } from 'src/shared/global/logTime.decorator' ;
5
6
6
7
const SPEC_URL = 'https://api.topcoder-dev.com/v6/review/api-docs-yaml' ;
7
8
@@ -15,6 +16,7 @@ export class ReviewApiSwaggerResource {
15
16
description : 'Swagger documentation for the Review V6 API' ,
16
17
mimeType : 'text/yaml' ,
17
18
} )
19
+ @LogTime ( 'ReviewApiSwaggerResource' )
18
20
async getReviewApiSwagger ( ) {
19
21
this . logger . debug ( 'Fetching Review V6 API Swagger' ) ;
20
22
// Fetch the content from the URI and return it.
Original file line number Diff line number Diff line change @@ -5,6 +5,7 @@ import { QUERY_CHALLENGES_TOOL_PARAMETERS } from './queryChallenges.parameters';
5
5
import { TopcoderChallengesService } from 'src/shared/topcoder/challenges.service' ;
6
6
import { Logger } from 'src/shared/global' ;
7
7
import { QUERY_CHALLENGES_TOOL_OUTPUT_SCHEMA } from './queryChallenges.output' ;
8
+ import { LogTime } from 'src/shared/global/logTime.decorator' ;
8
9
9
10
@Injectable ( )
10
11
export class QueryChallengesTool {
@@ -131,6 +132,7 @@ export class QueryChallengesTool {
131
132
readOnlyHint : true ,
132
133
} ,
133
134
} )
135
+ @LogTime ( 'ChallengesTool' )
134
136
async queryChallenges ( params ) {
135
137
return this . _queryChallenges ( params ) ;
136
138
}
Original file line number Diff line number Diff line change @@ -5,6 +5,7 @@ import { Logger } from 'src/shared/global';
5
5
import { QUERY_SKILLS_TOOL_PARAMETERS } from './querySkills.parameters' ;
6
6
import { QUERY_SKILLS_TOOL_OUTPUT_SCHEMA } from './querySkills.output' ;
7
7
import { TopcoderSkillsService } from 'src/shared/topcoder/skills.service' ;
8
+ import { LogTime } from 'src/shared/global/logTime.decorator' ;
8
9
9
10
@Injectable ( )
10
11
export class QuerySkillsTool {
@@ -125,6 +126,7 @@ export class QuerySkillsTool {
125
126
readOnlyHint : true ,
126
127
} ,
127
128
} )
129
+ @LogTime ( 'SkillsTool' )
128
130
async querySkills ( params ) {
129
131
return this . _querySkills ( params ) ;
130
132
}
Original file line number Diff line number Diff line change
1
+ import { Logger } from '@nestjs/common' ;
2
+
3
+ export function LogTime ( label ?: string ) {
4
+ const logger = new Logger ( 'ExecutionTime' ) ;
5
+
6
+ return function (
7
+ target : any ,
8
+ propertyKey : string ,
9
+ descriptor : PropertyDescriptor ,
10
+ ) {
11
+ const originalMethod = descriptor . value ;
12
+
13
+ descriptor . value = async function ( ...args : any [ ] ) {
14
+ const start = Date . now ( ) ;
15
+
16
+ try {
17
+ const result = await originalMethod . apply ( this , args ) ;
18
+ const ms = Date . now ( ) - start ;
19
+ logger . log ( `${ label || propertyKey } executed in ${ ms } ms` ) ;
20
+ return result ;
21
+ } catch ( error ) {
22
+ const ms = Date . now ( ) - start ;
23
+ logger . error (
24
+ `${ label || propertyKey } failed after ${ ms } ms – ${ error . message } ` ,
25
+ ) ;
26
+ throw error ;
27
+ }
28
+ } ;
29
+
30
+ return descriptor ;
31
+ } ;
32
+ }
Original file line number Diff line number Diff line change
1
+ import { Injectable , NestMiddleware , Logger } from '@nestjs/common' ;
2
+
3
+ import { Request , Response , NextFunction } from 'express' ;
4
+
5
+ @Injectable ( )
6
+ export class TimingInterceptorMiddleware implements NestMiddleware {
7
+ private logger = new Logger ( 'TimingInterceptor' ) ;
8
+
9
+ use ( request : Request , response : Response , next : NextFunction ) : void {
10
+ const { method, originalUrl : url } = request ;
11
+ const start = Date . now ( ) ;
12
+ const mcpMethod = request . body ?. method ;
13
+
14
+ response . on ( 'close' , ( ) => {
15
+ const { statusCode } = response ;
16
+ const duration = Date . now ( ) - start ;
17
+
18
+ this . logger . log (
19
+ `${ method } ${ mcpMethod ? `{${ mcpMethod } } ` : '' } ${ url } ${ statusCode } took ${ duration } ms`
20
+ ) ;
21
+ } ) ;
22
+
23
+ next ( ) ;
24
+ }
25
+ }
You can’t perform that action at this time.
0 commit comments