Update what is being audit logged (#11833)

No need to audit log workflow runs as it's already a form of audit log.
Add more audit log for other objects
Rename MessagingTelemetry to MessagingMonitoring
Merge Analytics and Audit in one (Audit)

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
This commit is contained in:
Félix Malfait
2025-05-04 14:35:41 +02:00
committed by GitHub
parent b1994f3707
commit 49b7f5255f
101 changed files with 948 additions and 1032 deletions

View File

@ -19,7 +19,7 @@ import {
MessageImportSyncStep,
} from 'src/modules/messaging/message-import-manager/services/messaging-import-exception-handler.service';
import { MessagingPartialMessageListFetchService } from 'src/modules/messaging/message-import-manager/services/messaging-partial-message-list-fetch.service';
import { MessagingTelemetryService } from 'src/modules/messaging/monitoring/services/messaging-telemetry.service';
import { MessagingMonitoringService } from 'src/modules/messaging/monitoring/services/messaging-monitoring.service';
export type MessagingMessageListFetchJobData = {
messageChannelId: string;
@ -36,7 +36,7 @@ export class MessagingMessageListFetchJob {
constructor(
private readonly messagingFullMessageListFetchService: MessagingFullMessageListFetchService,
private readonly messagingPartialMessageListFetchService: MessagingPartialMessageListFetchService,
private readonly messagingTelemetryService: MessagingTelemetryService,
private readonly messagingMonitoringService: MessagingMonitoringService,
private readonly twentyORMManager: TwentyORMManager,
private readonly connectedAccountRefreshTokensService: ConnectedAccountRefreshTokensService,
private readonly messageImportErrorHandlerService: MessageImportExceptionHandlerService,
@ -46,7 +46,7 @@ export class MessagingMessageListFetchJob {
async handle(data: MessagingMessageListFetchJobData): Promise<void> {
const { messageChannelId, workspaceId } = data;
await this.messagingTelemetryService.track({
await this.messagingMonitoringService.track({
eventName: 'message_list_fetch_job.triggered',
messageChannelId,
workspaceId,
@ -65,7 +65,7 @@ export class MessagingMessageListFetchJob {
});
if (!messageChannel) {
await this.messagingTelemetryService.track({
await this.messagingMonitoringService.track({
eventName: 'message_list_fetch_job.error.message_channel_not_found',
messageChannelId,
workspaceId,
@ -94,7 +94,7 @@ export class MessagingMessageListFetchJob {
switch (error.code) {
case ConnectedAccountRefreshAccessTokenExceptionCode.REFRESH_ACCESS_TOKEN_FAILED:
case ConnectedAccountRefreshAccessTokenExceptionCode.REFRESH_TOKEN_NOT_FOUND:
await this.messagingTelemetryService.track({
await this.messagingMonitoringService.track({
eventName: `refresh_token.error.insufficient_permissions`,
workspaceId,
connectedAccountId: messageChannel.connectedAccountId,
@ -121,7 +121,7 @@ export class MessagingMessageListFetchJob {
`Fetching partial message list for workspace ${workspaceId} and messageChannelId ${messageChannel.id}`,
);
await this.messagingTelemetryService.track({
await this.messagingMonitoringService.track({
eventName: 'partial_message_list_fetch.started',
workspaceId,
connectedAccountId: messageChannel.connectedAccount.id,
@ -134,7 +134,7 @@ export class MessagingMessageListFetchJob {
workspaceId,
);
await this.messagingTelemetryService.track({
await this.messagingMonitoringService.track({
eventName: 'partial_message_list_fetch.completed',
workspaceId,
connectedAccountId: messageChannel.connectedAccount.id,
@ -148,7 +148,7 @@ export class MessagingMessageListFetchJob {
`Fetching full message list for workspace ${workspaceId} and account ${messageChannel.connectedAccount.id}`,
);
await this.messagingTelemetryService.track({
await this.messagingMonitoringService.track({
eventName: 'full_message_list_fetch.started',
workspaceId,
connectedAccountId: messageChannel.connectedAccount.id,
@ -160,7 +160,7 @@ export class MessagingMessageListFetchJob {
workspaceId,
);
await this.messagingTelemetryService.track({
await this.messagingMonitoringService.track({
eventName: 'full_message_list_fetch.completed',
workspaceId,
connectedAccountId: messageChannel.connectedAccount.id,

View File

@ -10,8 +10,7 @@ import {
MessageChannelWorkspaceEntity,
} from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
import { MessagingMessagesImportService } from 'src/modules/messaging/message-import-manager/services/messaging-messages-import.service';
import { MessagingTelemetryService } from 'src/modules/messaging/monitoring/services/messaging-telemetry.service';
import { MessagingMonitoringService } from 'src/modules/messaging/monitoring/services/messaging-monitoring.service';
export type MessagingMessagesImportJobData = {
messageChannelId: string;
workspaceId: string;
@ -24,7 +23,7 @@ export type MessagingMessagesImportJobData = {
export class MessagingMessagesImportJob {
constructor(
private readonly messagingMessagesImportService: MessagingMessagesImportService,
private readonly messagingTelemetryService: MessagingTelemetryService,
private readonly messagingMonitoringService: MessagingMonitoringService,
private readonly twentyORMManager: TwentyORMManager,
) {}
@ -32,7 +31,7 @@ export class MessagingMessagesImportJob {
async handle(data: MessagingMessagesImportJobData): Promise<void> {
const { messageChannelId, workspaceId } = data;
await this.messagingTelemetryService.track({
await this.messagingMonitoringService.track({
eventName: 'messages_import.triggered',
workspaceId,
messageChannelId,
@ -51,7 +50,7 @@ export class MessagingMessagesImportJob {
});
if (!messageChannel) {
await this.messagingTelemetryService.track({
await this.messagingMonitoringService.track({
eventName: 'messages_import.error.message_channel_not_found',
messageChannelId,
workspaceId,

View File

@ -20,8 +20,7 @@ import { MessagingGetMessagesService } from 'src/modules/messaging/message-impor
import { MessageImportExceptionHandlerService } from 'src/modules/messaging/message-import-manager/services/messaging-import-exception-handler.service';
import { MessagingMessagesImportService } from 'src/modules/messaging/message-import-manager/services/messaging-messages-import.service';
import { MessagingSaveMessagesAndEnqueueContactCreationService } from 'src/modules/messaging/message-import-manager/services/messaging-save-messages-and-enqueue-contact-creation.service';
import { MessagingTelemetryService } from 'src/modules/messaging/monitoring/services/messaging-telemetry.service';
import { MessagingMonitoringService } from 'src/modules/messaging/monitoring/services/messaging-monitoring.service';
describe('MessagingMessagesImportService', () => {
let service: MessagingMessagesImportService;
let messageChannelSyncStatusService: MessageChannelSyncStatusService;
@ -78,7 +77,7 @@ describe('MessagingMessagesImportService', () => {
},
},
{
provide: MessagingTelemetryService,
provide: MessagingMonitoringService,
useValue: {
track: jest.fn().mockResolvedValue(undefined),
},

View File

@ -26,8 +26,7 @@ import {
} from 'src/modules/messaging/message-import-manager/services/messaging-import-exception-handler.service';
import { MessagingSaveMessagesAndEnqueueContactCreationService } from 'src/modules/messaging/message-import-manager/services/messaging-save-messages-and-enqueue-contact-creation.service';
import { filterEmails } from 'src/modules/messaging/message-import-manager/utils/filter-emails.util';
import { MessagingTelemetryService } from 'src/modules/messaging/monitoring/services/messaging-telemetry.service';
import { MessagingMonitoringService } from 'src/modules/messaging/monitoring/services/messaging-monitoring.service';
@Injectable()
export class MessagingMessagesImportService {
private readonly logger = new Logger(MessagingMessagesImportService.name);
@ -38,7 +37,7 @@ export class MessagingMessagesImportService {
private readonly messageChannelSyncStatusService: MessageChannelSyncStatusService,
private readonly saveMessagesAndEnqueueContactCreationService: MessagingSaveMessagesAndEnqueueContactCreationService,
private readonly connectedAccountRefreshTokensService: ConnectedAccountRefreshTokensService,
private readonly messagingTelemetryService: MessagingTelemetryService,
private readonly messagingMonitoringService: MessagingMonitoringService,
@InjectObjectMetadataRepository(BlocklistWorkspaceEntity)
private readonly blocklistRepository: BlocklistRepository,
private readonly emailAliasManagerService: EmailAliasManagerService,
@ -62,7 +61,7 @@ export class MessagingMessagesImportService {
return;
}
await this.messagingTelemetryService.track({
await this.messagingMonitoringService.track({
eventName: 'messages_import.started',
workspaceId,
connectedAccountId: messageChannel.connectedAccountId,
@ -87,7 +86,7 @@ export class MessagingMessagesImportService {
switch (error.code) {
case ConnectedAccountRefreshAccessTokenExceptionCode.REFRESH_ACCESS_TOKEN_FAILED:
case ConnectedAccountRefreshAccessTokenExceptionCode.REFRESH_TOKEN_NOT_FOUND:
await this.messagingTelemetryService.track({
await this.messagingMonitoringService.track({
eventName: `refresh_token.error.insufficient_permissions`,
workspaceId,
connectedAccountId: messageChannel.connectedAccountId,
@ -208,7 +207,7 @@ export class MessagingMessagesImportService {
messageChannel: MessageChannelWorkspaceEntity,
workspaceId: string,
) {
await this.messagingTelemetryService.track({
await this.messagingMonitoringService.track({
eventName: 'messages_import.completed',
workspaceId,
connectedAccountId: messageChannel.connectedAccountId,

View File

@ -1,7 +1,7 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AnalyticsModule } from 'src/engine/core-modules/analytics/analytics.module';
import { AuditModule } from 'src/engine/core-modules/audit/audit.module';
import { FeatureFlag } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
@ -22,7 +22,7 @@ import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-o
@Module({
imports: [
TypeOrmModule.forFeature([FeatureFlag, Workspace], 'core'),
AnalyticsModule,
AuditModule,
ContactCreationManagerModule,
WorkspaceDataSourceModule,
ObjectMetadataRepositoryModule.forFeature([

View File

@ -13,7 +13,7 @@ import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queu
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
import { MessagingTelemetryService } from 'src/modules/messaging/monitoring/services/messaging-telemetry.service';
import { MessagingMonitoringService } from 'src/modules/messaging/monitoring/services/messaging-monitoring.service';
export const MESSAGING_MESSAGE_CHANNEL_SYNC_STATUS_MONITORING_CRON_PATTERN =
'2/10 * * * *'; //Every 10 minutes, starting at 2 minutes past the hour
@ -27,7 +27,7 @@ export class MessagingMessageChannelSyncStatusMonitoringCronJob {
constructor(
@InjectRepository(Workspace, 'core')
private readonly workspaceRepository: Repository<Workspace>,
private readonly messagingTelemetryService: MessagingTelemetryService,
private readonly messagingMonitoringService: MessagingMonitoringService,
private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
private readonly exceptionHandlerService: ExceptionHandlerService,
) {}
@ -40,7 +40,7 @@ export class MessagingMessageChannelSyncStatusMonitoringCronJob {
async handle(): Promise<void> {
this.logger.log('Starting message channel sync status monitoring...');
await this.messagingTelemetryService.track({
await this.messagingMonitoringService.track({
eventName: 'message_channel.monitoring.sync_status.start',
message: 'Starting message channel sync status monitoring',
});
@ -66,7 +66,7 @@ export class MessagingMessageChannelSyncStatusMonitoringCronJob {
if (!messageChannel.syncStatus) {
continue;
}
await this.messagingTelemetryService.track({
await this.messagingMonitoringService.track({
eventName: `message_channel.monitoring.sync_status.${snakeCase(
messageChannel.syncStatus,
)}`,

View File

@ -1,18 +1,18 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AnalyticsModule } from 'src/engine/core-modules/analytics/analytics.module';
import { AuditModule } from 'src/engine/core-modules/audit/audit.module';
import { BillingModule } from 'src/engine/core-modules/billing/billing.module';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
import { MessagingCommonModule } from 'src/modules/messaging/common/messaging-common.module';
import { MessagingMessageChannelSyncStatusMonitoringCronCommand } from 'src/modules/messaging/monitoring/crons/commands/messaging-message-channel-sync-status-monitoring.cron.command';
import { MessagingMessageChannelSyncStatusMonitoringCronJob } from 'src/modules/messaging/monitoring/crons/jobs/messaging-message-channel-sync-status-monitoring.cron.job';
import { MessagingTelemetryService } from 'src/modules/messaging/monitoring/services/messaging-telemetry.service';
import { MessagingMonitoringService } from 'src/modules/messaging/monitoring/services/messaging-monitoring.service';
@Module({
imports: [
AnalyticsModule,
AuditModule,
MessagingCommonModule,
BillingModule,
TypeOrmModule.forFeature([Workspace], 'core'),
@ -21,8 +21,8 @@ import { MessagingTelemetryService } from 'src/modules/messaging/monitoring/serv
providers: [
MessagingMessageChannelSyncStatusMonitoringCronCommand,
MessagingMessageChannelSyncStatusMonitoringCronJob,
MessagingTelemetryService,
MessagingMonitoringService,
],
exports: [MessagingTelemetryService],
exports: [MessagingMonitoringService],
})
export class MessagingMonitoringModule {}

View File

@ -0,0 +1,47 @@
import { Injectable } from '@nestjs/common';
import { AuditService } from 'src/engine/core-modules/audit/services/audit.service';
type MessagingMonitoringTrackInput = {
eventName: string;
workspaceId?: string;
userId?: string;
connectedAccountId?: string;
messageChannelId?: string;
message?: string;
};
@Injectable()
export class MessagingMonitoringService {
constructor(private readonly auditService: AuditService) {}
public async track({
eventName,
workspaceId,
userId,
connectedAccountId,
messageChannelId,
message,
}: MessagingMonitoringTrackInput): Promise<void> {
const _eventName = eventName;
const _workspaceId = workspaceId;
const _userId = userId;
const _connectedAccountId = connectedAccountId;
const _messageChannelId = messageChannelId;
const _message = message;
// TODO: replace once we have Prometheus
/*
await this.auditService
.createContext({
userId,
workspaceId,
})
.track(MONITORING_EVENT, {
eventName: `messaging.${eventName}`,
connectedAccountId,
messageChannelId,
message,
}); */
}
}

View File

@ -1,39 +0,0 @@
import { Injectable } from '@nestjs/common';
import { AnalyticsService } from 'src/engine/core-modules/analytics/services/analytics.service';
import { MONITORING_EVENT } from 'src/engine/core-modules/analytics/utils/events/track/monitoring/monitoring';
type MessagingTelemetryTrackInput = {
eventName: string;
workspaceId?: string;
userId?: string;
connectedAccountId?: string;
messageChannelId?: string;
message?: string;
};
@Injectable()
export class MessagingTelemetryService {
constructor(private readonly analyticsService: AnalyticsService) {}
public async track({
eventName,
workspaceId,
userId,
connectedAccountId,
messageChannelId,
message,
}: MessagingTelemetryTrackInput): Promise<void> {
await this.analyticsService
.createAnalyticsContext({
userId,
workspaceId,
})
.track(MONITORING_EVENT, {
eventName: `messaging.${eventName}`,
connectedAccountId,
messageChannelId,
message,
});
}
}