Connect EventTracker to TB endpoint (#7240)

#7091 
EventTrackers send information of events to the TinyBird instance:

In order to test:

1. Set ANALYTICS_ENABLED= true and TELEMETRY_ENABLED=true in
evironment-variables.ts
2. Set the TINYBIRD_TOKEN in environment variables (go to TiniyBird
Tokens)
3. Log in to twenty's TinyBird and go to datasources/analytics_events in
twenty_analytics workspace
4. Run twenty and navigate it
5. New events will be logged in the datasources, containing their
timestamp, sessionId and payload.

<img width="1189" alt="Screenshot 2024-09-24 at 17 23 01"
src="https://github.com/user-attachments/assets/85375897-504d-4e75-98e4-98e6a9671f98">
Example of payload when user is not logged in

```
{"hostName":"localhost",
"pathname":"/welcome",
"locale":"en-US",
"userAgent":"Mozilla/5.0",
"href":"http://localhost:3001/welcome",
"referrer":"",
"timeZone":"Europe/Barcelona"}
```
Example of payload when user is logged in
```
{"userId":"2020202",
"workspaceId":"202",
"workspaceDisplayName":"Apple",
"workspaceDomainName":"apple.dev",
"hostName":"localhost",
"pathname":"/objects/companies",
"locale":"en-US",
"userAgent":"Mozilla/5.0Chrome/128.0.0.0Safari/537.36",
"href":"http://localhost:3001/objects/companies",
"referrer":"",
"timeZone":"Europe/Paris"}
```

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
Ana Sofia Marin Alexandre
2024-09-26 10:53:10 +02:00
committed by GitHub
parent c9e882f4c0
commit 16bb1f22e4
28 changed files with 273 additions and 187 deletions

View File

@ -1,14 +1,16 @@
import { Module } from '@nestjs/common';
import { HttpModule } from '@nestjs/axios';
import { Module } from '@nestjs/common';
import { AnalyticsService } from './analytics.service';
import { AnalyticsResolver } from './analytics.resolver';
import { AnalyticsService } from './analytics.service';
const TINYBIRD_BASE_URL = 'https://api.eu-central-1.aws.tinybird.co/v0';
@Module({
providers: [AnalyticsResolver, AnalyticsService],
imports: [
HttpModule.register({
baseURL: 'https://t.twenty.com/api/v1/s2s',
baseURL: TINYBIRD_BASE_URL,
}),
],
exports: [AnalyticsService],

View File

@ -31,9 +31,6 @@ export class AnalyticsResolver {
createAnalyticsInput,
user?.id,
workspace?.id,
workspace?.displayName,
workspace?.domainName,
this.environmentService.get('SERVER_URL') ?? request.hostname,
);
}
}

View File

@ -1,16 +1,19 @@
import { Injectable, Logger } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { Injectable, Logger } from '@nestjs/common';
import { AxiosRequestConfig } from 'axios';
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
type CreateEventInput = {
type: string;
data: object;
action: string;
payload: object;
};
@Injectable()
export class AnalyticsService {
private readonly logger = new Logger(AnalyticsService.name);
private readonly datasource = 'event';
constructor(
private readonly environmentService: EnvironmentService,
@ -21,30 +24,42 @@ export class AnalyticsService {
createEventInput: CreateEventInput,
userId: string | null | undefined,
workspaceId: string | null | undefined,
workspaceDisplayName: string | undefined,
workspaceDomainName: string | undefined,
hostName: string | undefined,
) {
if (!this.environmentService.get('TELEMETRY_ENABLED')) {
if (this.environmentService.get('ANALYTICS_ENABLED')) {
return { success: true };
}
const data = {
type: createEventInput.type,
data: {
hostname: hostName,
userUUID: userId,
workspaceUUID: workspaceId,
workspaceDisplayName: workspaceDisplayName,
workspaceDomainName: workspaceDomainName,
...createEventInput.data,
action: createEventInput.action,
timestamp: new Date().toISOString(),
version: '1',
payload: {
userId: userId,
workspaceId: workspaceId,
...createEventInput.payload,
},
};
const config: AxiosRequestConfig = {
headers: {
Authorization:
'Bearer ' + this.environmentService.get('TINYBIRD_TOKEN'),
},
};
try {
await this.httpService.axiosRef.post('/v1', data);
} catch {
this.logger.error('Failed to send analytics event');
await this.httpService.axiosRef.post(
`/events?name=${this.datasource}`,
data,
config,
);
} catch (error) {
this.logger.error('Error occurred:', error);
if (error.response) {
this.logger.error(
`Error response body: ${JSON.stringify(error.response.data)}`,
);
}
return { success: false };
}

View File

@ -1,16 +1,16 @@
import { ArgsType, Field } from '@nestjs/graphql';
import { IsNotEmpty, IsObject, IsString } from 'class-validator';
import graphqlTypeJson from 'graphql-type-json';
import { IsNotEmpty, IsString, IsObject } from 'class-validator';
@ArgsType()
export class CreateAnalyticsInput {
@Field({ description: 'Type of the event' })
@IsNotEmpty()
@IsString()
type: string;
action: string;
@Field(() => graphqlTypeJson, { description: 'Event data in JSON format' })
@Field(() => graphqlTypeJson, { description: 'Event payload in JSON format' })
@IsObject()
data: JSON;
payload: JSON;
}