From 5c4d4b2c6335a9c242b0d05cc0fb60db4e26a4a0 Mon Sep 17 00:00:00 2001 From: Simon Larsen Date: Thu, 29 Aug 2024 11:25:43 +0100 Subject: [PATCH] refactor: Add exception span status code and name to ExceptionInstance model --- .../AnalyticsModels/ExceptionInstance.ts | 65 +++++++++ .../Exceptions/ExceptionExplorer.tsx | 3 + .../Components/Exceptions/ExceptionsTable.tsx | 45 ++++++ .../Components/Exceptions/OccuranceTable.tsx | 130 ++++++++++++++++++ Ingestor/API/OTelIngest.ts | 2 + 5 files changed, 245 insertions(+) diff --git a/Common/Models/AnalyticsModels/ExceptionInstance.ts b/Common/Models/AnalyticsModels/ExceptionInstance.ts index f0b9a0e876..6f4fef921e 100644 --- a/Common/Models/AnalyticsModels/ExceptionInstance.ts +++ b/Common/Models/AnalyticsModels/ExceptionInstance.ts @@ -5,6 +5,7 @@ import AnalyticsTableColumn from "../../Types/AnalyticsDatabase/TableColumn"; import TableColumnType from "../../Types/AnalyticsDatabase/TableColumnType"; import ObjectID from "../../Types/ObjectID"; import Permission from "../../Types/Permission"; +import { SpanStatus } from "./Span"; export default class ExceptionInstance extends AnalyticsBaseModel { public constructor() { @@ -206,6 +207,29 @@ export default class ExceptionInstance extends AnalyticsBaseModel { }, }), + new AnalyticsTableColumn({ + key: "spanStatusCode", + title: "Span Status Code", + description: "Span Status Code", + required: false, + type: TableColumnType.Number, + accessControl: { + read: [ + Permission.ProjectOwner, + Permission.ProjectAdmin, + Permission.ProjectMember, + Permission.ReadTelemetryException, + ], + create: [ + Permission.ProjectOwner, + Permission.ProjectAdmin, + Permission.ProjectMember, + Permission.CreateTelemetryException, + ], + update: [], + }, + }), + new AnalyticsTableColumn({ key: "escaped", title: "Exception Escaped", @@ -298,6 +322,29 @@ export default class ExceptionInstance extends AnalyticsBaseModel { }, }), + new AnalyticsTableColumn({ + key: "spanName", + title: "Span Name", + description: "Name of the span", + required: false, + type: TableColumnType.Text, + accessControl: { + read: [ + Permission.ProjectOwner, + Permission.ProjectAdmin, + Permission.ProjectMember, + Permission.ReadTelemetryServiceTraces, + ], + create: [ + Permission.ProjectOwner, + Permission.ProjectAdmin, + Permission.ProjectMember, + Permission.CreateTelemetryServiceTraces, + ], + update: [], + }, + }), + new AnalyticsTableColumn({ key: "attributes", title: "Attributes", @@ -422,4 +469,22 @@ export default class ExceptionInstance extends AnalyticsBaseModel { public set attributes(v: Record) { this.setColumnValue("attributes", v); } + + public get spanStatusCode(): SpanStatus | undefined { + return this.getColumnValue("spanStatusCode") as SpanStatus | undefined; + } + + public set spanStatusCode(v: SpanStatus | undefined) { + this.setColumnValue("spanStatusCode", v); + } + + + public get spanName(): string | undefined { + return this.getColumnValue("spanName") as string | undefined; + } + + public set spanName(v: string | undefined) { + this.setColumnValue("spanName", v); + } + } diff --git a/Dashboard/src/Components/Exceptions/ExceptionExplorer.tsx b/Dashboard/src/Components/Exceptions/ExceptionExplorer.tsx index 035de28c9c..f4377f6494 100644 --- a/Dashboard/src/Components/Exceptions/ExceptionExplorer.tsx +++ b/Dashboard/src/Components/Exceptions/ExceptionExplorer.tsx @@ -17,6 +17,7 @@ import IconProp from "Common/Types/Icon/IconProp"; import OneUptimeDate from "Common/Types/Date"; import User from "Common/UI/Utils/User"; import { ButtonStyleType } from "Common/UI/Components/Button/Button"; +import OccouranceTable from "./OccuranceTable"; export interface ComponentProps { telemetryExceptionId: ObjectID; @@ -188,6 +189,8 @@ const ExceptionExplorer: FunctionComponent = ( {/** Occurance Table */} + {telemetryException.fingerprint && } + {/** Archive / Unarchive Button Button */} {isResolved && ( diff --git a/Dashboard/src/Components/Exceptions/ExceptionsTable.tsx b/Dashboard/src/Components/Exceptions/ExceptionsTable.tsx index 04973c93a8..68749fd0fa 100644 --- a/Dashboard/src/Components/Exceptions/ExceptionsTable.tsx +++ b/Dashboard/src/Components/Exceptions/ExceptionsTable.tsx @@ -11,6 +11,7 @@ import TelemetryExceptionElement from "./ExceptionElement"; import RouteMap, { RouteUtil } from "../../Utils/RouteMap"; import Route from "Common/Types/API/Route"; import PageMap from "../../Utils/PageMap"; +import User from "Common/Models/DatabaseModels/User"; export interface ComponentProps { telemetryServiceId?: ObjectID | undefined; @@ -100,6 +101,28 @@ const TelemetryExceptionTable: FunctionComponent = ( title: "Resolved", type: FieldType.Boolean, }, + { + field: { + markedAsResolvedAt: true, + }, + title: "Marked As Resolved At", + type: FieldType.Date, + }, + { + field: { + markedAsResolvedByUser: true, + }, + title: "Marked As Resolved At", + type: FieldType.EntityArray, + filterEntityType: User, + filterQuery: { + projectId: DashboardNavigation.getProjectId()!, + }, + filterDropdownField: { + label: "name", + value: "_id", + }, + }, { field: { isArchived: true, @@ -107,6 +130,28 @@ const TelemetryExceptionTable: FunctionComponent = ( title: "Archived", type: FieldType.Boolean, }, + { + field: { + markedAsArchivedAt: true, + }, + title: "Marked As Archived At", + type: FieldType.Date, + }, + { + field: { + markedAsArchivedByUser: true, + }, + title: "Marked As Archived At", + type: FieldType.EntityArray, + filterEntityType: User, + filterQuery: { + projectId: DashboardNavigation.getProjectId()!, + }, + filterDropdownField: { + label: "name", + value: "_id", + }, + }, ]} selectMoreFields={{ isResolved: true, diff --git a/Dashboard/src/Components/Exceptions/OccuranceTable.tsx b/Dashboard/src/Components/Exceptions/OccuranceTable.tsx index e69de29bb2..b9239afeba 100644 --- a/Dashboard/src/Components/Exceptions/OccuranceTable.tsx +++ b/Dashboard/src/Components/Exceptions/OccuranceTable.tsx @@ -0,0 +1,130 @@ +import SpanStatusElement from "../Span/SpanStatusElement"; +import DashboardNavigation from "../../Utils/Navigation"; +import SortOrder from "Common/Types/BaseDatabase/SortOrder"; +import ExceptionInstance from "Common/Models/AnalyticsModels/ExceptionInstance"; +import AnalyticsModelTable from "Common/UI/Components/ModelTable/AnalyticsModelTable"; +import FieldType from "Common/UI/Components/Types/FieldType"; +import React, { + Fragment, + FunctionComponent, + ReactElement, +} from "react"; + +export interface ComponentProps { + exceptionFingerprint: string; +} + +const OccouranceTable: FunctionComponent = ( + props: ComponentProps, +): ReactElement => { + + + return ( + +
+ + modelType={ExceptionInstance} + id="traces-table" + isDeleteable={false} + isEditable={false} + isCreateable={false} + singularName="Exception" + pluralName="Exceptions" + name="Exception" + isViewable={false} + cardProps={ + { + title: "Exception Occurrences", + description: + "View all the traces that are related to this exception.", + } + } + query={{ + projectId: DashboardNavigation.getProjectId()!, + fingerprint: props.exceptionFingerprint, + }} + showViewIdButton={true} + noItemsMessage={ + "No exception found." + } + showRefreshButton={true} + sortBy="time" + sortOrder={SortOrder.Descending} + filters={[ + { + field: { + traceId: true, + }, + type: FieldType.Text, + title: "Trace ID", + }, + { + field: { + spanId: true, + }, + type: FieldType.Text, + title: "Span ID", + }, + { + field: { + time: true, + }, + type: FieldType.DateTime, + title: "Time of Occurrence", + }, + { + field: { + spanName: true, + }, + type: FieldType.Text, + title: "Span Name", + } + ]} + columns={[ + { + field: { + spanId: true, + }, + title: "Span ID", + type: FieldType.Element, + getElement: (exceptionInstance: ExceptionInstance): ReactElement => { + return ( + + + + ); + }, + }, + { + field: { + traceId: true, + }, + title: "Trace ID", + type: FieldType.Text, + }, + { + field: { + spanName: true, + }, + title: "Span Name", + type: FieldType.Text, + }, + { + field: { + time: true, + }, + title: "Time of Occurrence", + type: FieldType.DateTime, + } + ]} + /> +
+
+ ); +}; + +export default OccouranceTable; diff --git a/Ingestor/API/OTelIngest.ts b/Ingestor/API/OTelIngest.ts index ec65088e97..06b5234c8b 100644 --- a/Ingestor/API/OTelIngest.ts +++ b/Ingestor/API/OTelIngest.ts @@ -308,6 +308,8 @@ router.post( exception.traceId = dbSpan.traceId; exception.time = eventTime; exception.timeUnixNano = eventTimeUnixNano; + exception.spanStatusCode = dbSpan.statusCode; + exception.spanName = dbSpan.name; exception.message = (eventAttributes["exception.message"] as string) || ""; exception.stackTrace =