Skip to content

Commit

Permalink
chore: add telemetry information to supabase
Browse files Browse the repository at this point in the history
  • Loading branch information
pratapalakshmi committed Dec 15, 2024
1 parent 35e675e commit ddfa7d6
Show file tree
Hide file tree
Showing 13 changed files with 287 additions and 13 deletions.
71 changes: 70 additions & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion services/workflows-service/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ WEB_UI_SDK_URL=http://localhost:5202
#HASHING_KEY_SECRET="$2b$10$FovZTB91/QQ4Yu28nvL8e."
NOTION_API_KEY=secret
HASHING_KEY_SECRET_BASE64=JDJiJDEwJFRYNjhmQi5JMlRCWHN0aGowakFHSi4=
SECRETS_MANAGER_PROVIDER=in-memory
SECRETS_MANAGER_PROVIDER=in-memory
3 changes: 2 additions & 1 deletion services/workflows-service/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@ COPY --from=dev /app/scripts ./scripts
COPY --from=dev /app/src ./src
COPY --from=dev /app/tsconfig.build.json ./tsconfig.build.json
COPY --from=dev /app/tsconfig.json ./tsconfig.json
COPY --from=dev /app/entrypoint.sh ./entrypoint.sh

EXPOSE 3000

CMD [ "dumb-init", "npm", "run", "prod" ]
ENTRYPOINT ["/app/entrypoint.sh"]

68 changes: 68 additions & 0 deletions services/workflows-service/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/usr/bin/env bash

infra_file="/tmp/infra.json"

## Get cloudProvider details
function get_cloud_provider() {
release_details=$(uname -r || echo "")
if [[ $release_details == *"amzn"* ]]; then
cloud_provider="amazon"
elif [[ $release_details == *"azure"* ]]; then
cloud_provider="azure"
elif [[ $release_details == *"cloud"* ]]; then
cloud_provider="gcp"
elif [[ $release_details == *"generic"* ]]; then
cloud_provider="digitalocean"
elif [[ $release_details == *"ecs"* ]]; then
cloud_provider="alibaba"
elif [[ -n "${DYNO:-}" ]]; then
cloud_provider="heroku"
else
cloud_provider="others(including local)"
fi
}

## Get deployment tool details
function get_tool() {
if [[ -z "${KUBERNETES_SERVICE_HOST:-}" ]]; then
dep_tool="likely docker"
else
dep_tool="kubernetes"
fi
}

## Check hostname
function get_hostname() {
if [[ -f /etc/hostname ]]; then
hostname="$(cat /etc/hostname)"
else
hostname="$(hostname || echo "unknown")"
fi
}

## Get current Time
function get_current_time() {
currentTime="$(date -u -Iseconds || echo "unknown")"
}

## Check if it's an ECS Fargate deployment
function check_for_fargate() {
if [[ $cloud_provider == "amazon" && $dep_tool == "likely docker" ]]; then
dep_tool="ecs-fargate"
fi
}

## Main Block
get_cloud_provider || true
get_tool || true
get_hostname || true
check_for_fargate || true
get_current_time || true

infra_json='{"cloudProvider":"'"${cloud_provider}"'","tool":"'"${dep_tool}"'","hostname":"'"${hostname}"'","currentTime":"'"${currentTime}"'"}'
echo "${infra_json}"

echo "${infra_json}" > "${infra_file}"

exec dumb-init npm run prod

1 change: 1 addition & 0 deletions services/workflows-service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
"@sentry/integrations": "^7.52.1",
"@sentry/node": "^7.52.1",
"@sinclair/typebox": "0.32.15",
"@supabase/supabase-js": "^2.43.1",
"@t3-oss/env-core": "^0.6.1",
"ajv": "^8.12.0",
"ajv-formats": "^2.1.1",
Expand Down
3 changes: 3 additions & 0 deletions services/workflows-service/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { ServeStaticOptionsService } from './serve-static-options.service';
import { EndUserModule } from './end-user/end-user.module';
import { BusinessModule } from './business/business.module';
import { StorageModule } from './storage/storage.module';
import { SupabaseModule } from './supabase/supabase.module';
import { MulterModule } from '@nestjs/platform-express';
import { EventEmitterModule } from '@nestjs/event-emitter';
import { FilterModule } from '@/filter/filter.module';
Expand Down Expand Up @@ -74,6 +75,7 @@ export const validate = async (config: Record<string, unknown>) => {

return result.data;
};

