Last active
January 29, 2020 14:46
-
-
Save krivochenko/a4d53a1a1c69e727cad10a1d42e48393 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common'; | |
import { Observable } from 'rxjs'; | |
import { tap } from 'rxjs/operators'; | |
import { StatisticsService } from './statistics.service'; | |
@Injectable() | |
export class StatisticsInterceptor implements NestInterceptor { | |
constructor( | |
private readonly statisticsService: StatisticsService, | |
) { | |
} | |
intercept(context: ExecutionContext, next: CallHandler<any>): Observable<any> | Promise<Observable<any>> { | |
const controllerClass = context.getClass(); | |
const method = context.getHandler(); | |
const controllerPath = Reflect.getMetadata('path', controllerClass).replace(/(^\/)|(\/$)/g, ''); | |
const methodPath = Reflect.getMetadata('path', method).replace(/(^\/)|(\/$)/g, ''); | |
const parts = [controllerPath, methodPath].filter(part => !!part); | |
const fullPath = parts.join('/') || '/'; | |
const startTime = Date.now(); | |
return next | |
.handle() | |
.pipe(tap(async () => { | |
const endTime = Date.now(); | |
const time = endTime - startTime; | |
await this.statisticsService.add(fullPath, time); | |
})); | |
} | |
} |
This file contains hidden or 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
import { Injectable } from '@nestjs/common'; | |
import { RedisService } from '../redis/redis.service'; | |
import { ago, now } from '../utils/helpers'; | |
import { AppConfig } from '../../config/app.config'; | |
import { InjectConfig } from '@shakajs/nestjs-config'; | |
@Injectable() | |
export class StatisticsService { | |
constructor( | |
private readonly redisService: RedisService, | |
@InjectConfig() private readonly config: AppConfig, | |
) {} | |
async add(path: string, time: number) { | |
const records = await this.getRecords(path); | |
records.push({ path, time, createdAt: now() }); | |
await this.client.set(path, JSON.stringify(records), 'EX', this.config.statisticsPeriod); | |
} | |
getStatistics() { | |
return this.client.keys('*').then(async (paths) => { | |
const statistics = {}; | |
for (const path of paths) { | |
const records = await this.getRecords(path); | |
const fullTime = records.reduce((previous, record) => previous + record.time, 0); | |
statistics[path] = { | |
requestsCount: records.length, | |
avgTime: fullTime / records.length, | |
} | |
} | |
return statistics; | |
}); | |
} | |
getRecords(path: string) { | |
return this.client.get(path).then(async (result) => { | |
const records: StatisticRecord[] = !!result ? JSON.parse(result) : []; | |
return records.filter(record => record.createdAt >= ago(this.config.statisticsPeriod * 24)); | |
}); | |
} | |
get client() { | |
return this.redisService.getClient('statistics'); | |
} | |
} | |
export interface StatisticRecord { | |
path: string; | |
time: number; | |
createdAt: number; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment