@oneuptime/common 11.3.9 → 11.3.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Models/AnalyticsModels/MutableMetric.ts +333 -0
- package/Server/Services/AlertService.ts +167 -206
- package/Server/Services/AlertStateTimelineService.ts +121 -1
- package/Server/Services/AnalyticsDatabaseService.ts +19 -23
- package/Server/Services/IncidentService.ts +179 -252
- package/Server/Services/IncidentStateTimelineService.ts +120 -1
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/MetricAggregationService.ts +73 -3
- package/Server/Services/MetricService.ts +228 -0
- package/Server/Services/MutableMetricService.ts +275 -0
- package/Server/Services/TelemetryAttributeService.ts +183 -1
- package/Server/Utils/AnalyticsDatabase/ClusterConfig.ts +2 -0
- package/Server/Utils/AnalyticsDatabase/Statement.ts +2 -0
- package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +143 -0
- package/Tests/Types/Monitor/MonitorStepEntityScope.test.ts +0 -56
- package/Types/AnalyticsDatabase/AnalyticsTableEngine.ts +1 -0
- package/Types/AnalyticsDatabase/AnalyticsTableName.ts +1 -0
- package/Types/Monitor/MonitorStepMetricMonitor.ts +0 -27
- package/build/dist/Models/AnalyticsModels/MutableMetric.js +275 -0
- package/build/dist/Models/AnalyticsModels/MutableMetric.js.map +1 -0
- package/build/dist/Server/Services/AlertService.js +133 -170
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/AlertStateTimelineService.js +97 -0
- package/build/dist/Server/Services/AlertStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +16 -15
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +142 -207
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/IncidentStateTimelineService.js +97 -0
- package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +2 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/MetricAggregationService.js +49 -3
- package/build/dist/Server/Services/MetricAggregationService.js.map +1 -1
- package/build/dist/Server/Services/MetricService.js +155 -0
- package/build/dist/Server/Services/MetricService.js.map +1 -1
- package/build/dist/Server/Services/MutableMetricService.js +182 -0
- package/build/dist/Server/Services/MutableMetricService.js.map +1 -0
- package/build/dist/Server/Services/TelemetryAttributeService.js +131 -6
- package/build/dist/Server/Services/TelemetryAttributeService.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/ClusterConfig.js +2 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/ClusterConfig.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js +2 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js.map +1 -1
- package/build/dist/Types/AnalyticsDatabase/AnalyticsTableEngine.js +1 -0
- package/build/dist/Types/AnalyticsDatabase/AnalyticsTableEngine.js.map +1 -1
- package/build/dist/Types/AnalyticsDatabase/AnalyticsTableName.js +1 -0
- package/build/dist/Types/AnalyticsDatabase/AnalyticsTableName.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepMetricMonitor.js +0 -13
- package/build/dist/Types/Monitor/MonitorStepMetricMonitor.js.map +1 -1
- package/package.json +1 -1
|
@@ -41,10 +41,11 @@ import IncidentStateTimeline from "../../Models/DatabaseModels/IncidentStateTime
|
|
|
41
41
|
import Monitor from "../../Models/DatabaseModels/Monitor";
|
|
42
42
|
import MonitorStatusTimeline from "../../Models/DatabaseModels/MonitorStatusTimeline";
|
|
43
43
|
import { IsBillingEnabled } from "../EnvironmentConfig";
|
|
44
|
-
import
|
|
44
|
+
import MutableMetricService from "./MutableMetricService";
|
|
45
45
|
import GlobalConfigService from "./GlobalConfigService";
|
|
46
46
|
import IncidentMetricType from "../../Types/Incident/IncidentMetricType";
|
|
47
|
-
import
|
|
47
|
+
import MutableMetric from "../../Models/AnalyticsModels/MutableMetric";
|
|
48
|
+
import { MetricPointType } from "../../Models/AnalyticsModels/Metric";
|
|
48
49
|
import ServiceType from "../../Types/Telemetry/ServiceType";
|
|
49
50
|
import OneUptimeDate from "../../Types/Date";
|
|
50
51
|
import TelemetryUtil from "../Utils/Telemetry/Telemetry";
|
|
@@ -1319,12 +1320,14 @@ ${incident.remediationNotes || "No remediation notes provided."}
|
|
|
1319
1320
|
});
|
|
1320
1321
|
// only emit if the incident has been resolved
|
|
1321
1322
|
if (resolvedTimeline && resolvedTimeline.startsAt) {
|
|
1322
|
-
const postmortemMetric = new
|
|
1323
|
+
const postmortemMetric = new MutableMetric();
|
|
1323
1324
|
postmortemMetric.projectId = projectId;
|
|
1324
1325
|
postmortemMetric.primaryEntityId = incidentId;
|
|
1325
1326
|
postmortemMetric.primaryEntityType = ServiceType.Incident;
|
|
1326
1327
|
postmortemMetric.name =
|
|
1327
1328
|
IncidentMetricType.PostmortemCompletionTime;
|
|
1329
|
+
postmortemMetric.metricPointId =
|
|
1330
|
+
IncidentMetricType.PostmortemCompletionTime;
|
|
1328
1331
|
postmortemMetric.value = OneUptimeDate.getDifferenceInSeconds(postmortemPostedAt, resolvedTimeline.startsAt);
|
|
1329
1332
|
postmortemMetric.attributes = {
|
|
1330
1333
|
incidentId: incidentId.toString(),
|
|
@@ -1336,11 +1339,8 @@ ${incident.remediationNotes || "No remediation notes provided."}
|
|
|
1336
1339
|
postmortemMetric.metricPointType = MetricPointType.Sum;
|
|
1337
1340
|
const postmortemRetentionDays = await this.getMetricRetentionDays();
|
|
1338
1341
|
postmortemMetric.retentionDate = OneUptimeDate.addRemoveDays(OneUptimeDate.getCurrentDate(), postmortemRetentionDays);
|
|
1339
|
-
await
|
|
1340
|
-
|
|
1341
|
-
props: {
|
|
1342
|
-
isRoot: true,
|
|
1343
|
-
},
|
|
1342
|
+
await MutableMetricService.createMutableMetrics({
|
|
1343
|
+
metrics: [postmortemMetric],
|
|
1344
1344
|
});
|
|
1345
1345
|
const postmortemMetricType = new MetricType();
|
|
1346
1346
|
postmortemMetricType.name =
|
|
@@ -1500,11 +1500,12 @@ ${incidentSeverity.name}
|
|
|
1500
1500
|
}
|
|
1501
1501
|
// emit severity change metric
|
|
1502
1502
|
try {
|
|
1503
|
-
const severityChangeMetric = new
|
|
1503
|
+
const severityChangeMetric = new MutableMetric();
|
|
1504
1504
|
severityChangeMetric.projectId = projectId;
|
|
1505
1505
|
severityChangeMetric.primaryEntityId = incidentId;
|
|
1506
1506
|
severityChangeMetric.primaryEntityType = ServiceType.Incident;
|
|
1507
1507
|
severityChangeMetric.name = IncidentMetricType.SeverityChange;
|
|
1508
|
+
severityChangeMetric.metricPointId = `severity-change:${ObjectID.generate().toString()}`;
|
|
1508
1509
|
severityChangeMetric.value = 1;
|
|
1509
1510
|
severityChangeMetric.attributes = {
|
|
1510
1511
|
incidentId: incidentId.toString(),
|
|
@@ -1519,11 +1520,8 @@ ${incidentSeverity.name}
|
|
|
1519
1520
|
severityChangeMetric.metricPointType = MetricPointType.Sum;
|
|
1520
1521
|
const severityRetentionDays = await this.getMetricRetentionDays();
|
|
1521
1522
|
severityChangeMetric.retentionDate = OneUptimeDate.addRemoveDays(OneUptimeDate.getCurrentDate(), severityRetentionDays);
|
|
1522
|
-
await
|
|
1523
|
-
|
|
1524
|
-
props: {
|
|
1525
|
-
isRoot: true,
|
|
1526
|
-
},
|
|
1523
|
+
await MutableMetricService.createMutableMetrics({
|
|
1524
|
+
metrics: [severityChangeMetric],
|
|
1527
1525
|
});
|
|
1528
1526
|
const severityChangeMetricType = new MetricType();
|
|
1529
1527
|
severityChangeMetricType.name = IncidentMetricType.SeverityChange;
|
|
@@ -1847,14 +1845,13 @@ ${incidentSeverity.name}
|
|
|
1847
1845
|
await this.markMonitorsActiveForMonitoring(incident.projectId, incident.monitors);
|
|
1848
1846
|
}
|
|
1849
1847
|
if (incident.projectId && incident.id) {
|
|
1850
|
-
await
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
},
|
|
1848
|
+
const metricRetentionDays = await this.getMetricRetentionDays();
|
|
1849
|
+
await MutableMetricService.tombstoneEntityMetrics({
|
|
1850
|
+
projectId: incident.projectId,
|
|
1851
|
+
primaryEntityId: incident.id,
|
|
1852
|
+
primaryEntityType: ServiceType.Incident,
|
|
1853
|
+
metricNames: Object.values(IncidentMetricType),
|
|
1854
|
+
retentionDate: OneUptimeDate.addRemoveDays(OneUptimeDate.getCurrentDate(), metricRetentionDays),
|
|
1858
1855
|
});
|
|
1859
1856
|
}
|
|
1860
1857
|
}
|
|
@@ -1941,12 +1938,13 @@ ${incidentSeverity.name}
|
|
|
1941
1938
|
return Service.DEFAULT_METRIC_RETENTION_DAYS;
|
|
1942
1939
|
}
|
|
1943
1940
|
async refreshIncidentMetrics(data) {
|
|
1944
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u
|
|
1941
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
|
|
1945
1942
|
const incident = await this.findOneById({
|
|
1946
1943
|
id: data.incidentId,
|
|
1947
1944
|
select: {
|
|
1948
1945
|
projectId: true,
|
|
1949
1946
|
declaredAt: true,
|
|
1947
|
+
postmortemPostedAt: true,
|
|
1950
1948
|
monitors: {
|
|
1951
1949
|
_id: true,
|
|
1952
1950
|
name: true,
|
|
@@ -2039,6 +2037,7 @@ ${incidentSeverity.name}
|
|
|
2039
2037
|
incidentId: data.incidentId,
|
|
2040
2038
|
},
|
|
2041
2039
|
select: {
|
|
2040
|
+
_id: true,
|
|
2042
2041
|
projectId: true,
|
|
2043
2042
|
incidentStateId: true,
|
|
2044
2043
|
incidentState: {
|
|
@@ -2061,18 +2060,10 @@ ${incidentSeverity.name}
|
|
|
2061
2060
|
});
|
|
2062
2061
|
const firstIncidentStateTimeline = incidentStateTimelines[0];
|
|
2063
2062
|
/*
|
|
2064
|
-
* Serialize concurrent refreshes for this incident across pods.
|
|
2065
|
-
*
|
|
2066
|
-
*
|
|
2067
|
-
*
|
|
2068
|
-
* close-together transitions (e.g. auto-acknowledge then auto-resolve)
|
|
2069
|
-
* could interleave: both read a snapshot missing a metric and both
|
|
2070
|
-
* insert it. The Metric table is a plain MergeTree with no row collapse,
|
|
2071
|
-
* so those duplicates would be permanent and re-inflate the very Sum/Avg
|
|
2072
|
-
* widgets this change fixes. A best-effort distributed lock keyed on the
|
|
2073
|
-
* incident makes the read+insert atomic; if the lock can't be taken we
|
|
2074
|
-
* still proceed (the existence check alone covers the common sequential
|
|
2075
|
-
* case).
|
|
2063
|
+
* Serialize concurrent refreshes for this incident across pods. Mutable
|
|
2064
|
+
* metrics are versioned inserts, but the replace operation also tombstones
|
|
2065
|
+
* stale metric-point identities. The lock keeps that read+insert cycle
|
|
2066
|
+
* ordered for each incident.
|
|
2076
2067
|
*/
|
|
2077
2068
|
let metricRefreshMutex = null;
|
|
2078
2069
|
try {
|
|
@@ -2089,65 +2080,6 @@ ${incidentSeverity.name}
|
|
|
2089
2080
|
});
|
|
2090
2081
|
}
|
|
2091
2082
|
try {
|
|
2092
|
-
/*
|
|
2093
|
-
* Write-once metrics — no deletes.
|
|
2094
|
-
*
|
|
2095
|
-
* The raw Metric table (`MetricItemV3`) feeds an AggregatingMergeTree
|
|
2096
|
-
* materialized view (`MetricItemAggMV1m_mv`) that accumulates
|
|
2097
|
-
* `sumState`/`countState` per (projectId, name, primaryEntityId,
|
|
2098
|
-
* minute). The MV trigger fires only on INSERT — an `ALTER ... DELETE`
|
|
2099
|
-
* mutation on the source rolls back nothing in the MV. So the old
|
|
2100
|
-
* "delete every metric for this incident, then re-insert" refresh both
|
|
2101
|
-
* (a) inflated those rollups (the Sum-of-IncidentCount widget read high)
|
|
2102
|
-
* and (b) issued one heavy `ALTER ... DELETE` mutation per state
|
|
2103
|
-
* transition per incident — a mutation storm.
|
|
2104
|
-
*
|
|
2105
|
-
* Every incident metric has a single eventually-final value:
|
|
2106
|
-
* IncidentCount is constant `value = 1`; MTTA/MTTR/duration/time-in-state
|
|
2107
|
-
* are each fixed once the relevant state transition has happened. So we
|
|
2108
|
-
* load what we've already emitted for this incident and insert each
|
|
2109
|
-
* metric exactly once, when it becomes final. Repeat refreshes that find
|
|
2110
|
-
* nothing new are pure no-ops (no insert, no mutation).
|
|
2111
|
-
*/
|
|
2112
|
-
const existingMetrics = await MetricService.findBy({
|
|
2113
|
-
query: {
|
|
2114
|
-
projectId: incident.projectId,
|
|
2115
|
-
primaryEntityId: data.incidentId,
|
|
2116
|
-
},
|
|
2117
|
-
select: {
|
|
2118
|
-
name: true,
|
|
2119
|
-
time: true,
|
|
2120
|
-
attributes: true,
|
|
2121
|
-
},
|
|
2122
|
-
skip: 0,
|
|
2123
|
-
limit: LIMIT_PER_PROJECT,
|
|
2124
|
-
props: {
|
|
2125
|
-
isRoot: true,
|
|
2126
|
-
},
|
|
2127
|
-
});
|
|
2128
|
-
const existingMetricNames = new Set(existingMetrics
|
|
2129
|
-
.map((metric) => {
|
|
2130
|
-
return metric.name;
|
|
2131
|
-
})
|
|
2132
|
-
.filter(Boolean));
|
|
2133
|
-
/*
|
|
2134
|
-
* Identity of a TimeInState row: the state plus the instant that state
|
|
2135
|
-
* began (a state can be entered more than once over a re-opened
|
|
2136
|
-
* incident). Second granularity is robust against DateTime64 round-trip
|
|
2137
|
-
* jitter and two distinct entries into the same state within one second
|
|
2138
|
-
* never happen.
|
|
2139
|
-
*/
|
|
2140
|
-
const buildTimeInStateKey = (stateId, startsAt) => {
|
|
2141
|
-
return `${stateId || ""}|${startsAt ? OneUptimeDate.toUnixTimestamp(startsAt) : ""}`;
|
|
2142
|
-
};
|
|
2143
|
-
const existingTimeInStateKeys = new Set(existingMetrics
|
|
2144
|
-
.filter((metric) => {
|
|
2145
|
-
return metric.name === IncidentMetricType.TimeInState;
|
|
2146
|
-
})
|
|
2147
|
-
.map((metric) => {
|
|
2148
|
-
var _a;
|
|
2149
|
-
return buildTimeInStateKey((_a = metric.attributes) === null || _a === void 0 ? void 0 : _a["incidentStateId"], metric.time);
|
|
2150
|
-
}));
|
|
2151
2083
|
const itemsToSave = [];
|
|
2152
2084
|
const metricRetentionDays = await this.getMetricRetentionDays();
|
|
2153
2085
|
const incidentMetricRetentionDate = OneUptimeDate.addRemoveDays(OneUptimeDate.getCurrentDate(), metricRetentionDays);
|
|
@@ -2180,29 +2112,20 @@ ${incidentSeverity.name}
|
|
|
2180
2112
|
ownerTeamIds: ownerTeamIds.join(", "),
|
|
2181
2113
|
ownerTeamNames: ownerTeamNames.join(", "),
|
|
2182
2114
|
};
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
incidentCountMetric.value = 1;
|
|
2198
|
-
incidentCountMetric.attributes = Object.assign({}, baseMetricAttributes);
|
|
2199
|
-
incidentCountMetric.attributeKeys = TelemetryUtil.getAttributeKeys(incidentCountMetric.attributes);
|
|
2200
|
-
incidentCountMetric.time = incidentStartsAt;
|
|
2201
|
-
incidentCountMetric.timeUnixNano = OneUptimeDate.toUnixNano(incidentCountMetric.time);
|
|
2202
|
-
incidentCountMetric.metricPointType = MetricPointType.Sum;
|
|
2203
|
-
incidentCountMetric.retentionDate = incidentMetricRetentionDate;
|
|
2204
|
-
itemsToSave.push(incidentCountMetric);
|
|
2205
|
-
}
|
|
2115
|
+
const incidentCountMetric = new MutableMetric();
|
|
2116
|
+
incidentCountMetric.projectId = incident.projectId;
|
|
2117
|
+
incidentCountMetric.primaryEntityId = incident.id;
|
|
2118
|
+
incidentCountMetric.primaryEntityType = ServiceType.Incident;
|
|
2119
|
+
incidentCountMetric.name = IncidentMetricType.IncidentCount;
|
|
2120
|
+
incidentCountMetric.metricPointId = IncidentMetricType.IncidentCount;
|
|
2121
|
+
incidentCountMetric.value = 1;
|
|
2122
|
+
incidentCountMetric.attributes = Object.assign({}, baseMetricAttributes);
|
|
2123
|
+
incidentCountMetric.attributeKeys = TelemetryUtil.getAttributeKeys(incidentCountMetric.attributes);
|
|
2124
|
+
incidentCountMetric.time = incidentStartsAt;
|
|
2125
|
+
incidentCountMetric.timeUnixNano = OneUptimeDate.toUnixNano(incidentCountMetric.time);
|
|
2126
|
+
incidentCountMetric.metricPointType = MetricPointType.Sum;
|
|
2127
|
+
incidentCountMetric.retentionDate = incidentMetricRetentionDate;
|
|
2128
|
+
itemsToSave.push(incidentCountMetric);
|
|
2206
2129
|
// Always register the metric type so it shows up in the type catalog.
|
|
2207
2130
|
const metricType = new MetricType();
|
|
2208
2131
|
metricType.name = IncidentMetricType.IncidentCount;
|
|
@@ -2227,29 +2150,27 @@ ${incidentSeverity.name}
|
|
|
2227
2150
|
metricType.description = "Time taken to acknowledge the incident";
|
|
2228
2151
|
metricType.unit = "seconds";
|
|
2229
2152
|
metricTypesMap[IncidentMetricType.TimeToAcknowledge] = metricType;
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
timeToAcknowledgeMetric.
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
itemsToSave.push(timeToAcknowledgeMetric);
|
|
2252
|
-
}
|
|
2153
|
+
const timeToAcknowledgeMetric = new MutableMetric();
|
|
2154
|
+
timeToAcknowledgeMetric.projectId = incident.projectId;
|
|
2155
|
+
timeToAcknowledgeMetric.primaryEntityId = incident.id;
|
|
2156
|
+
timeToAcknowledgeMetric.primaryEntityType = ServiceType.Incident;
|
|
2157
|
+
timeToAcknowledgeMetric.name = IncidentMetricType.TimeToAcknowledge;
|
|
2158
|
+
timeToAcknowledgeMetric.metricPointId =
|
|
2159
|
+
IncidentMetricType.TimeToAcknowledge;
|
|
2160
|
+
timeToAcknowledgeMetric.value = OneUptimeDate.getDifferenceInSeconds((ackIncidentStateTimeline === null || ackIncidentStateTimeline === void 0 ? void 0 : ackIncidentStateTimeline.startsAt) ||
|
|
2161
|
+
OneUptimeDate.getCurrentDate(), incidentStartsAt);
|
|
2162
|
+
timeToAcknowledgeMetric.attributes = Object.assign({}, baseMetricAttributes);
|
|
2163
|
+
timeToAcknowledgeMetric.attributeKeys =
|
|
2164
|
+
TelemetryUtil.getAttributeKeys(timeToAcknowledgeMetric.attributes);
|
|
2165
|
+
timeToAcknowledgeMetric.time =
|
|
2166
|
+
(ackIncidentStateTimeline === null || ackIncidentStateTimeline === void 0 ? void 0 : ackIncidentStateTimeline.startsAt) ||
|
|
2167
|
+
incident.declaredAt ||
|
|
2168
|
+
incident.createdAt ||
|
|
2169
|
+
OneUptimeDate.getCurrentDate();
|
|
2170
|
+
timeToAcknowledgeMetric.timeUnixNano = OneUptimeDate.toUnixNano(timeToAcknowledgeMetric.time);
|
|
2171
|
+
timeToAcknowledgeMetric.metricPointType = MetricPointType.Sum;
|
|
2172
|
+
timeToAcknowledgeMetric.retentionDate = incidentMetricRetentionDate;
|
|
2173
|
+
itemsToSave.push(timeToAcknowledgeMetric);
|
|
2253
2174
|
}
|
|
2254
2175
|
}
|
|
2255
2176
|
// time to resolve
|
|
@@ -2268,39 +2189,26 @@ ${incidentSeverity.name}
|
|
|
2268
2189
|
metricType.description = "Time taken to resolve the incident";
|
|
2269
2190
|
metricType.unit = "seconds";
|
|
2270
2191
|
metricTypesMap[IncidentMetricType.TimeToResolve] = metricType;
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
itemsToSave.push(timeToResolveMetric);
|
|
2291
|
-
}
|
|
2192
|
+
const timeToResolveMetric = new MutableMetric();
|
|
2193
|
+
timeToResolveMetric.projectId = incident.projectId;
|
|
2194
|
+
timeToResolveMetric.primaryEntityId = incident.id;
|
|
2195
|
+
timeToResolveMetric.primaryEntityType = ServiceType.Incident;
|
|
2196
|
+
timeToResolveMetric.name = IncidentMetricType.TimeToResolve;
|
|
2197
|
+
timeToResolveMetric.metricPointId = IncidentMetricType.TimeToResolve;
|
|
2198
|
+
timeToResolveMetric.value = OneUptimeDate.getDifferenceInSeconds((resolvedIncidentStateTimeline === null || resolvedIncidentStateTimeline === void 0 ? void 0 : resolvedIncidentStateTimeline.startsAt) ||
|
|
2199
|
+
OneUptimeDate.getCurrentDate(), incidentStartsAt);
|
|
2200
|
+
timeToResolveMetric.attributes = Object.assign({}, baseMetricAttributes);
|
|
2201
|
+
timeToResolveMetric.attributeKeys = TelemetryUtil.getAttributeKeys(timeToResolveMetric.attributes);
|
|
2202
|
+
timeToResolveMetric.time =
|
|
2203
|
+
(resolvedIncidentStateTimeline === null || resolvedIncidentStateTimeline === void 0 ? void 0 : resolvedIncidentStateTimeline.startsAt) ||
|
|
2204
|
+
incident.declaredAt ||
|
|
2205
|
+
incident.createdAt ||
|
|
2206
|
+
OneUptimeDate.getCurrentDate();
|
|
2207
|
+
timeToResolveMetric.timeUnixNano = OneUptimeDate.toUnixNano(timeToResolveMetric.time);
|
|
2208
|
+
timeToResolveMetric.metricPointType = MetricPointType.Sum;
|
|
2209
|
+
timeToResolveMetric.retentionDate = incidentMetricRetentionDate;
|
|
2210
|
+
itemsToSave.push(timeToResolveMetric);
|
|
2292
2211
|
}
|
|
2293
|
-
/*
|
|
2294
|
-
* Incident duration — write-once, finalized at resolution.
|
|
2295
|
-
*
|
|
2296
|
-
* The previous implementation recomputed duration as
|
|
2297
|
-
* (latest state transition − start) on every refresh, so an open
|
|
2298
|
-
* incident's duration grew and had to be deleted + re-inserted each
|
|
2299
|
-
* time. With no deletes we emit a single final duration once the
|
|
2300
|
-
* incident reaches a resolved state: (first resolution − start). An
|
|
2301
|
-
* incident that is never resolved has no duration row (its lifetime is
|
|
2302
|
-
* not yet final), which keeps the "Avg Duration" widget meaningful.
|
|
2303
|
-
*/
|
|
2304
2212
|
if (isIncidentResolved && resolvedIncidentStateTimeline) {
|
|
2305
2213
|
// register the metric type so the catalog stays complete across refreshes.
|
|
2306
2214
|
const metricType = new MetricType();
|
|
@@ -2308,22 +2216,47 @@ ${incidentSeverity.name}
|
|
|
2308
2216
|
metricType.description = "Duration of the incident";
|
|
2309
2217
|
metricType.unit = "seconds";
|
|
2310
2218
|
metricTypesMap[IncidentMetricType.IncidentDuration] = metricType;
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2219
|
+
const incidentEndsAt = resolvedIncidentStateTimeline.startsAt ||
|
|
2220
|
+
OneUptimeDate.getCurrentDate();
|
|
2221
|
+
const incidentDurationMetric = new MutableMetric();
|
|
2222
|
+
incidentDurationMetric.projectId = incident.projectId;
|
|
2223
|
+
incidentDurationMetric.primaryEntityId = incident.id;
|
|
2224
|
+
incidentDurationMetric.primaryEntityType = ServiceType.Incident;
|
|
2225
|
+
incidentDurationMetric.name = IncidentMetricType.IncidentDuration;
|
|
2226
|
+
incidentDurationMetric.metricPointId =
|
|
2227
|
+
IncidentMetricType.IncidentDuration;
|
|
2228
|
+
incidentDurationMetric.value = OneUptimeDate.getDifferenceInSeconds(incidentEndsAt, incidentStartsAt);
|
|
2229
|
+
incidentDurationMetric.attributes = Object.assign({}, baseMetricAttributes);
|
|
2230
|
+
incidentDurationMetric.attributeKeys = TelemetryUtil.getAttributeKeys(incidentDurationMetric.attributes);
|
|
2231
|
+
incidentDurationMetric.time = incidentEndsAt;
|
|
2232
|
+
incidentDurationMetric.timeUnixNano = OneUptimeDate.toUnixNano(incidentDurationMetric.time);
|
|
2233
|
+
incidentDurationMetric.metricPointType = MetricPointType.Sum;
|
|
2234
|
+
incidentDurationMetric.retentionDate = incidentMetricRetentionDate;
|
|
2235
|
+
itemsToSave.push(incidentDurationMetric);
|
|
2236
|
+
if (incident.postmortemPostedAt) {
|
|
2237
|
+
const postmortemMetricType = new MetricType();
|
|
2238
|
+
postmortemMetricType.name =
|
|
2239
|
+
IncidentMetricType.PostmortemCompletionTime;
|
|
2240
|
+
postmortemMetricType.description =
|
|
2241
|
+
"Time from incident resolution to postmortem publication";
|
|
2242
|
+
postmortemMetricType.unit = "seconds";
|
|
2243
|
+
metricTypesMap[IncidentMetricType.PostmortemCompletionTime] =
|
|
2244
|
+
postmortemMetricType;
|
|
2245
|
+
const postmortemMetric = new MutableMetric();
|
|
2246
|
+
postmortemMetric.projectId = incident.projectId;
|
|
2247
|
+
postmortemMetric.primaryEntityId = incident.id;
|
|
2248
|
+
postmortemMetric.primaryEntityType = ServiceType.Incident;
|
|
2249
|
+
postmortemMetric.name = IncidentMetricType.PostmortemCompletionTime;
|
|
2250
|
+
postmortemMetric.metricPointId =
|
|
2251
|
+
IncidentMetricType.PostmortemCompletionTime;
|
|
2252
|
+
postmortemMetric.value = OneUptimeDate.getDifferenceInSeconds(incident.postmortemPostedAt, incidentEndsAt);
|
|
2253
|
+
postmortemMetric.attributes = Object.assign({}, baseMetricAttributes);
|
|
2254
|
+
postmortemMetric.attributeKeys = TelemetryUtil.getAttributeKeys(postmortemMetric.attributes);
|
|
2255
|
+
postmortemMetric.time = incident.postmortemPostedAt;
|
|
2256
|
+
postmortemMetric.timeUnixNano = OneUptimeDate.toUnixNano(postmortemMetric.time);
|
|
2257
|
+
postmortemMetric.metricPointType = MetricPointType.Sum;
|
|
2258
|
+
postmortemMetric.retentionDate = incidentMetricRetentionDate;
|
|
2259
|
+
itemsToSave.push(postmortemMetric);
|
|
2327
2260
|
}
|
|
2328
2261
|
}
|
|
2329
2262
|
// time-in-state metrics — emit one metric per state transition that has a completed duration
|
|
@@ -2331,19 +2264,15 @@ ${incidentSeverity.name}
|
|
|
2331
2264
|
if (!timeline.startsAt || !timeline.endsAt) {
|
|
2332
2265
|
continue;
|
|
2333
2266
|
}
|
|
2334
|
-
|
|
2335
|
-
const
|
|
2336
|
-
if (existingTimeInStateKeys.has(timeInStateKey)) {
|
|
2337
|
-
continue;
|
|
2338
|
-
}
|
|
2339
|
-
const stateName = ((_l = (_k = timeline.incidentState) === null || _k === void 0 ? void 0 : _k.name) === null || _l === void 0 ? void 0 : _l.toString()) || "Unknown";
|
|
2340
|
-
const timeInStateMetric = new Metric();
|
|
2267
|
+
const stateName = ((_k = (_j = timeline.incidentState) === null || _j === void 0 ? void 0 : _j.name) === null || _k === void 0 ? void 0 : _k.toString()) || "Unknown";
|
|
2268
|
+
const timeInStateMetric = new MutableMetric();
|
|
2341
2269
|
timeInStateMetric.projectId = incident.projectId;
|
|
2342
2270
|
timeInStateMetric.primaryEntityId = incident.id;
|
|
2343
2271
|
timeInStateMetric.primaryEntityType = ServiceType.Incident;
|
|
2344
2272
|
timeInStateMetric.name = IncidentMetricType.TimeInState;
|
|
2273
|
+
timeInStateMetric.metricPointId = `time-in-state:${timeline.id.toString()}`;
|
|
2345
2274
|
timeInStateMetric.value = OneUptimeDate.getDifferenceInSeconds(timeline.endsAt, timeline.startsAt);
|
|
2346
|
-
timeInStateMetric.attributes = Object.assign(Object.assign({}, baseMetricAttributes), { incidentStateName: stateName, incidentStateId: (
|
|
2275
|
+
timeInStateMetric.attributes = Object.assign(Object.assign({}, baseMetricAttributes), { incidentStateName: stateName, incidentStateId: (_l = timeline.incidentStateId) === null || _l === void 0 ? void 0 : _l.toString(), isCreatedState: ((_o = (_m = timeline.incidentState) === null || _m === void 0 ? void 0 : _m.isCreatedState) === null || _o === void 0 ? void 0 : _o.toString()) || "false", isAcknowledgedState: ((_q = (_p = timeline.incidentState) === null || _p === void 0 ? void 0 : _p.isAcknowledgedState) === null || _q === void 0 ? void 0 : _q.toString()) || "false", isResolvedState: ((_s = (_r = timeline.incidentState) === null || _r === void 0 ? void 0 : _r.isResolvedState) === null || _s === void 0 ? void 0 : _s.toString()) || "false" });
|
|
2347
2276
|
timeInStateMetric.attributeKeys = TelemetryUtil.getAttributeKeys(timeInStateMetric.attributes);
|
|
2348
2277
|
timeInStateMetric.time = timeline.startsAt;
|
|
2349
2278
|
timeInStateMetric.timeUnixNano = OneUptimeDate.toUnixNano(timeInStateMetric.time);
|
|
@@ -2362,15 +2291,21 @@ ${incidentSeverity.name}
|
|
|
2362
2291
|
timeInStateMetricType.unit = "seconds";
|
|
2363
2292
|
metricTypesMap[timeInStateMetricType.name] = timeInStateMetricType;
|
|
2364
2293
|
}
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2294
|
+
await MutableMetricService.replaceEntityMetrics({
|
|
2295
|
+
projectId: incident.projectId,
|
|
2296
|
+
primaryEntityId: incident.id,
|
|
2297
|
+
primaryEntityType: ServiceType.Incident,
|
|
2298
|
+
metricNames: [
|
|
2299
|
+
IncidentMetricType.IncidentCount,
|
|
2300
|
+
IncidentMetricType.TimeToAcknowledge,
|
|
2301
|
+
IncidentMetricType.TimeToResolve,
|
|
2302
|
+
IncidentMetricType.IncidentDuration,
|
|
2303
|
+
IncidentMetricType.TimeInState,
|
|
2304
|
+
IncidentMetricType.PostmortemCompletionTime,
|
|
2305
|
+
],
|
|
2306
|
+
metrics: itemsToSave,
|
|
2307
|
+
retentionDate: incidentMetricRetentionDate,
|
|
2308
|
+
});
|
|
2374
2309
|
TelemetryUtil.indexMetricNameServiceNameMap({
|
|
2375
2310
|
metricNameServiceNameMap: metricTypesMap,
|
|
2376
2311
|
projectId: incident.projectId,
|
|
@@ -2389,8 +2324,8 @@ ${incidentSeverity.name}
|
|
|
2389
2324
|
}
|
|
2390
2325
|
catch (err) {
|
|
2391
2326
|
logger.error(err, {
|
|
2392
|
-
projectId: (
|
|
2393
|
-
incidentId: (
|
|
2327
|
+
projectId: (_t = incident.projectId) === null || _t === void 0 ? void 0 : _t.toString(),
|
|
2328
|
+
incidentId: (_u = incident.id) === null || _u === void 0 ? void 0 : _u.toString(),
|
|
2394
2329
|
});
|
|
2395
2330
|
}
|
|
2396
2331
|
}
|