@Module({
controllers: [SwaggerController],
imports: [
Expand Down Expand Up @@ -109,6 +111,7 @@ export const validate = async (config: Record<string, unknown>) => {
AuthModule,
HealthModule,
PrismaModule,
SupabaseModule,
ConfigModule.forRoot({
validate,
isGlobal: true,
Expand Down
25 changes: 16 additions & 9 deletions services/workflows-service/src/auth/local/local-auth.guard.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import { CanActivate, Injectable, ExecutionContext } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ExecutionContext } from '@nestjs/common';
import type { Request } from 'express';
import { SupabaseService } from '../../supabase/supabase.service';

export class LocalAuthGuard extends AuthGuard('local') {
async canActivate(context: ExecutionContext) {
const result = await super.canActivate(context);
const request = context.switchToHttp().getRequest<Request>();

await super.logIn(request);
@Injectable()
export class LocalAuthGuard extends AuthGuard('local') implements CanActivate {
constructor(private readonly supabaseService: SupabaseService) {
super();
}

return result as boolean;
async canActivate(context: ExecutionContext): Promise<boolean> {
const result = super.canActivate(context) as boolean;
const request = context.switchToHttp().getRequest();
if (result && request.user) {
const fullUrl = request.protocol + '://' + request.get('host') + request.originalUrl;
this.supabaseService.logSignIn(fullUrl);
}
super.logIn(request);
return Promise.resolve(result);
}
}
20 changes: 20 additions & 0 deletions services/workflows-service/src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,26 @@ export const serverEnvSchema = {
IN_MEMORIES_SECRET_ACQUIRER_ID: z.string().optional(),
IN_MEMORIES_SECRET_PRIVATE_KEY: z.string().optional(),
IN_MEMORIES_SECRET_CONSUMER_KEY: z.string().optional(),
SUPABASE_TELEMETRY_ENABLED: z
.enum(['true', 'false', ''])
.default('true')
.nullable()
.optional()
.transform(value => value === 'true' || value === null)
.describe('Enable or disable telemetry'),
TELEMETRY_SUPABASE_URL: z
.string()
.url()
.optional()
.default('https://lrwqumfbfgajpfnupayx.supabase.co')
.describe('Supabase URL for telemetry'),
TELEMETRY_SUPABASE_API_KEY: z
.string()
.optional()
.default(
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Imxyd3F1bWZiZmdhanBmbnVwYXl4Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MTUyNTU3NDMsImV4cCI6MjAzMDgzMTc0M30.EJWCMJhnBvG9_BQWw6wy3dT0GrwR3S41w2Z92R80BVI',
)
.describe('Supabase API key for telemetry'),
};

if (!process.env['ENVIRONMENT_NAME'] || process.env['ENVIRONMENT_NAME'] === 'local') {
Expand Down
1 change: 0 additions & 1 deletion services/workflows-service/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import '@total-typescript/ts-reset';

import passport from 'passport';
import dayjs from 'dayjs';
import cookieSession from 'cookie-session';
Expand Down
15 changes: 15 additions & 0 deletions services/workflows-service/src/supabase/mock-supabase.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Injectable, Logger } from '@nestjs/common';
import { ISupabaseService } from './types';

@Injectable()
export class MockSupabaseService implements ISupabaseService {
private readonly logger = new Logger(MockSupabaseService.name);

async logSignIn(url: string): Promise<void> {
this.logger.debug(`Mock log: Sign-in recorded for URL: ${url}`);
}

async logInfraData(infradata: JSON): Promise<void> {
this.logger.debug(`Mock log: ${infradata} Infra data logged`);
}
}
10 changes: 10 additions & 0 deletions services/workflows-service/src/supabase/supabase.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Module } from '@nestjs/common';
import { SupabaseService } from './supabase.service';
import { SentryModule } from '@/sentry/sentry.module';

@Module({
providers: [SupabaseService],
exports: [SupabaseService],
imports: [SentryModule],
})
export class SupabaseModule {}
77 changes: 77 additions & 0 deletions services/workflows-service/src/supabase/supabase.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { createClient, SupabaseClient } from '@supabase/supabase-js';
import { ISupabaseService } from './types';
import { SentryService } from '../sentry/sentry.service';

@Injectable()
export class SupabaseService implements ISupabaseService {
private readonly supabaseClient!: SupabaseClient;
private readonly logger = new Logger(SupabaseService.name);

constructor(
private readonly configService: ConfigService,
private readonly SentryService: SentryService,
) {
const telemetryEnabled = this.configService.get('TELEMETRY_ENABLED');
const supabaseUrl = this.configService.get<string>('TELEMETRY_SUPABASE_URL');
const supabaseApiKey = this.configService.get<string>('TELEMETRY_SUPABASE_API_KEY');
if (telemetryEnabled) {
if (!supabaseUrl || !supabaseApiKey) {
throw new Error('Supabase URL or API key is missing in configuration');
} else {
this.supabaseClient = createClient(supabaseUrl, supabaseApiKey, {
db: { schema: 'public' },
});
this.logger.log('Supabase client initialized.');
// This log is created as part of the entrypoint script
// which gather details of the infrastructure.
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const infradata = require('/tmp/infra.json');
void this.logInfraData(infradata);
} catch (error: Error | any) {
if (error.code === 'MODULE_NOT_FOUND') {
this.logger.error(`file not present: ${error.message}`);
this.SentryService.captureException(error.message);
} else {
this.logger.error(`Exception infra data not present: ${error.message}`);
}
}
}
} else {
this.logger.log('Telemetry disabled.');
}
}

async logSignIn(url: string): Promise<void> {
try {
const { data, error } = await this.supabaseClient.from('logins').insert([{ url }]);

if (error) {
this.logger.error(`Failed to log sign-in: ${error.message}`);
} else {
this.logger.log(`Sign-in logged successfully: ${data}`);
}
} catch (error: Error | any) {
this.logger.error(`Exception to log sign in data: ${error.message}`);
this.SentryService.captureException(error.message);
}
}

async logInfraData(infradata: JSON): Promise<void> {
try {
const { data, error } = await this.supabaseClient.from('infra').insert([infradata]);

if (error) {
this.logger.error(`Failed to log infra data: ${error.message}`);
} else {
this.logger.log(`logged infra data successfully: ${data}`);
}
} catch (error: Error | any) {
this.logger.error(`Exception to log infra data: ${error.message}`);
this.SentryService.captureException(error.message);
}
}
}
4 changes: 4 additions & 0 deletions services/workflows-service/src/supabase/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface ISupabaseService {
logSignIn(url: string): Promise<void>;
logInfraData(infradata: JSON): Promise<void>;
}

0 comments on commit ddfa7d6

Please sign in to comment.