From 0c3bc0cae654a6783f85e86995f978cc458d8b5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karol=20S=C3=B3jko?= Date: Thu, 4 Jan 2024 17:22:42 +0100 Subject: [PATCH] feat(syncing-server): send user based metrics to cloudwatch --- packages/syncing-server/bin/statistics.ts | 32 +++++++++++++ .../Domain/Metrics/MetricsStoreInterface.ts | 9 ++++ .../src/Infra/Dummy/DummyMetricStore.ts | 12 +++++ .../src/Infra/Redis/RedisMetricStore.ts | 45 +++++++++++++++++++ 4 files changed, 98 insertions(+) diff --git a/packages/syncing-server/bin/statistics.ts b/packages/syncing-server/bin/statistics.ts index 7b91b7774..ed15af818 100644 --- a/packages/syncing-server/bin/statistics.ts +++ b/packages/syncing-server/bin/statistics.ts @@ -57,6 +57,38 @@ const sendStatistics = async ( ) } } + + const userMetricsToProcess = [Metric.NAMES.ItemOperation, Metric.NAMES.ContentSizeUtilized] + for (const metricToProcess of userMetricsToProcess) { + for (let i = 0; i <= minutesToProcess; i++) { + const dateNMinutesAgo = timer.getUTCDateNMinutesAgo(minutesToProcess - i) + const timestamp = timer.convertDateToMicroseconds(dateNMinutesAgo) + + const statistics = await metricsStore.getUserBasedStatistics(metricToProcess, timestamp) + + if (statistics.sampleCount === 0) { + continue + } + + await cloudwatchClient.send( + new PutMetricDataCommand({ + Namespace: 'SyncingServer', + MetricData: [ + { + MetricName: metricToProcess, + Timestamp: dateNMinutesAgo, + StatisticValues: { + Maximum: statistics.max, + Minimum: statistics.min, + SampleCount: statistics.sampleCount, + Sum: statistics.sum, + }, + }, + ], + }), + ) + } + } } const container = new ContainerConfigLoader('worker') diff --git a/packages/syncing-server/src/Domain/Metrics/MetricsStoreInterface.ts b/packages/syncing-server/src/Domain/Metrics/MetricsStoreInterface.ts index 8f26068a2..6d91e288d 100644 --- a/packages/syncing-server/src/Domain/Metrics/MetricsStoreInterface.ts +++ b/packages/syncing-server/src/Domain/Metrics/MetricsStoreInterface.ts @@ -2,6 +2,15 @@ import { Metric } from './Metric' export interface MetricsStoreInterface { storeUserBasedMetric(metric: Metric, value: number, userUuid: string): Promise + getUserBasedStatistics( + name: string, + timestamp: number, + ): Promise<{ + sum: number + max: number + min: number + sampleCount: number + }> storeMetric(metric: Metric): Promise getStatistics( name: string, diff --git a/packages/syncing-server/src/Infra/Dummy/DummyMetricStore.ts b/packages/syncing-server/src/Infra/Dummy/DummyMetricStore.ts index 37cabdd7b..3c8ee31ed 100644 --- a/packages/syncing-server/src/Infra/Dummy/DummyMetricStore.ts +++ b/packages/syncing-server/src/Infra/Dummy/DummyMetricStore.ts @@ -2,6 +2,18 @@ import { MetricsStoreInterface } from '../../Domain/Metrics/MetricsStoreInterfac import { Metric } from '../../Domain/Metrics/Metric' export class DummyMetricStore implements MetricsStoreInterface { + async getUserBasedStatistics( + _name: string, + _timestamp: number, + ): Promise<{ sum: number; max: number; min: number; sampleCount: number }> { + return { + sum: 0, + max: 0, + min: 0, + sampleCount: 0, + } + } + async storeUserBasedMetric(_metric: Metric, _value: number, _userUuid: string): Promise { // do nothing } diff --git a/packages/syncing-server/src/Infra/Redis/RedisMetricStore.ts b/packages/syncing-server/src/Infra/Redis/RedisMetricStore.ts index 005deb258..b41024a25 100644 --- a/packages/syncing-server/src/Infra/Redis/RedisMetricStore.ts +++ b/packages/syncing-server/src/Infra/Redis/RedisMetricStore.ts @@ -29,6 +29,51 @@ export class RedisMetricStore implements MetricsStoreInterface { await pipeline.exec() } + async getUserBasedStatistics( + name: string, + timestamp: number, + ): Promise<{ sum: number; max: number; min: number; sampleCount: number }> { + const date = this.timer.convertMicrosecondsToDate(timestamp) + const dateToTheMinuteString = this.timer.convertDateToFormattedString(date, 'YYYY-MM-DD HH:mm') + + const userMetricsKeys = await this.redisClient.keys( + `${this.METRIC_PER_USER_PREFIX}:*:${name}:${dateToTheMinuteString}`, + ) + + let sum = 0 + let max = 0 + let min = 0 + let sampleCount = 0 + + const values = await this.redisClient.mget(userMetricsKeys) + + for (const value of values) { + if (!value) { + continue + } + + const valueAsNumber = Number(value) + + sum += valueAsNumber + sampleCount++ + + if (valueAsNumber > max) { + max = valueAsNumber + } + + if (valueAsNumber < min) { + min = valueAsNumber + } + } + + return { + sum, + max, + min, + sampleCount, + } + } + async getStatistics( name: string, from: number,