mirror of
https://github.com/OneUptime/oneuptime
synced 2024-11-21 14:49:07 +00:00
refactor: Add TelemetryExceptionStatusService to handle telemetry exception status in the database
This commit is contained in:
parent
a6a5f189c3
commit
2f3dbebe9a
@ -6,12 +6,13 @@ import TableColumnType from "../../Types/AnalyticsDatabase/TableColumnType";
|
||||
import ObjectID from "../../Types/ObjectID";
|
||||
import Permission from "../../Types/Permission";
|
||||
|
||||
export default class Exception extends AnalyticsBaseModel {
|
||||
export default class ExceptionInstance extends AnalyticsBaseModel {
|
||||
public constructor() {
|
||||
super({
|
||||
tableName: "ExceptionTelemetry",
|
||||
tableName: "ExceptionInstanceTelemetry",
|
||||
tableEngine: AnalyticsTableEngine.MergeTree,
|
||||
singularName: "Exception",
|
||||
pluralName: "Exceptions",
|
||||
enableRealtimeEventsOn: {
|
||||
create: true,
|
||||
},
|
@ -4,7 +4,7 @@ import Metric from "./Metric";
|
||||
import MonitorMetricsByMinute from "./MonitorMetricsByMinute";
|
||||
import Span from "./Span";
|
||||
import TelemetryAttribute from "./TelemetryAttribute";
|
||||
import Exception from "./Exception";
|
||||
import ExceptionInstance from "./ExceptionInstance";
|
||||
|
||||
const AnalyticsModels: Array<typeof AnalyticsBaseModel> = [
|
||||
Log,
|
||||
@ -12,7 +12,7 @@ const AnalyticsModels: Array<typeof AnalyticsBaseModel> = [
|
||||
Metric,
|
||||
MonitorMetricsByMinute,
|
||||
TelemetryAttribute,
|
||||
Exception,
|
||||
ExceptionInstance,
|
||||
];
|
||||
|
||||
export default AnalyticsModels;
|
||||
|
@ -135,7 +135,7 @@ import UserTwoFactorAuth from "./UserTwoFactorAuth";
|
||||
|
||||
import TelemetryIngestionKey from "./TelemetryIngestionKey";
|
||||
|
||||
import TelemetryExceptionStatus from "./TelemetryExceptionStatus";
|
||||
import TelemetryException from "./TelemetryException";
|
||||
|
||||
export default [
|
||||
User,
|
||||
@ -292,5 +292,5 @@ export default [
|
||||
|
||||
TelemetryIngestionKey,
|
||||
|
||||
TelemetryExceptionStatus
|
||||
TelemetryException,
|
||||
];
|
||||
|
@ -53,17 +53,17 @@ import TelemetryService from "./TelemetryService";
|
||||
})
|
||||
@CrudApiEndpoint(new Route("/telemetry-exception-status"))
|
||||
@TableMetadata({
|
||||
tableName: "TelemetryExceptionStatus",
|
||||
singularName: "TelemetryExceptionStatus",
|
||||
tableName: "TelemetryException",
|
||||
singularName: "TelemetryException",
|
||||
pluralName: "TelemetryExceptionsStatus",
|
||||
icon: IconProp.Error,
|
||||
tableDescription:
|
||||
"List of all Telemetry Exceptions created for the telemetry service for this OneUptime project and it's status.",
|
||||
})
|
||||
@Entity({
|
||||
name: "TelemetryExceptionStatus",
|
||||
name: "TelemetryException",
|
||||
})
|
||||
export default class TelemetryExceptionStatus extends DatabaseBaseModel {
|
||||
export default class TelemetryException extends DatabaseBaseModel {
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
@ -128,7 +128,6 @@ export default class TelemetryExceptionStatus extends DatabaseBaseModel {
|
||||
})
|
||||
public projectId?: ObjectID = undefined;
|
||||
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
@ -233,7 +232,6 @@ export default class TelemetryExceptionStatus extends DatabaseBaseModel {
|
||||
})
|
||||
public message?: string = undefined;
|
||||
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
@ -257,7 +255,8 @@ export default class TelemetryExceptionStatus extends DatabaseBaseModel {
|
||||
type: TableColumnType.LongText,
|
||||
canReadOnRelationQuery: false,
|
||||
title: "Stack Trace",
|
||||
description: "Stack trace of the exception that was thrown by the telemetry service",
|
||||
description:
|
||||
"Stack trace of the exception that was thrown by the telemetry service",
|
||||
})
|
||||
@Column({
|
||||
nullable: true,
|
||||
@ -265,7 +264,6 @@ export default class TelemetryExceptionStatus extends DatabaseBaseModel {
|
||||
})
|
||||
public stackTrace?: string = undefined;
|
||||
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
@ -289,7 +287,8 @@ export default class TelemetryExceptionStatus extends DatabaseBaseModel {
|
||||
type: TableColumnType.LongText,
|
||||
canReadOnRelationQuery: false,
|
||||
title: "Exception Type",
|
||||
description: "Type of the exception that was thrown by the telemetry service",
|
||||
description:
|
||||
"Type of the exception that was thrown by the telemetry service",
|
||||
})
|
||||
@Column({
|
||||
nullable: true,
|
||||
@ -297,6 +296,7 @@ export default class TelemetryExceptionStatus extends DatabaseBaseModel {
|
||||
})
|
||||
public exceptionType?: string = undefined;
|
||||
|
||||
@Index()
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
@ -320,14 +320,15 @@ export default class TelemetryExceptionStatus extends DatabaseBaseModel {
|
||||
type: TableColumnType.ShortText,
|
||||
canReadOnRelationQuery: false,
|
||||
title: "Finger Print",
|
||||
description: "Finger print of the exception that was thrown by the telemetry service",
|
||||
description:
|
||||
"Finger print of the exception that was thrown by the telemetry service",
|
||||
})
|
||||
@Column({
|
||||
nullable: true,
|
||||
type: ColumnType.ShortText,
|
||||
length: ColumnLength.ShortText,
|
||||
})
|
||||
public fingerPrint?: string = undefined;
|
||||
public fingerprint?: string = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
@ -393,14 +394,22 @@ export default class TelemetryExceptionStatus extends DatabaseBaseModel {
|
||||
public createdByUserId?: ObjectID = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CreateTelemetryException,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadTelemetryException,
|
||||
],
|
||||
update: [],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.EditTelemetryException,
|
||||
],
|
||||
})
|
||||
@TableColumn({
|
||||
manyToOneRelationColumn: "deletedByUserId",
|
||||
@ -425,14 +434,22 @@ export default class TelemetryExceptionStatus extends DatabaseBaseModel {
|
||||
public deletedByUser?: User = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CreateTelemetryException,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadTelemetryException,
|
||||
],
|
||||
update: [],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.EditTelemetryException,
|
||||
],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
@ -451,15 +468,19 @@ export default class TelemetryExceptionStatus extends DatabaseBaseModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CreateProjectTeam,
|
||||
Permission.InviteProjectTeamMembers,
|
||||
Permission.CreateTelemetryException,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ReadProjectTeam,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadTelemetryException,
|
||||
],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.EditTelemetryException,
|
||||
],
|
||||
update: [Permission.CurrentUser],
|
||||
})
|
||||
@TableColumn({
|
||||
required: false,
|
||||
@ -474,21 +495,23 @@ export default class TelemetryExceptionStatus extends DatabaseBaseModel {
|
||||
})
|
||||
public markedAsResolvedAt?: Date = undefined;
|
||||
|
||||
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CreateProjectTeam,
|
||||
Permission.InviteProjectTeamMembers,
|
||||
Permission.CreateTelemetryException,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ReadProjectTeam,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadTelemetryException,
|
||||
],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.EditTelemetryException,
|
||||
],
|
||||
update: [Permission.CurrentUser],
|
||||
})
|
||||
@TableColumn({
|
||||
required: false,
|
||||
@ -503,20 +526,23 @@ export default class TelemetryExceptionStatus extends DatabaseBaseModel {
|
||||
})
|
||||
public markedAsMutedAt?: Date = undefined;
|
||||
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CreateProjectTeam,
|
||||
Permission.InviteProjectTeamMembers,
|
||||
Permission.CreateTelemetryException,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ReadProjectTeam,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadTelemetryException,
|
||||
],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.EditTelemetryException,
|
||||
],
|
||||
update: [Permission.CurrentUser],
|
||||
})
|
||||
@TableColumn({
|
||||
required: false,
|
||||
@ -535,15 +561,19 @@ export default class TelemetryExceptionStatus extends DatabaseBaseModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CreateProjectTeam,
|
||||
Permission.InviteProjectTeamMembers,
|
||||
Permission.CreateTelemetryException,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ReadProjectTeam,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadTelemetryException,
|
||||
],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.EditTelemetryException,
|
||||
],
|
||||
update: [Permission.CurrentUser],
|
||||
})
|
||||
@TableColumn({
|
||||
required: false,
|
||||
@ -558,24 +588,30 @@ export default class TelemetryExceptionStatus extends DatabaseBaseModel {
|
||||
})
|
||||
public lastSeenAt?: Date = undefined;
|
||||
|
||||
|
||||
// assign to.
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CreateTelemetryException,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadTelemetryException,
|
||||
],
|
||||
update: [],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.EditTelemetryException,
|
||||
],
|
||||
})
|
||||
@TableColumn({
|
||||
manyToOneRelationColumn: "assignToUserId",
|
||||
type: TableColumnType.Entity,
|
||||
title: "Assign to User",
|
||||
description:
|
||||
"Relation to User who this exception is assigned to.",
|
||||
description: "Relation to User who this exception is assigned to.",
|
||||
})
|
||||
@ManyToOne(
|
||||
() => {
|
||||
@ -593,20 +629,27 @@ export default class TelemetryExceptionStatus extends DatabaseBaseModel {
|
||||
public assignToUser?: User = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CreateTelemetryException,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadTelemetryException,
|
||||
],
|
||||
update: [],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.EditTelemetryException,
|
||||
],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
title: "Assign to User ID",
|
||||
description:
|
||||
"User ID who this exception is assigned to.",
|
||||
description: "User ID who this exception is assigned to.",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
@ -615,27 +658,32 @@ export default class TelemetryExceptionStatus extends DatabaseBaseModel {
|
||||
})
|
||||
public assignToUserId?: ObjectID = undefined;
|
||||
|
||||
|
||||
|
||||
// assign to team.
|
||||
|
||||
// assign to.
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CreateTelemetryException,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadTelemetryException,
|
||||
],
|
||||
update: [],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.EditTelemetryException,
|
||||
],
|
||||
})
|
||||
@TableColumn({
|
||||
manyToOneRelationColumn: "assignToTeamId",
|
||||
type: TableColumnType.Entity,
|
||||
title: "Assign to Team",
|
||||
description:
|
||||
"Relation to Team who this exception is assigned to.",
|
||||
description: "Relation to Team who this exception is assigned to.",
|
||||
})
|
||||
@ManyToOne(
|
||||
() => {
|
||||
@ -653,20 +701,27 @@ export default class TelemetryExceptionStatus extends DatabaseBaseModel {
|
||||
public assignToTeam?: Team = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CreateTelemetryException,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadTelemetryException,
|
||||
],
|
||||
update: [],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.EditTelemetryException,
|
||||
],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
title: "Assign to Team ID",
|
||||
description:
|
||||
"Team ID who this exception is assigned to.",
|
||||
description: "Team ID who this exception is assigned to.",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
@ -675,18 +730,25 @@ export default class TelemetryExceptionStatus extends DatabaseBaseModel {
|
||||
})
|
||||
public assignToTeamId?: ObjectID = undefined;
|
||||
|
||||
|
||||
// mark as resolved by.
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CreateTelemetryException,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadTelemetryException,
|
||||
],
|
||||
update: [],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.EditTelemetryException,
|
||||
],
|
||||
})
|
||||
@TableColumn({
|
||||
manyToOneRelationColumn: "markedAsResolvedByUserId",
|
||||
@ -711,20 +773,27 @@ export default class TelemetryExceptionStatus extends DatabaseBaseModel {
|
||||
public markedAsResolvedByUser?: User = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CreateTelemetryException,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadTelemetryException,
|
||||
],
|
||||
update: [],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.EditTelemetryException,
|
||||
],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
title: "Marked as Resolved By User ID",
|
||||
description:
|
||||
"User ID who marked this exception as resolved.",
|
||||
description: "User ID who marked this exception as resolved.",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
@ -733,26 +802,31 @@ export default class TelemetryExceptionStatus extends DatabaseBaseModel {
|
||||
})
|
||||
public markedAsResolvedByUserId?: ObjectID = undefined;
|
||||
|
||||
|
||||
|
||||
// Mark as muted by.
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CreateTelemetryException,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadTelemetryException,
|
||||
],
|
||||
update: [],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.EditTelemetryException,
|
||||
],
|
||||
})
|
||||
@TableColumn({
|
||||
manyToOneRelationColumn: "markedAsMutedByUserId",
|
||||
type: TableColumnType.Entity,
|
||||
title: "Mark as Muted By User",
|
||||
description:
|
||||
"Mark as muted by User",
|
||||
description: "Mark as muted by User",
|
||||
})
|
||||
@ManyToOne(
|
||||
() => {
|
||||
@ -770,20 +844,27 @@ export default class TelemetryExceptionStatus extends DatabaseBaseModel {
|
||||
public markedAsMutedByUser?: User = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CreateTelemetryException,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadTelemetryException,
|
||||
],
|
||||
update: [],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.EditTelemetryException,
|
||||
],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
title: "Mark as Muted By User ID",
|
||||
description:
|
||||
"User ID who marked this exception as muted.",
|
||||
description: "User ID who marked this exception as muted.",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
@ -791,8 +872,4 @@ export default class TelemetryExceptionStatus extends DatabaseBaseModel {
|
||||
transformer: ObjectID.getDatabaseTransformer(),
|
||||
})
|
||||
public markedAsMutedByUserId?: ObjectID = undefined;
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class MigrationName1724607603707 implements MigrationInterface {
|
||||
public name = 'MigrationName1724607603707'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`CREATE TABLE "TelemetryExceptionStatus" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP, "version" integer NOT NULL, "projectId" uuid NOT NULL, "telemetryServiceId" uuid NOT NULL, "message" character varying, "stackTrace" character varying, "exceptionType" character varying, "fingerPrint" character varying(100), "createdByUserId" uuid, "deletedByUserId" uuid, "markedAsResolvedAt" TIMESTAMP WITH TIME ZONE, "markedAsMutedAt" TIMESTAMP WITH TIME ZONE, "firstSeenAt" TIMESTAMP WITH TIME ZONE, "lastSeenAt" TIMESTAMP WITH TIME ZONE, "assignToUserId" uuid, "assignToTeamId" uuid, "markedAsResolvedByUserId" uuid, "markedAsMutedByUserId" uuid, CONSTRAINT "PK_8db287c0fc7516e22d53876137c" PRIMARY KEY ("_id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_7c02d07bf73bfdac7301a6c86d" ON "TelemetryExceptionStatus" ("projectId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_0f66442452b5a89efa085ede0f" ON "TelemetryExceptionStatus" ("telemetryServiceId") `);
|
||||
await queryRunner.query(`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`);
|
||||
await queryRunner.query(`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`);
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryExceptionStatus" ADD CONSTRAINT "FK_7c02d07bf73bfdac7301a6c86d5" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryExceptionStatus" ADD CONSTRAINT "FK_0f66442452b5a89efa085ede0fd" FOREIGN KEY ("telemetryServiceId") REFERENCES "TelemetryService"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryExceptionStatus" ADD CONSTRAINT "FK_fe9e43b2cf2278894f9fe67c92f" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryExceptionStatus" ADD CONSTRAINT "FK_3b402ffb6fe47992c38f4cd5e7a" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryExceptionStatus" ADD CONSTRAINT "FK_88a1d97d74c54cd80b384f2a911" FOREIGN KEY ("assignToUserId") REFERENCES "User"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryExceptionStatus" ADD CONSTRAINT "FK_1c8cc9368c92f60cb093af277f8" FOREIGN KEY ("assignToTeamId") REFERENCES "Team"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryExceptionStatus" ADD CONSTRAINT "FK_fe156e1dce6bdae3f349d33e293" FOREIGN KEY ("markedAsResolvedByUserId") REFERENCES "User"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryExceptionStatus" ADD CONSTRAINT "FK_9d7647bf6d537f5afbd00ef4a8b" FOREIGN KEY ("markedAsMutedByUserId") REFERENCES "User"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryExceptionStatus" DROP CONSTRAINT "FK_9d7647bf6d537f5afbd00ef4a8b"`);
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryExceptionStatus" DROP CONSTRAINT "FK_fe156e1dce6bdae3f349d33e293"`);
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryExceptionStatus" DROP CONSTRAINT "FK_1c8cc9368c92f60cb093af277f8"`);
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryExceptionStatus" DROP CONSTRAINT "FK_88a1d97d74c54cd80b384f2a911"`);
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryExceptionStatus" DROP CONSTRAINT "FK_3b402ffb6fe47992c38f4cd5e7a"`);
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryExceptionStatus" DROP CONSTRAINT "FK_fe9e43b2cf2278894f9fe67c92f"`);
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryExceptionStatus" DROP CONSTRAINT "FK_0f66442452b5a89efa085ede0fd"`);
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryExceptionStatus" DROP CONSTRAINT "FK_7c02d07bf73bfdac7301a6c86d5"`);
|
||||
await queryRunner.query(`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`);
|
||||
await queryRunner.query(`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`);
|
||||
await queryRunner.query(`DROP INDEX "public"."IDX_0f66442452b5a89efa085ede0f"`);
|
||||
await queryRunner.query(`DROP INDEX "public"."IDX_7c02d07bf73bfdac7301a6c86d"`);
|
||||
await queryRunner.query(`DROP TABLE "TelemetryExceptionStatus"`);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class MigrationName1724610006927 implements MigrationInterface {
|
||||
public name = "MigrationName1724610006927";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`CREATE TABLE "TelemetryException" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP, "version" integer NOT NULL, "projectId" uuid NOT NULL, "telemetryServiceId" uuid NOT NULL, "message" character varying, "stackTrace" character varying, "exceptionType" character varying, "fingerprint" character varying(100), "createdByUserId" uuid, "deletedByUserId" uuid, "markedAsResolvedAt" TIMESTAMP WITH TIME ZONE, "markedAsMutedAt" TIMESTAMP WITH TIME ZONE, "firstSeenAt" TIMESTAMP WITH TIME ZONE, "lastSeenAt" TIMESTAMP WITH TIME ZONE, "assignToUserId" uuid, "assignToTeamId" uuid, "markedAsResolvedByUserId" uuid, "markedAsMutedByUserId" uuid, CONSTRAINT "PK_53717afe73c3e72c11713e5e25f" PRIMARY KEY ("_id"))`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_3310c3a807a7e8bca9d1bd8e0e" ON "TelemetryException" ("projectId") `,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_6470c69cb5f53c5899c0483df5" ON "TelemetryException" ("telemetryServiceId") `,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_e270eb229cd583c653c2176db9" ON "TelemetryException" ("fingerprint") `,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "TelemetryException" ADD CONSTRAINT "FK_3310c3a807a7e8bca9d1bd8e0eb" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "TelemetryException" ADD CONSTRAINT "FK_6470c69cb5f53c5899c0483df5f" FOREIGN KEY ("telemetryServiceId") REFERENCES "TelemetryService"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "TelemetryException" ADD CONSTRAINT "FK_d2e1b4f5dcaebbf14ed6cbd303d" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "TelemetryException" ADD CONSTRAINT "FK_757f473e68b584bc42fcfbd9373" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "TelemetryException" ADD CONSTRAINT "FK_f7ec3f51dae2b4963cfb8fe5c46" FOREIGN KEY ("assignToUserId") REFERENCES "User"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "TelemetryException" ADD CONSTRAINT "FK_63221e8bd973ab71a49598d6c88" FOREIGN KEY ("assignToTeamId") REFERENCES "Team"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "TelemetryException" ADD CONSTRAINT "FK_10c7733499d5afa9b857f4a00c5" FOREIGN KEY ("markedAsResolvedByUserId") REFERENCES "User"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "TelemetryException" ADD CONSTRAINT "FK_199e3572d19b75e59f2082251f8" FOREIGN KEY ("markedAsMutedByUserId") REFERENCES "User"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "TelemetryException" DROP CONSTRAINT "FK_199e3572d19b75e59f2082251f8"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "TelemetryException" DROP CONSTRAINT "FK_10c7733499d5afa9b857f4a00c5"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "TelemetryException" DROP CONSTRAINT "FK_63221e8bd973ab71a49598d6c88"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "TelemetryException" DROP CONSTRAINT "FK_f7ec3f51dae2b4963cfb8fe5c46"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "TelemetryException" DROP CONSTRAINT "FK_757f473e68b584bc42fcfbd9373"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "TelemetryException" DROP CONSTRAINT "FK_d2e1b4f5dcaebbf14ed6cbd303d"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "TelemetryException" DROP CONSTRAINT "FK_6470c69cb5f53c5899c0483df5f"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "TelemetryException" DROP CONSTRAINT "FK_3310c3a807a7e8bca9d1bd8e0eb"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."IDX_e270eb229cd583c653c2176db9"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."IDX_6470c69cb5f53c5899c0483df5"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."IDX_3310c3a807a7e8bca9d1bd8e0e"`,
|
||||
);
|
||||
await queryRunner.query(`DROP TABLE "TelemetryException"`);
|
||||
}
|
||||
}
|
@ -41,6 +41,7 @@ import { MigrationName1722892318363 } from "./1722892318363-MigrationName";
|
||||
import { MigrationName1723825511054 } from "./1723825511054-MigrationName";
|
||||
import { MigrationName1723828588502 } from "./1723828588502-MigrationName";
|
||||
import { MigrationName1724078044172 } from "./1724078044172-MigrationName";
|
||||
import { MigrationName1724610006927 } from "./1724610006927-MigrationName";
|
||||
|
||||
export default [
|
||||
InitialMigration,
|
||||
@ -86,5 +87,6 @@ export default [
|
||||
MigrationName1723825511054,
|
||||
MigrationName1723828588502,
|
||||
MigrationName1724078044172,
|
||||
MigrationName1720812937067
|
||||
MigrationName1720812937067,
|
||||
MigrationName1724610006927,
|
||||
];
|
||||
|
@ -130,6 +130,7 @@ import AnalyticsBaseModel from "Common/Models/AnalyticsModels/AnalyticsBaseModel
|
||||
import CopilotPullRequestService from "./CopilotPullRequestService";
|
||||
import ServiceCatalogDependencyService from "./ServiceCatalogDependencyService";
|
||||
import TelemetryAttributeService from "./TelemetryAttributeService";
|
||||
import TelemetryExceptionStatusService from "./TelemetryExceptionStatusService";
|
||||
|
||||
const services: Array<BaseService> = [
|
||||
AcmeCertificateService,
|
||||
@ -271,6 +272,8 @@ const services: Array<BaseService> = [
|
||||
CopilotActionService,
|
||||
ServiceCopilotCodeRepositoryService,
|
||||
CopilotPullRequestService,
|
||||
|
||||
TelemetryExceptionStatusService,
|
||||
];
|
||||
|
||||
export const AnalyticsServices: Array<
|
||||
|
10
Common/Server/Services/TelemetryExceptionStatusService.ts
Normal file
10
Common/Server/Services/TelemetryExceptionStatusService.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import DatabaseService from "./DatabaseService";
|
||||
import Model from "Common/Models/DatabaseModels/TelemetryException";
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor() {
|
||||
super(Model);
|
||||
}
|
||||
}
|
||||
|
||||
export default new Service();
|
@ -13,6 +13,10 @@ export default class OneUptimeDate {
|
||||
return seconds * 1000 * 1000 * 1000;
|
||||
}
|
||||
|
||||
public static now(): Date {
|
||||
return this.getCurrentDate();
|
||||
}
|
||||
|
||||
public static getDateFromYYYYMMDD(
|
||||
year: string,
|
||||
month: string,
|
||||
|
@ -8,5 +8,4 @@ export default class Crypto {
|
||||
public static getSha256Hash(text: string): string {
|
||||
return CryptoJS.SHA256(text).toString();
|
||||
}
|
||||
|
||||
}
|
@ -7,7 +7,7 @@ import OTelIngestService, {
|
||||
TelemetryServiceDataIngested,
|
||||
} from "../Service/OTelIngest";
|
||||
import OneUptimeDate from "Common/Types/Date";
|
||||
import BadRequestException from "Common/Types/Exception/BadRequestException";
|
||||
import BadRequestException from "Common/Types/ExceptionInstance/BadRequestException";
|
||||
import { JSONArray, JSONObject } from "Common/Types/JSON";
|
||||
import JSONFunctions from "Common/Types/JSONFunctions";
|
||||
import ProductType from "Common/Types/MeteredPlan/ProductType";
|
||||
@ -36,7 +36,7 @@ import protobuf from "protobufjs";
|
||||
import Dictionary from "Common/Types/Dictionary";
|
||||
import ObjectID from "Common/Types/ObjectID";
|
||||
import LogSeverity from "Common/Types/Log/LogSeverity";
|
||||
import Exception from "Common/Models/AnalyticsModels/Exception";
|
||||
import ExceptionInstance from "Common/Models/AnalyticsModels/ExceptionInstance";
|
||||
import ExceptionUtil from "../Utils/Exception";
|
||||
|
||||
// Load proto file for OTel
|
||||
@ -127,7 +127,7 @@ router.post(
|
||||
const resourceSpans: JSONArray = traceData["resourceSpans"] as JSONArray;
|
||||
|
||||
const dbSpans: Array<Span> = [];
|
||||
const dbExceptions: Array<Exception> = [];
|
||||
const dbExceptions: Array<ExceptionInstance> = [];
|
||||
|
||||
let attributes: string[] = [];
|
||||
|
||||
@ -301,7 +301,7 @@ router.post(
|
||||
|
||||
if (event["name"] === SpanEventType.Exception) {
|
||||
// add exception object.
|
||||
const exception: Exception = new Exception();
|
||||
const exception: ExceptionInstance = new ExceptionInstance();
|
||||
exception.projectId = dbSpan.projectId;
|
||||
exception.serviceId = dbSpan.serviceId;
|
||||
exception.spanId = dbSpan.spanId;
|
||||
@ -314,10 +314,15 @@ router.post(
|
||||
] as string;
|
||||
exception.exceptionType = eventAttributes["type"] as string;
|
||||
exception.escaped = eventAttributes["escaped"] as boolean;
|
||||
exception.fingerprint = ExceptionUtil.getFingerprint(exception);
|
||||
exception.fingerprint =
|
||||
ExceptionUtil.getFingerprint(exception);
|
||||
|
||||
// add exception to dbExceptions
|
||||
dbExceptions.push(exception);
|
||||
|
||||
// save exception status
|
||||
// maybe this can be improved instead of doing a lot of db calls.
|
||||
await ExceptionUtil.saveOrUpdateTelemetryException(exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -360,7 +365,12 @@ router.post(
|
||||
},
|
||||
});
|
||||
|
||||
await ExceptionService;
|
||||
await ExceptionService.createMany({
|
||||
items: dbExceptions,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
OTelIngestService.indexAttributes({
|
||||
attributes: ArrayUtil.removeDuplicates(attributes),
|
||||
|
@ -1,16 +1,112 @@
|
||||
import Exception from 'Common/Models/AnalyticsModels/Exception';
|
||||
import Crypto from 'Common/Utils/Crypto';
|
||||
import ExceptionInstance from "Common/Models/AnalyticsModels/ExceptionInstance";
|
||||
import TelemetryException from "Common/Models/DatabaseModels/TelemetryException";
|
||||
import TelemetryExceptionStatusService from "Common/Server/Services/TelemetryExceptionStatusService";
|
||||
import OneUptimeDate from "Common/Types/Date";
|
||||
import BadDataException from "Common/Types/Exception/BadDataException";
|
||||
import Crypto from "Common/Utils/Crypto";
|
||||
|
||||
export default class ExceptionUtil {
|
||||
public static getFingerprint(exception: Exception): string {
|
||||
public static getFingerprint(exception: ExceptionInstance): string {
|
||||
const message: string = exception.message || "";
|
||||
const stackTrace: string = exception.stackTrace || "";
|
||||
const type: string = exception.exceptionType || "";
|
||||
const projectId: string = exception.projectId?.toString() || "";
|
||||
const serviceId: string = exception.serviceId?.toString() || "";
|
||||
|
||||
const hash: string = Crypto.getSha256Hash(projectId + serviceId + message + stackTrace + type);
|
||||
const hash: string = Crypto.getSha256Hash(
|
||||
projectId + serviceId + message + stackTrace + type,
|
||||
);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
public static async saveOrUpdateTelemetryException(
|
||||
exception: ExceptionInstance,
|
||||
): Promise<void> {
|
||||
// Exception is saved to main database as well (not just analytics db), so users can assgin it, resolve it, etc.
|
||||
|
||||
if (!exception.fingerprint) {
|
||||
throw new BadDataException(
|
||||
"Fingerprint is required to save exception status",
|
||||
);
|
||||
}
|
||||
|
||||
if (!exception.projectId) {
|
||||
throw new BadDataException(
|
||||
"Project ID is required to save exception status",
|
||||
);
|
||||
}
|
||||
|
||||
if (!exception.serviceId) {
|
||||
throw new BadDataException(
|
||||
"Service ID is required to save exception status",
|
||||
);
|
||||
}
|
||||
|
||||
const fingerprint: string = exception.fingerprint;
|
||||
|
||||
// check if the exception with the same fingerprint already exists in the database
|
||||
|
||||
const existingExceptionStatus: TelemetryException | null =
|
||||
await TelemetryExceptionStatusService.findOneBy({
|
||||
query: {
|
||||
fingerprint: fingerprint,
|
||||
projectId: exception.projectId,
|
||||
telemetryServiceId: exception.serviceId,
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (existingExceptionStatus) {
|
||||
// then update last seen as and unmark as resolved/muted
|
||||
await TelemetryExceptionStatusService.updateOneBy({
|
||||
query: {
|
||||
_id: existingExceptionStatus._id,
|
||||
},
|
||||
data: {
|
||||
lastSeenAt: OneUptimeDate.now(),
|
||||
markedAsResolvedByUserId: null,
|
||||
markedAsResolvedAt: null, // unmark as resolved if it was marked as resolved
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (!existingExceptionStatus) {
|
||||
// Create a new exception status if it doesn't exist
|
||||
const newExceptionStatus: TelemetryException = new TelemetryException();
|
||||
newExceptionStatus.fingerprint = exception.fingerprint;
|
||||
newExceptionStatus.projectId = exception.projectId;
|
||||
newExceptionStatus.telemetryServiceId = exception.serviceId;
|
||||
newExceptionStatus.lastSeenAt = OneUptimeDate.now();
|
||||
newExceptionStatus.firstSeenAt = OneUptimeDate.now();
|
||||
|
||||
if (exception.exceptionType) {
|
||||
newExceptionStatus.exceptionType = exception.exceptionType;
|
||||
}
|
||||
|
||||
if (exception.message) {
|
||||
newExceptionStatus.message = exception.message;
|
||||
}
|
||||
|
||||
if (exception.stackTrace) {
|
||||
newExceptionStatus.stackTrace = exception.stackTrace;
|
||||
}
|
||||
|
||||
// Save the new exception status to the database
|
||||
await TelemetryExceptionStatusService.create({
|
||||
data: newExceptionStatus,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user