@oneuptime/common 10.5.22 → 10.5.24
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/Server/Infrastructure/Semaphore.ts +10 -0
- package/Server/Utils/Monitor/MonitorResource.ts +570 -545
- package/build/dist/Server/Infrastructure/Semaphore.js +6 -0
- package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +434 -416
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/package.json +1 -1
|
@@ -58,17 +58,6 @@ export default class MonitorResourceUtil {
|
|
|
58
58
|
public static async monitorResource(
|
|
59
59
|
dataToProcess: DataToProcess,
|
|
60
60
|
): Promise<ProbeApiIngestResponse> {
|
|
61
|
-
let mutex: SemaphoreMutex | null = null;
|
|
62
|
-
|
|
63
|
-
try {
|
|
64
|
-
mutex = await Semaphore.lock({
|
|
65
|
-
key: dataToProcess.monitorId.toString(),
|
|
66
|
-
namespace: "MonitorResourceUtil.monitorResource",
|
|
67
|
-
});
|
|
68
|
-
} catch (err) {
|
|
69
|
-
logger.error(err);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
61
|
let response: ProbeApiIngestResponse = {
|
|
73
62
|
monitorId: dataToProcess.monitorId,
|
|
74
63
|
criteriaMetId: undefined,
|
|
@@ -188,114 +177,181 @@ export default class MonitorResourceUtil {
|
|
|
188
177
|
);
|
|
189
178
|
}
|
|
190
179
|
|
|
191
|
-
|
|
192
|
-
|
|
180
|
+
/*
|
|
181
|
+
* Acquire a per-monitor lock so concurrent results for the same monitor are
|
|
182
|
+
* processed serially. This MUST come after the validation above: acquiring
|
|
183
|
+
* before the not-found/disabled checks meant those throw paths held — and
|
|
184
|
+
* leaked — the lock. redis-semaphore keeps a refresh timer alive until
|
|
185
|
+
* release() is called, so a leaked lock pinned the Redis key until pod
|
|
186
|
+
* restart and forced every other worker to spin on acquire. The try/finally
|
|
187
|
+
* below guarantees the lock is released on every exit path (return or
|
|
188
|
+
* throw); acquireTimeout/retryInterval cap the acquire spin so a contended
|
|
189
|
+
* lock fails fast instead of polling Redis for 10s.
|
|
190
|
+
*/
|
|
191
|
+
let mutex: SemaphoreMutex | null = null;
|
|
193
192
|
|
|
194
|
-
|
|
193
|
+
try {
|
|
194
|
+
mutex = await Semaphore.lock({
|
|
195
|
+
key: dataToProcess.monitorId.toString(),
|
|
196
|
+
namespace: "MonitorResourceUtil.monitorResource",
|
|
197
|
+
acquireTimeout: 2000,
|
|
198
|
+
retryInterval: 100,
|
|
199
|
+
acquireAttemptsLimit: 20,
|
|
200
|
+
});
|
|
201
|
+
} catch (err) {
|
|
202
|
+
logger.error(err);
|
|
203
|
+
}
|
|
195
204
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
205
|
+
const releaseMutex: () => Promise<void> = async (): Promise<void> => {
|
|
206
|
+
if (mutex) {
|
|
207
|
+
try {
|
|
208
|
+
await Semaphore.release(mutex);
|
|
209
|
+
} catch (err) {
|
|
210
|
+
logger.error(err);
|
|
211
|
+
}
|
|
212
|
+
mutex = null;
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
try {
|
|
217
|
+
let probeName: string | undefined = undefined;
|
|
218
|
+
const monitorName: string | undefined = monitor.name || undefined;
|
|
219
|
+
|
|
220
|
+
// save the last log to MonitorProbe.
|
|
202
221
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
222
|
+
// get last log. We do this because there are many monitoring steps and we need to store those.
|
|
223
|
+
logger.debug(
|
|
224
|
+
`${dataToProcess.monitorId.toString()} - monitor type ${
|
|
225
|
+
monitor.monitorType
|
|
226
|
+
}`,
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
if (
|
|
230
|
+
monitor.monitorType &&
|
|
231
|
+
MonitorTypeHelper.isProbableMonitor(monitor.monitorType)
|
|
232
|
+
) {
|
|
233
|
+
dataToProcess = dataToProcess as ProbeMonitorResponse;
|
|
234
|
+
if ((dataToProcess as ProbeMonitorResponse).probeId) {
|
|
235
|
+
const monitorProbe: MonitorProbe | null =
|
|
236
|
+
await MonitorProbeService.findOneBy({
|
|
237
|
+
query: {
|
|
238
|
+
monitorId: monitor.id!,
|
|
239
|
+
probeId: (dataToProcess as ProbeMonitorResponse).probeId!,
|
|
240
|
+
},
|
|
241
|
+
select: {
|
|
242
|
+
lastMonitoringLog: true,
|
|
243
|
+
probe: {
|
|
244
|
+
name: true,
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
props: {
|
|
248
|
+
isRoot: true,
|
|
249
|
+
},
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
if (!monitorProbe) {
|
|
253
|
+
throw new BadDataException("Probe is not assigned to this monitor");
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
probeName = monitorProbe.probe?.name || undefined;
|
|
257
|
+
|
|
258
|
+
await MonitorProbeService.updateOneBy({
|
|
211
259
|
query: {
|
|
212
260
|
monitorId: monitor.id!,
|
|
213
261
|
probeId: (dataToProcess as ProbeMonitorResponse).probeId!,
|
|
214
262
|
},
|
|
215
|
-
|
|
216
|
-
lastMonitoringLog:
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
263
|
+
data: {
|
|
264
|
+
lastMonitoringLog: {
|
|
265
|
+
...(monitorProbe.lastMonitoringLog || {}),
|
|
266
|
+
[(
|
|
267
|
+
dataToProcess as ProbeMonitorResponse
|
|
268
|
+
).monitorStepId.toString()]: {
|
|
269
|
+
...JSON.parse(JSON.stringify(dataToProcess)),
|
|
270
|
+
monitoredAt: OneUptimeDate.getCurrentDate(),
|
|
271
|
+
},
|
|
272
|
+
} as any,
|
|
220
273
|
},
|
|
221
274
|
props: {
|
|
222
275
|
isRoot: true,
|
|
223
276
|
},
|
|
224
277
|
});
|
|
278
|
+
}
|
|
279
|
+
}
|
|
225
280
|
|
|
226
|
-
|
|
227
|
-
|
|
281
|
+
const serverMonitorResponse: ServerMonitorResponse | undefined =
|
|
282
|
+
monitor.monitorType === MonitorType.Server &&
|
|
283
|
+
(dataToProcess as ServerMonitorResponse).requestReceivedAt
|
|
284
|
+
? (dataToProcess as ServerMonitorResponse)
|
|
285
|
+
: undefined;
|
|
286
|
+
|
|
287
|
+
const incomingMonitorRequest: IncomingMonitorRequest | undefined =
|
|
288
|
+
monitor.monitorType === MonitorType.IncomingRequest &&
|
|
289
|
+
(dataToProcess as IncomingMonitorRequest).incomingRequestReceivedAt &&
|
|
290
|
+
!(dataToProcess as IncomingMonitorRequest)
|
|
291
|
+
.onlyCheckForIncomingRequestReceivedAt
|
|
292
|
+
? (dataToProcess as IncomingMonitorRequest)
|
|
293
|
+
: undefined;
|
|
294
|
+
|
|
295
|
+
let hasPersistedMonitorData: boolean = false;
|
|
296
|
+
|
|
297
|
+
const persistLatestMonitorPayload: () => Promise<void> = async () => {
|
|
298
|
+
if (hasPersistedMonitorData) {
|
|
299
|
+
return;
|
|
228
300
|
}
|
|
229
301
|
|
|
230
|
-
|
|
302
|
+
if (serverMonitorResponse) {
|
|
303
|
+
logger.debug(
|
|
304
|
+
`${dataToProcess.monitorId.toString()} - Server request received at ${serverMonitorResponse.requestReceivedAt}`,
|
|
305
|
+
);
|
|
231
306
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
307
|
+
logger.debug(dataToProcess);
|
|
308
|
+
|
|
309
|
+
/*
|
|
310
|
+
* Skip persistence when this evaluation originated from the
|
|
311
|
+
* CheckOnlineStatus cron (onlyCheckRequestReceivedAt=true). The cron
|
|
312
|
+
* re-evaluates using the already-stale value read from the DB and has
|
|
313
|
+
* no new heartbeat data to persist — writing it back would race with
|
|
314
|
+
* (and overwrite) the ingest path's fresh heartbeat update, causing
|
|
315
|
+
* the monitor to flap between Online and Offline every minute.
|
|
316
|
+
*/
|
|
317
|
+
if (!serverMonitorResponse.onlyCheckRequestReceivedAt) {
|
|
318
|
+
await MonitorService.updateOneById({
|
|
319
|
+
id: monitor.id!,
|
|
320
|
+
data: {
|
|
321
|
+
serverMonitorRequestReceivedAt:
|
|
322
|
+
serverMonitorResponse.requestReceivedAt!,
|
|
323
|
+
serverMonitorResponse,
|
|
245
324
|
},
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
const incomingMonitorRequest: IncomingMonitorRequest | undefined =
|
|
262
|
-
monitor.monitorType === MonitorType.IncomingRequest &&
|
|
263
|
-
(dataToProcess as IncomingMonitorRequest).incomingRequestReceivedAt &&
|
|
264
|
-
!(dataToProcess as IncomingMonitorRequest)
|
|
265
|
-
.onlyCheckForIncomingRequestReceivedAt
|
|
266
|
-
? (dataToProcess as IncomingMonitorRequest)
|
|
267
|
-
: undefined;
|
|
268
|
-
|
|
269
|
-
let hasPersistedMonitorData: boolean = false;
|
|
270
|
-
|
|
271
|
-
const persistLatestMonitorPayload: () => Promise<void> = async () => {
|
|
272
|
-
if (hasPersistedMonitorData) {
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
325
|
+
props: {
|
|
326
|
+
isRoot: true,
|
|
327
|
+
ignoreHooks: true,
|
|
328
|
+
},
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
logger.debug(
|
|
332
|
+
`${dataToProcess.monitorId.toString()} - Monitor Server Response Updated`,
|
|
333
|
+
);
|
|
334
|
+
} else {
|
|
335
|
+
logger.debug(
|
|
336
|
+
`${dataToProcess.monitorId.toString()} - Skipping Monitor Server Response persist (cron re-evaluation).`,
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
275
340
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
341
|
+
if (incomingMonitorRequest) {
|
|
342
|
+
logger.debug(
|
|
343
|
+
`${dataToProcess.monitorId.toString()} - Incoming request received at ${incomingMonitorRequest.incomingRequestReceivedAt}`,
|
|
344
|
+
);
|
|
280
345
|
|
|
281
|
-
logger.debug(dataToProcess);
|
|
282
|
-
|
|
283
|
-
/*
|
|
284
|
-
* Skip persistence when this evaluation originated from the
|
|
285
|
-
* CheckOnlineStatus cron (onlyCheckRequestReceivedAt=true). The cron
|
|
286
|
-
* re-evaluates using the already-stale value read from the DB and has
|
|
287
|
-
* no new heartbeat data to persist — writing it back would race with
|
|
288
|
-
* (and overwrite) the ingest path's fresh heartbeat update, causing
|
|
289
|
-
* the monitor to flap between Online and Offline every minute.
|
|
290
|
-
*/
|
|
291
|
-
if (!serverMonitorResponse.onlyCheckRequestReceivedAt) {
|
|
292
346
|
await MonitorService.updateOneById({
|
|
293
347
|
id: monitor.id!,
|
|
294
348
|
data: {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
349
|
+
incomingRequestMonitorHeartbeatCheckedAt:
|
|
350
|
+
OneUptimeDate.getCurrentDate(),
|
|
351
|
+
incomingMonitorRequest: JSON.parse(
|
|
352
|
+
JSON.stringify(incomingMonitorRequest),
|
|
353
|
+
) as IncomingMonitorRequest,
|
|
354
|
+
} as any,
|
|
299
355
|
props: {
|
|
300
356
|
isRoot: true,
|
|
301
357
|
ignoreHooks: true,
|
|
@@ -303,267 +359,162 @@ export default class MonitorResourceUtil {
|
|
|
303
359
|
});
|
|
304
360
|
|
|
305
361
|
logger.debug(
|
|
306
|
-
`${dataToProcess.monitorId.toString()} - Monitor
|
|
307
|
-
);
|
|
308
|
-
} else {
|
|
309
|
-
logger.debug(
|
|
310
|
-
`${dataToProcess.monitorId.toString()} - Skipping Monitor Server Response persist (cron re-evaluation).`,
|
|
362
|
+
`${dataToProcess.monitorId.toString()} - Monitor Incoming Request Updated`,
|
|
311
363
|
);
|
|
312
364
|
}
|
|
313
|
-
}
|
|
314
365
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
`${dataToProcess.monitorId.toString()} - Incoming request received at ${incomingMonitorRequest.incomingRequestReceivedAt}`,
|
|
318
|
-
);
|
|
366
|
+
hasPersistedMonitorData = true;
|
|
367
|
+
};
|
|
319
368
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
incomingRequestMonitorHeartbeatCheckedAt:
|
|
324
|
-
OneUptimeDate.getCurrentDate(),
|
|
325
|
-
incomingMonitorRequest: JSON.parse(
|
|
326
|
-
JSON.stringify(incomingMonitorRequest),
|
|
327
|
-
) as IncomingMonitorRequest,
|
|
328
|
-
} as any,
|
|
329
|
-
props: {
|
|
330
|
-
isRoot: true,
|
|
331
|
-
ignoreHooks: true,
|
|
332
|
-
},
|
|
333
|
-
});
|
|
369
|
+
logger.debug(
|
|
370
|
+
`${dataToProcess.monitorId.toString()} - Saving monitor metrics`,
|
|
371
|
+
);
|
|
334
372
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
373
|
+
try {
|
|
374
|
+
await MonitorMetricUtil.saveMonitorMetrics({
|
|
375
|
+
monitorId: monitor.id!,
|
|
376
|
+
projectId: monitor.projectId!,
|
|
377
|
+
dataToProcess: dataToProcess,
|
|
378
|
+
probeName: probeName || undefined,
|
|
379
|
+
monitorName: monitorName || undefined,
|
|
380
|
+
});
|
|
381
|
+
} catch (err) {
|
|
382
|
+
logger.error("Unable to save metrics");
|
|
383
|
+
logger.error(err);
|
|
338
384
|
}
|
|
339
385
|
|
|
340
|
-
hasPersistedMonitorData = true;
|
|
341
|
-
};
|
|
342
|
-
|
|
343
|
-
logger.debug(
|
|
344
|
-
`${dataToProcess.monitorId.toString()} - Saving monitor metrics`,
|
|
345
|
-
);
|
|
346
|
-
|
|
347
|
-
try {
|
|
348
|
-
await MonitorMetricUtil.saveMonitorMetrics({
|
|
349
|
-
monitorId: monitor.id!,
|
|
350
|
-
projectId: monitor.projectId!,
|
|
351
|
-
dataToProcess: dataToProcess,
|
|
352
|
-
probeName: probeName || undefined,
|
|
353
|
-
monitorName: monitorName || undefined,
|
|
354
|
-
});
|
|
355
|
-
} catch (err) {
|
|
356
|
-
logger.error("Unable to save metrics");
|
|
357
|
-
logger.error(err);
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
logger.debug(
|
|
361
|
-
`${dataToProcess.monitorId.toString()} - Monitor metrics saved`,
|
|
362
|
-
);
|
|
363
|
-
|
|
364
|
-
const monitorSteps: MonitorSteps = monitor.monitorSteps!;
|
|
365
|
-
|
|
366
|
-
if (
|
|
367
|
-
!monitorSteps.data?.monitorStepsInstanceArray ||
|
|
368
|
-
monitorSteps.data?.monitorStepsInstanceArray.length === 0
|
|
369
|
-
) {
|
|
370
386
|
logger.debug(
|
|
371
|
-
`${dataToProcess.monitorId.toString()} -
|
|
387
|
+
`${dataToProcess.monitorId.toString()} - Monitor metrics saved`,
|
|
372
388
|
);
|
|
373
|
-
await persistLatestMonitorPayload();
|
|
374
389
|
|
|
375
|
-
|
|
376
|
-
monitorId: monitor.id!,
|
|
377
|
-
projectId: monitor.projectId!,
|
|
378
|
-
dataToProcess: dataToProcess,
|
|
379
|
-
});
|
|
380
|
-
return response;
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
logger.debug(
|
|
384
|
-
`${dataToProcess.monitorId.toString()} - Auto resolving criteria instances.`,
|
|
385
|
-
);
|
|
390
|
+
const monitorSteps: MonitorSteps = monitor.monitorSteps!;
|
|
386
391
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
.
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
.map((criteria: MonitorCriteria | undefined) => {
|
|
396
|
-
return [...(criteria?.data?.monitorCriteriaInstanceArray || [])];
|
|
397
|
-
})
|
|
398
|
-
.flat();
|
|
392
|
+
if (
|
|
393
|
+
!monitorSteps.data?.monitorStepsInstanceArray ||
|
|
394
|
+
monitorSteps.data?.monitorStepsInstanceArray.length === 0
|
|
395
|
+
) {
|
|
396
|
+
logger.debug(
|
|
397
|
+
`${dataToProcess.monitorId.toString()} - No monitoring steps.`,
|
|
398
|
+
);
|
|
399
|
+
await persistLatestMonitorPayload();
|
|
399
400
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
401
|
+
MonitorLogUtil.saveMonitorLog({
|
|
402
|
+
monitorId: monitor.id!,
|
|
403
|
+
projectId: monitor.projectId!,
|
|
404
|
+
dataToProcess: dataToProcess,
|
|
405
|
+
});
|
|
406
|
+
return response;
|
|
407
|
+
}
|
|
403
408
|
|
|
404
|
-
|
|
409
|
+
logger.debug(
|
|
410
|
+
`${dataToProcess.monitorId.toString()} - Auto resolving criteria instances.`,
|
|
411
|
+
);
|
|
405
412
|
|
|
406
|
-
|
|
407
|
-
|
|
413
|
+
const criteriaInstances: Array<MonitorCriteriaInstance> =
|
|
414
|
+
monitorSteps.data.monitorStepsInstanceArray
|
|
415
|
+
.map((step: MonitorStep) => {
|
|
416
|
+
return step.data?.monitorCriteria;
|
|
417
|
+
})
|
|
418
|
+
.filter((criteria: MonitorCriteria | undefined) => {
|
|
419
|
+
return Boolean(criteria);
|
|
420
|
+
})
|
|
421
|
+
.map((criteria: MonitorCriteria | undefined) => {
|
|
422
|
+
return [...(criteria?.data?.monitorCriteriaInstanceArray || [])];
|
|
423
|
+
})
|
|
424
|
+
.flat();
|
|
425
|
+
|
|
426
|
+
const autoResolveCriteriaInstanceIdIncidentIdsDictionary: Dictionary<
|
|
427
|
+
Array<string>
|
|
428
|
+
> = {};
|
|
429
|
+
|
|
430
|
+
const criteriaInstanceMap: Dictionary<MonitorCriteriaInstance> = {};
|
|
431
|
+
|
|
432
|
+
for (const criteriaInstance of criteriaInstances) {
|
|
433
|
+
criteriaInstanceMap[criteriaInstance.data?.id || ""] = criteriaInstance;
|
|
434
|
+
|
|
435
|
+
if (
|
|
436
|
+
criteriaInstance.data?.incidents &&
|
|
437
|
+
criteriaInstance.data?.incidents.length > 0
|
|
438
|
+
) {
|
|
439
|
+
for (const incidentTemplate of criteriaInstance.data!.incidents) {
|
|
440
|
+
if (incidentTemplate.autoResolveIncident) {
|
|
441
|
+
if (
|
|
442
|
+
!autoResolveCriteriaInstanceIdIncidentIdsDictionary[
|
|
443
|
+
criteriaInstance.data.id.toString()
|
|
444
|
+
]
|
|
445
|
+
) {
|
|
446
|
+
autoResolveCriteriaInstanceIdIncidentIdsDictionary[
|
|
447
|
+
criteriaInstance.data.id.toString()
|
|
448
|
+
] = [];
|
|
449
|
+
}
|
|
408
450
|
|
|
409
|
-
if (
|
|
410
|
-
criteriaInstance.data?.incidents &&
|
|
411
|
-
criteriaInstance.data?.incidents.length > 0
|
|
412
|
-
) {
|
|
413
|
-
for (const incidentTemplate of criteriaInstance.data!.incidents) {
|
|
414
|
-
if (incidentTemplate.autoResolveIncident) {
|
|
415
|
-
if (
|
|
416
|
-
!autoResolveCriteriaInstanceIdIncidentIdsDictionary[
|
|
417
|
-
criteriaInstance.data.id.toString()
|
|
418
|
-
]
|
|
419
|
-
) {
|
|
420
451
|
autoResolveCriteriaInstanceIdIncidentIdsDictionary[
|
|
421
452
|
criteriaInstance.data.id.toString()
|
|
422
|
-
]
|
|
453
|
+
]?.push(incidentTemplate.id);
|
|
423
454
|
}
|
|
424
|
-
|
|
425
|
-
autoResolveCriteriaInstanceIdIncidentIdsDictionary[
|
|
426
|
-
criteriaInstance.data.id.toString()
|
|
427
|
-
]?.push(incidentTemplate.id);
|
|
428
455
|
}
|
|
429
456
|
}
|
|
430
457
|
}
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
// alerts.
|
|
434
458
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
459
|
+
// alerts.
|
|
460
|
+
|
|
461
|
+
const autoResolveCriteriaInstanceIdAlertIdsDictionary: Dictionary<
|
|
462
|
+
Array<string>
|
|
463
|
+
> = {};
|
|
464
|
+
|
|
465
|
+
const criteriaInstanceAlertMap: Dictionary<MonitorCriteriaInstance> = {};
|
|
466
|
+
|
|
467
|
+
for (const criteriaInstance of criteriaInstances) {
|
|
468
|
+
criteriaInstanceAlertMap[criteriaInstance.data?.id || ""] =
|
|
469
|
+
criteriaInstance;
|
|
470
|
+
|
|
471
|
+
if (
|
|
472
|
+
criteriaInstance.data?.alerts &&
|
|
473
|
+
criteriaInstance.data?.alerts.length > 0
|
|
474
|
+
) {
|
|
475
|
+
for (const alertTemplate of criteriaInstance.data!.alerts) {
|
|
476
|
+
if (alertTemplate.autoResolveAlert) {
|
|
477
|
+
if (
|
|
478
|
+
!autoResolveCriteriaInstanceIdAlertIdsDictionary[
|
|
479
|
+
criteriaInstance.data.id.toString()
|
|
480
|
+
]
|
|
481
|
+
) {
|
|
482
|
+
autoResolveCriteriaInstanceIdAlertIdsDictionary[
|
|
483
|
+
criteriaInstance.data.id.toString()
|
|
484
|
+
] = [];
|
|
485
|
+
}
|
|
438
486
|
|
|
439
|
-
const criteriaInstanceAlertMap: Dictionary<MonitorCriteriaInstance> = {};
|
|
440
|
-
|
|
441
|
-
for (const criteriaInstance of criteriaInstances) {
|
|
442
|
-
criteriaInstanceAlertMap[criteriaInstance.data?.id || ""] =
|
|
443
|
-
criteriaInstance;
|
|
444
|
-
|
|
445
|
-
if (
|
|
446
|
-
criteriaInstance.data?.alerts &&
|
|
447
|
-
criteriaInstance.data?.alerts.length > 0
|
|
448
|
-
) {
|
|
449
|
-
for (const alertTemplate of criteriaInstance.data!.alerts) {
|
|
450
|
-
if (alertTemplate.autoResolveAlert) {
|
|
451
|
-
if (
|
|
452
|
-
!autoResolveCriteriaInstanceIdAlertIdsDictionary[
|
|
453
|
-
criteriaInstance.data.id.toString()
|
|
454
|
-
]
|
|
455
|
-
) {
|
|
456
487
|
autoResolveCriteriaInstanceIdAlertIdsDictionary[
|
|
457
488
|
criteriaInstance.data.id.toString()
|
|
458
|
-
]
|
|
489
|
+
]?.push(alertTemplate.id);
|
|
459
490
|
}
|
|
460
|
-
|
|
461
|
-
autoResolveCriteriaInstanceIdAlertIdsDictionary[
|
|
462
|
-
criteriaInstance.data.id.toString()
|
|
463
|
-
]?.push(alertTemplate.id);
|
|
464
491
|
}
|
|
465
492
|
}
|
|
466
493
|
}
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
const monitorStep: MonitorStep | undefined =
|
|
470
|
-
monitorSteps.data.monitorStepsInstanceArray[0];
|
|
471
494
|
|
|
472
|
-
|
|
495
|
+
const monitorStep: MonitorStep | undefined =
|
|
496
|
+
monitorSteps.data.monitorStepsInstanceArray[0];
|
|
473
497
|
|
|
474
|
-
if ((dataToProcess as ProbeMonitorResponse).monitorStepId) {
|
|
475
|
-
monitorSteps.data.monitorStepsInstanceArray.find(
|
|
476
|
-
(monitorStep: MonitorStep) => {
|
|
477
|
-
return (
|
|
478
|
-
monitorStep.id.toString() ===
|
|
479
|
-
(dataToProcess as ProbeMonitorResponse).monitorStepId.toString()
|
|
480
|
-
);
|
|
481
|
-
},
|
|
482
|
-
);
|
|
483
498
|
logger.debug(
|
|
484
|
-
`
|
|
485
|
-
);
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
if (!monitorStep) {
|
|
489
|
-
logger.debug("No steps found, ignoring everything.");
|
|
490
|
-
await persistLatestMonitorPayload();
|
|
491
|
-
|
|
492
|
-
MonitorLogUtil.saveMonitorLog({
|
|
493
|
-
monitorId: monitor.id!,
|
|
494
|
-
projectId: monitor.projectId!,
|
|
495
|
-
dataToProcess: dataToProcess,
|
|
496
|
-
});
|
|
497
|
-
return response;
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
// now process the monitor step
|
|
501
|
-
response.ingestedMonitorStepId = monitorStep.id;
|
|
502
|
-
logger.debug(`Ingested Monitor Step ID: ${monitorStep.id}`);
|
|
503
|
-
|
|
504
|
-
//find next monitor step after this one.
|
|
505
|
-
const nextMonitorStepIndex: number =
|
|
506
|
-
monitorSteps.data.monitorStepsInstanceArray.findIndex(
|
|
507
|
-
(step: MonitorStep) => {
|
|
508
|
-
return step.id.toString() === monitorStep.id.toString();
|
|
509
|
-
},
|
|
499
|
+
`Monitor Step: ${monitorStep ? monitorStep.id : "undefined"}`,
|
|
510
500
|
);
|
|
511
501
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
response = await MonitorCriteriaEvaluator.processMonitorStep({
|
|
523
|
-
dataToProcess: dataToProcess,
|
|
524
|
-
monitorStep: monitorStep,
|
|
525
|
-
monitor: monitor,
|
|
526
|
-
probeApiIngestResponse: response,
|
|
527
|
-
evaluationSummary: evaluationSummary,
|
|
528
|
-
});
|
|
529
|
-
|
|
530
|
-
// Check probe agreement for probe-based monitors
|
|
531
|
-
if (
|
|
532
|
-
monitor.monitorType &&
|
|
533
|
-
MonitorTypeHelper.isProbableMonitor(monitor.monitorType)
|
|
534
|
-
) {
|
|
535
|
-
const probeAgreementResult: ProbeAgreementResult =
|
|
536
|
-
await MonitorResourceUtil.checkProbeAgreement({
|
|
537
|
-
monitor: monitor,
|
|
538
|
-
monitorStep: monitorStep,
|
|
539
|
-
currentCriteriaMetId: response.criteriaMetId || null,
|
|
540
|
-
currentRootCause: response.rootCause || null,
|
|
541
|
-
});
|
|
542
|
-
|
|
543
|
-
// Add probe agreement event to evaluation summary
|
|
544
|
-
evaluationSummary.events.push({
|
|
545
|
-
type: "probe-agreement",
|
|
546
|
-
title: "Probe Agreement Check",
|
|
547
|
-
message: probeAgreementResult.hasAgreement
|
|
548
|
-
? `Probe agreement reached: ${probeAgreementResult.agreementCount}/${probeAgreementResult.requiredCount} probes agree (${probeAgreementResult.totalActiveProbes} active probes total).`
|
|
549
|
-
: `Probe agreement not reached: ${probeAgreementResult.agreementCount}/${probeAgreementResult.requiredCount} probes agree (${probeAgreementResult.totalActiveProbes} active probes total). Skipping status change.`,
|
|
550
|
-
at: OneUptimeDate.getCurrentDate(),
|
|
551
|
-
});
|
|
552
|
-
|
|
553
|
-
if (!probeAgreementResult.hasAgreement) {
|
|
502
|
+
if ((dataToProcess as ProbeMonitorResponse).monitorStepId) {
|
|
503
|
+
monitorSteps.data.monitorStepsInstanceArray.find(
|
|
504
|
+
(monitorStep: MonitorStep) => {
|
|
505
|
+
return (
|
|
506
|
+
monitorStep.id.toString() ===
|
|
507
|
+
(dataToProcess as ProbeMonitorResponse).monitorStepId.toString()
|
|
508
|
+
);
|
|
509
|
+
},
|
|
510
|
+
);
|
|
554
511
|
logger.debug(
|
|
555
|
-
|
|
512
|
+
`Found Monitor Step ID: ${(dataToProcess as ProbeMonitorResponse).monitorStepId}`,
|
|
556
513
|
);
|
|
514
|
+
}
|
|
557
515
|
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
try {
|
|
561
|
-
await Semaphore.release(mutex);
|
|
562
|
-
} catch (err) {
|
|
563
|
-
logger.error(err);
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
|
|
516
|
+
if (!monitorStep) {
|
|
517
|
+
logger.debug("No steps found, ignoring everything.");
|
|
567
518
|
await persistLatestMonitorPayload();
|
|
568
519
|
|
|
569
520
|
MonitorLogUtil.saveMonitorLog({
|
|
@@ -571,273 +522,347 @@ export default class MonitorResourceUtil {
|
|
|
571
522
|
projectId: monitor.projectId!,
|
|
572
523
|
dataToProcess: dataToProcess,
|
|
573
524
|
});
|
|
574
|
-
|
|
575
|
-
response.evaluationSummary = evaluationSummary;
|
|
576
525
|
return response;
|
|
577
526
|
}
|
|
578
527
|
|
|
579
|
-
//
|
|
580
|
-
response.
|
|
581
|
-
|
|
582
|
-
: undefined;
|
|
583
|
-
response.rootCause = probeAgreementResult.agreedRootCause;
|
|
528
|
+
// now process the monitor step
|
|
529
|
+
response.ingestedMonitorStepId = monitorStep.id;
|
|
530
|
+
logger.debug(`Ingested Monitor Step ID: ${monitorStep.id}`);
|
|
584
531
|
|
|
585
|
-
//
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
`;
|
|
593
|
-
}
|
|
594
|
-
}
|
|
532
|
+
//find next monitor step after this one.
|
|
533
|
+
const nextMonitorStepIndex: number =
|
|
534
|
+
monitorSteps.data.monitorStepsInstanceArray.findIndex(
|
|
535
|
+
(step: MonitorStep) => {
|
|
536
|
+
return step.id.toString() === monitorStep.id.toString();
|
|
537
|
+
},
|
|
538
|
+
);
|
|
595
539
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
);
|
|
540
|
+
response.nextMonitorStepId =
|
|
541
|
+
monitorSteps.data.monitorStepsInstanceArray[
|
|
542
|
+
nextMonitorStepIndex + 1
|
|
543
|
+
]?.id;
|
|
544
|
+
|
|
545
|
+
logger.debug(`Next Monitor Step ID: ${response.nextMonitorStepId}`);
|
|
546
|
+
|
|
547
|
+
// now process probe response monitors
|
|
602
548
|
logger.debug(
|
|
603
|
-
`${dataToProcess.monitorId.toString()} -
|
|
604
|
-
response.rootCause
|
|
605
|
-
}`,
|
|
549
|
+
`${dataToProcess.monitorId.toString()} - Processing monitor step...`,
|
|
606
550
|
);
|
|
607
551
|
|
|
608
|
-
|
|
552
|
+
response = await MonitorCriteriaEvaluator.processMonitorStep({
|
|
553
|
+
dataToProcess: dataToProcess,
|
|
554
|
+
monitorStep: monitorStep,
|
|
555
|
+
monitor: monitor,
|
|
556
|
+
probeApiIngestResponse: response,
|
|
557
|
+
evaluationSummary: evaluationSummary,
|
|
558
|
+
});
|
|
609
559
|
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
560
|
+
// Check probe agreement for probe-based monitors
|
|
561
|
+
if (
|
|
562
|
+
monitor.monitorType &&
|
|
563
|
+
MonitorTypeHelper.isProbableMonitor(monitor.monitorType)
|
|
564
|
+
) {
|
|
565
|
+
const probeAgreementResult: ProbeAgreementResult =
|
|
566
|
+
await MonitorResourceUtil.checkProbeAgreement({
|
|
567
|
+
monitor: monitor,
|
|
568
|
+
monitorStep: monitorStep,
|
|
569
|
+
currentCriteriaMetId: response.criteriaMetId || null,
|
|
570
|
+
currentRootCause: response.rootCause || null,
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
// Add probe agreement event to evaluation summary
|
|
574
|
+
evaluationSummary.events.push({
|
|
575
|
+
type: "probe-agreement",
|
|
576
|
+
title: "Probe Agreement Check",
|
|
577
|
+
message: probeAgreementResult.hasAgreement
|
|
578
|
+
? `Probe agreement reached: ${probeAgreementResult.agreementCount}/${probeAgreementResult.requiredCount} probes agree (${probeAgreementResult.totalActiveProbes} active probes total).`
|
|
579
|
+
: `Probe agreement not reached: ${probeAgreementResult.agreementCount}/${probeAgreementResult.requiredCount} probes agree (${probeAgreementResult.totalActiveProbes} active probes total). Skipping status change.`,
|
|
580
|
+
at: OneUptimeDate.getCurrentDate(),
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
if (!probeAgreementResult.hasAgreement) {
|
|
584
|
+
logger.debug(
|
|
585
|
+
`${dataToProcess.monitorId.toString()} - Probe agreement not met. ${probeAgreementResult.agreementCount}/${probeAgreementResult.requiredCount} probes agree. Skipping status change.`,
|
|
586
|
+
);
|
|
587
|
+
|
|
588
|
+
// Release lock and return early - no status change
|
|
589
|
+
await releaseMutex();
|
|
590
|
+
|
|
591
|
+
await persistLatestMonitorPayload();
|
|
592
|
+
|
|
593
|
+
MonitorLogUtil.saveMonitorLog({
|
|
594
|
+
monitorId: monitor.id!,
|
|
595
|
+
projectId: monitor.projectId!,
|
|
596
|
+
dataToProcess: dataToProcess,
|
|
597
|
+
});
|
|
598
|
+
|
|
599
|
+
response.evaluationSummary = evaluationSummary;
|
|
600
|
+
return response;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// Use the agreed criteria result
|
|
604
|
+
response.criteriaMetId = probeAgreementResult.agreedCriteriaId
|
|
605
|
+
? probeAgreementResult.agreedCriteriaId
|
|
606
|
+
: undefined;
|
|
607
|
+
response.rootCause = probeAgreementResult.agreedRootCause;
|
|
608
|
+
|
|
609
|
+
// Add probe names in agreement to the root cause
|
|
610
|
+
if (
|
|
611
|
+
response.rootCause &&
|
|
612
|
+
probeAgreementResult.agreedProbeNames.length > 0
|
|
613
|
+
) {
|
|
614
|
+
response.rootCause += `
|
|
615
|
+
**Probes in Agreement**: ${probeAgreementResult.agreedProbeNames.join(", ")}
|
|
616
|
+
`;
|
|
617
|
+
}
|
|
619
618
|
}
|
|
620
619
|
|
|
621
|
-
if (
|
|
622
|
-
telemetryQuery = {
|
|
623
|
-
telemetryQuery: (dataToProcess as TraceMonitorResponse).spanQuery,
|
|
624
|
-
telemetryType: TelemetryType.Trace,
|
|
625
|
-
metricViewData: null,
|
|
626
|
-
};
|
|
620
|
+
if (response.criteriaMetId && response.rootCause) {
|
|
627
621
|
logger.debug(
|
|
628
|
-
`${dataToProcess.monitorId.toString()} -
|
|
622
|
+
`${dataToProcess.monitorId.toString()} - Criteria met: ${
|
|
623
|
+
response.criteriaMetId
|
|
624
|
+
}`,
|
|
629
625
|
);
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
if (
|
|
633
|
-
dataToProcess &&
|
|
634
|
-
(dataToProcess as MetricMonitorResponse).metricViewConfig &&
|
|
635
|
-
(dataToProcess as MetricMonitorResponse).startAndEndDate
|
|
636
|
-
) {
|
|
637
|
-
telemetryQuery = {
|
|
638
|
-
telemetryQuery: null,
|
|
639
|
-
telemetryType: TelemetryType.Metric,
|
|
640
|
-
metricViewData: {
|
|
641
|
-
startAndEndDate:
|
|
642
|
-
(dataToProcess as MetricMonitorResponse).startAndEndDate || null,
|
|
643
|
-
queryConfigs: (dataToProcess as MetricMonitorResponse)
|
|
644
|
-
.metricViewConfig.queryConfigs,
|
|
645
|
-
formulaConfigs: (dataToProcess as MetricMonitorResponse)
|
|
646
|
-
.metricViewConfig.formulaConfigs,
|
|
647
|
-
},
|
|
648
|
-
};
|
|
649
626
|
logger.debug(
|
|
650
|
-
`${dataToProcess.monitorId.toString()} -
|
|
627
|
+
`${dataToProcess.monitorId.toString()} - Root cause: ${
|
|
628
|
+
response.rootCause
|
|
629
|
+
}`,
|
|
651
630
|
);
|
|
652
|
-
}
|
|
653
631
|
|
|
654
|
-
|
|
655
|
-
dataToProcess &&
|
|
656
|
-
(dataToProcess as ExceptionMonitorResponse).exceptionQuery
|
|
657
|
-
) {
|
|
658
|
-
const exceptionResponse: ExceptionMonitorResponse =
|
|
659
|
-
dataToProcess as ExceptionMonitorResponse;
|
|
660
|
-
telemetryQuery = {
|
|
661
|
-
telemetryQuery: exceptionResponse.exceptionQuery,
|
|
662
|
-
telemetryType: TelemetryType.Exception,
|
|
663
|
-
metricViewData: null,
|
|
664
|
-
};
|
|
632
|
+
let telemetryQuery: TelemetryQuery | undefined = undefined;
|
|
665
633
|
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
634
|
+
if (dataToProcess && (dataToProcess as LogMonitorResponse).logQuery) {
|
|
635
|
+
telemetryQuery = {
|
|
636
|
+
telemetryQuery: (dataToProcess as LogMonitorResponse).logQuery,
|
|
637
|
+
telemetryType: TelemetryType.Log,
|
|
638
|
+
metricViewData: null,
|
|
639
|
+
};
|
|
640
|
+
logger.debug(
|
|
641
|
+
`${dataToProcess.monitorId.toString()} - Log query found.`,
|
|
642
|
+
);
|
|
643
|
+
}
|
|
670
644
|
|
|
671
|
-
|
|
672
|
-
|
|
645
|
+
if (
|
|
646
|
+
dataToProcess &&
|
|
647
|
+
(dataToProcess as TraceMonitorResponse).spanQuery
|
|
648
|
+
) {
|
|
649
|
+
telemetryQuery = {
|
|
650
|
+
telemetryQuery: (dataToProcess as TraceMonitorResponse).spanQuery,
|
|
651
|
+
telemetryType: TelemetryType.Trace,
|
|
652
|
+
metricViewData: null,
|
|
653
|
+
};
|
|
654
|
+
logger.debug(
|
|
655
|
+
`${dataToProcess.monitorId.toString()} - Span query found.`,
|
|
656
|
+
);
|
|
657
|
+
}
|
|
673
658
|
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
659
|
+
if (
|
|
660
|
+
dataToProcess &&
|
|
661
|
+
(dataToProcess as MetricMonitorResponse).metricViewConfig &&
|
|
662
|
+
(dataToProcess as MetricMonitorResponse).startAndEndDate
|
|
663
|
+
) {
|
|
664
|
+
telemetryQuery = {
|
|
665
|
+
telemetryQuery: null,
|
|
666
|
+
telemetryType: TelemetryType.Metric,
|
|
667
|
+
metricViewData: {
|
|
668
|
+
startAndEndDate:
|
|
669
|
+
(dataToProcess as MetricMonitorResponse).startAndEndDate ||
|
|
670
|
+
null,
|
|
671
|
+
queryConfigs: (dataToProcess as MetricMonitorResponse)
|
|
672
|
+
.metricViewConfig.queryConfigs,
|
|
673
|
+
formulaConfigs: (dataToProcess as MetricMonitorResponse)
|
|
674
|
+
.metricViewConfig.formulaConfigs,
|
|
675
|
+
},
|
|
676
|
+
};
|
|
677
|
+
logger.debug(
|
|
678
|
+
`${dataToProcess.monitorId.toString()} - Span query found.`,
|
|
679
|
+
);
|
|
680
|
+
}
|
|
684
681
|
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
682
|
+
if (
|
|
683
|
+
dataToProcess &&
|
|
684
|
+
(dataToProcess as ExceptionMonitorResponse).exceptionQuery
|
|
685
|
+
) {
|
|
686
|
+
const exceptionResponse: ExceptionMonitorResponse =
|
|
687
|
+
dataToProcess as ExceptionMonitorResponse;
|
|
688
|
+
telemetryQuery = {
|
|
689
|
+
telemetryQuery: exceptionResponse.exceptionQuery,
|
|
690
|
+
telemetryType: TelemetryType.Exception,
|
|
691
|
+
metricViewData: null,
|
|
692
|
+
};
|
|
690
693
|
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
? `Monitor status changed to "${changedStatusName}" because criteria "${matchedCriteriaInstance.data?.name || "Unnamed criteria"}" was met.`
|
|
696
|
-
: `Monitor status changed because criteria "${matchedCriteriaInstance.data?.name || "Unnamed criteria"}" was met.`,
|
|
697
|
-
relatedCriteriaId: matchedCriteriaInstance.data?.id,
|
|
698
|
-
at: OneUptimeDate.getCurrentDate(),
|
|
699
|
-
});
|
|
700
|
-
}
|
|
694
|
+
logger.debug(
|
|
695
|
+
`${dataToProcess.monitorId.toString()} - Exception query found.`,
|
|
696
|
+
);
|
|
697
|
+
}
|
|
701
698
|
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
rootCause: response.rootCause,
|
|
705
|
-
dataToProcess: dataToProcess,
|
|
706
|
-
autoResolveCriteriaInstanceIdIncidentIdsDictionary,
|
|
707
|
-
criteriaInstance: matchedCriteriaInstance,
|
|
708
|
-
evaluationSummary: evaluationSummary,
|
|
709
|
-
props: {
|
|
710
|
-
telemetryQuery: telemetryQuery,
|
|
711
|
-
},
|
|
712
|
-
matchesPerSeries: response.perSeriesMatches,
|
|
713
|
-
});
|
|
699
|
+
const matchedCriteriaInstance: MonitorCriteriaInstance =
|
|
700
|
+
criteriaInstanceMap[response.criteriaMetId!]!;
|
|
714
701
|
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
matchesPerSeries: response.perSeriesMatches,
|
|
726
|
-
});
|
|
727
|
-
} else if (
|
|
728
|
-
!response.criteriaMetId &&
|
|
729
|
-
monitorSteps.data.defaultMonitorStatusId &&
|
|
730
|
-
monitor.currentMonitorStatusId?.toString() !==
|
|
731
|
-
monitorSteps.data.defaultMonitorStatusId.toString()
|
|
732
|
-
) {
|
|
733
|
-
logger.debug(
|
|
734
|
-
`${dataToProcess.monitorId.toString()} - No criteria met. Change to default status.`,
|
|
735
|
-
);
|
|
702
|
+
const monitorStatusTimelineChange: MonitorStatusTimeline | null =
|
|
703
|
+
await MonitorStatusTimelineUtil.updateMonitorStatusTimeline({
|
|
704
|
+
monitor: monitor,
|
|
705
|
+
rootCause: response.rootCause,
|
|
706
|
+
dataToProcess: dataToProcess,
|
|
707
|
+
criteriaInstance: matchedCriteriaInstance,
|
|
708
|
+
props: {
|
|
709
|
+
telemetryQuery: telemetryQuery,
|
|
710
|
+
},
|
|
711
|
+
});
|
|
736
712
|
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
dataToProcess: dataToProcess,
|
|
743
|
-
evaluationSummary: evaluationSummary,
|
|
744
|
-
});
|
|
713
|
+
if (monitorStatusTimelineChange) {
|
|
714
|
+
const changedStatusName: string | null = await getMonitorStatusName(
|
|
715
|
+
matchedCriteriaInstance.data?.monitorStatusId ||
|
|
716
|
+
monitorStatusTimelineChange.monitorStatusId,
|
|
717
|
+
);
|
|
745
718
|
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
719
|
+
evaluationSummary.events.push({
|
|
720
|
+
type: "monitor-status-changed",
|
|
721
|
+
title: "Monitor status updated",
|
|
722
|
+
message: changedStatusName
|
|
723
|
+
? `Monitor status changed to "${changedStatusName}" because criteria "${matchedCriteriaInstance.data?.name || "Unnamed criteria"}" was met.`
|
|
724
|
+
: `Monitor status changed because criteria "${matchedCriteriaInstance.data?.name || "Unnamed criteria"}" was met.`,
|
|
725
|
+
relatedCriteriaId: matchedCriteriaInstance.data?.id,
|
|
726
|
+
at: OneUptimeDate.getCurrentDate(),
|
|
727
|
+
});
|
|
728
|
+
}
|
|
754
729
|
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
select: {
|
|
763
|
-
_id: true,
|
|
764
|
-
monitorStatusId: true,
|
|
765
|
-
},
|
|
766
|
-
sort: {
|
|
767
|
-
startsAt: SortOrder.Descending,
|
|
768
|
-
},
|
|
730
|
+
await MonitorIncident.criteriaMetCreateIncidentsAndUpdateMonitorStatus({
|
|
731
|
+
monitor: monitor,
|
|
732
|
+
rootCause: response.rootCause,
|
|
733
|
+
dataToProcess: dataToProcess,
|
|
734
|
+
autoResolveCriteriaInstanceIdIncidentIdsDictionary,
|
|
735
|
+
criteriaInstance: matchedCriteriaInstance,
|
|
736
|
+
evaluationSummary: evaluationSummary,
|
|
769
737
|
props: {
|
|
770
|
-
|
|
738
|
+
telemetryQuery: telemetryQuery,
|
|
771
739
|
},
|
|
740
|
+
matchesPerSeries: response.perSeriesMatches,
|
|
772
741
|
});
|
|
773
742
|
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
* status is same as last status. do not create new status timeline.
|
|
782
|
-
* do nothing! status is same as last status.
|
|
783
|
-
*/
|
|
784
|
-
} else {
|
|
785
|
-
// if no criteria is met then update monitor to default state.
|
|
786
|
-
const monitorStatusTimeline: MonitorStatusTimeline =
|
|
787
|
-
new MonitorStatusTimeline();
|
|
788
|
-
monitorStatusTimeline.monitorId = monitor.id!;
|
|
789
|
-
monitorStatusTimeline.monitorStatusId =
|
|
790
|
-
monitorSteps.data.defaultMonitorStatusId!;
|
|
791
|
-
monitorStatusTimeline.projectId = monitor.projectId!;
|
|
792
|
-
monitorStatusTimeline.isOwnerNotified = true; // no need to notify owner as this is default status.
|
|
793
|
-
monitorStatusTimeline.statusChangeLog = JSON.parse(
|
|
794
|
-
JSON.stringify(dataToProcess),
|
|
795
|
-
);
|
|
796
|
-
monitorStatusTimeline.rootCause =
|
|
797
|
-
"No monitoring criteria met. Change to default status. ";
|
|
798
|
-
|
|
799
|
-
await MonitorStatusTimelineService.create({
|
|
800
|
-
data: monitorStatusTimeline,
|
|
743
|
+
await MonitorAlert.criteriaMetCreateAlertsAndUpdateMonitorStatus({
|
|
744
|
+
monitor: monitor,
|
|
745
|
+
rootCause: response.rootCause,
|
|
746
|
+
dataToProcess: dataToProcess,
|
|
747
|
+
autoResolveCriteriaInstanceIdAlertIdsDictionary,
|
|
748
|
+
criteriaInstance: criteriaInstanceAlertMap[response.criteriaMetId!]!,
|
|
749
|
+
evaluationSummary: evaluationSummary,
|
|
801
750
|
props: {
|
|
802
|
-
|
|
751
|
+
telemetryQuery: telemetryQuery,
|
|
803
752
|
},
|
|
753
|
+
matchesPerSeries: response.perSeriesMatches,
|
|
804
754
|
});
|
|
755
|
+
} else if (
|
|
756
|
+
!response.criteriaMetId &&
|
|
757
|
+
monitorSteps.data.defaultMonitorStatusId &&
|
|
758
|
+
monitor.currentMonitorStatusId?.toString() !==
|
|
759
|
+
monitorSteps.data.defaultMonitorStatusId.toString()
|
|
760
|
+
) {
|
|
805
761
|
logger.debug(
|
|
806
|
-
`${dataToProcess.monitorId.toString()} -
|
|
762
|
+
`${dataToProcess.monitorId.toString()} - No criteria met. Change to default status.`,
|
|
807
763
|
);
|
|
808
764
|
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
765
|
+
await MonitorIncident.checkOpenIncidentsAndCloseIfResolved({
|
|
766
|
+
monitorId: monitor.id!,
|
|
767
|
+
autoResolveCriteriaInstanceIdIncidentIdsDictionary,
|
|
768
|
+
rootCause: "No monitoring criteria met. Change to default status.",
|
|
769
|
+
criteriaInstance: null, // no criteria met!
|
|
770
|
+
dataToProcess: dataToProcess,
|
|
771
|
+
evaluationSummary: evaluationSummary,
|
|
772
|
+
});
|
|
812
773
|
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
774
|
+
await MonitorAlert.checkOpenAlertsAndCloseIfResolved({
|
|
775
|
+
monitorId: monitor.id!,
|
|
776
|
+
autoResolveCriteriaInstanceIdAlertIdsDictionary,
|
|
777
|
+
rootCause: "No monitoring criteria met. Change to default status.",
|
|
778
|
+
criteriaInstance: null, // no criteria met!
|
|
779
|
+
dataToProcess: dataToProcess,
|
|
780
|
+
evaluationSummary: evaluationSummary,
|
|
820
781
|
});
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
782
|
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
783
|
+
// get last monitor status timeline.
|
|
784
|
+
const lastMonitorStatusTimeline: MonitorStatusTimeline | null =
|
|
785
|
+
await MonitorStatusTimelineService.findOneBy({
|
|
786
|
+
query: {
|
|
787
|
+
monitorId: monitor.id!,
|
|
788
|
+
projectId: monitor.projectId!,
|
|
789
|
+
},
|
|
790
|
+
select: {
|
|
791
|
+
_id: true,
|
|
792
|
+
monitorStatusId: true,
|
|
793
|
+
},
|
|
794
|
+
sort: {
|
|
795
|
+
startsAt: SortOrder.Descending,
|
|
796
|
+
},
|
|
797
|
+
props: {
|
|
798
|
+
isRoot: true,
|
|
799
|
+
},
|
|
800
|
+
});
|
|
801
|
+
|
|
802
|
+
if (
|
|
803
|
+
lastMonitorStatusTimeline &&
|
|
804
|
+
lastMonitorStatusTimeline.monitorStatusId &&
|
|
805
|
+
lastMonitorStatusTimeline.monitorStatusId.toString() ===
|
|
806
|
+
monitorSteps.data.defaultMonitorStatusId.toString()
|
|
807
|
+
) {
|
|
808
|
+
/*
|
|
809
|
+
* status is same as last status. do not create new status timeline.
|
|
810
|
+
* do nothing! status is same as last status.
|
|
811
|
+
*/
|
|
812
|
+
} else {
|
|
813
|
+
// if no criteria is met then update monitor to default state.
|
|
814
|
+
const monitorStatusTimeline: MonitorStatusTimeline =
|
|
815
|
+
new MonitorStatusTimeline();
|
|
816
|
+
monitorStatusTimeline.monitorId = monitor.id!;
|
|
817
|
+
monitorStatusTimeline.monitorStatusId =
|
|
818
|
+
monitorSteps.data.defaultMonitorStatusId!;
|
|
819
|
+
monitorStatusTimeline.projectId = monitor.projectId!;
|
|
820
|
+
monitorStatusTimeline.isOwnerNotified = true; // no need to notify owner as this is default status.
|
|
821
|
+
monitorStatusTimeline.statusChangeLog = JSON.parse(
|
|
822
|
+
JSON.stringify(dataToProcess),
|
|
823
|
+
);
|
|
824
|
+
monitorStatusTimeline.rootCause =
|
|
825
|
+
"No monitoring criteria met. Change to default status. ";
|
|
826
|
+
|
|
827
|
+
await MonitorStatusTimelineService.create({
|
|
828
|
+
data: monitorStatusTimeline,
|
|
829
|
+
props: {
|
|
830
|
+
isRoot: true,
|
|
831
|
+
},
|
|
832
|
+
});
|
|
833
|
+
logger.debug(
|
|
834
|
+
`${dataToProcess.monitorId.toString()} - Monitor status updated to default.`,
|
|
835
|
+
);
|
|
836
|
+
|
|
837
|
+
const defaultStatusName: string | null = await getMonitorStatusName(
|
|
838
|
+
monitorSteps.data.defaultMonitorStatusId,
|
|
839
|
+
);
|
|
840
|
+
|
|
841
|
+
evaluationSummary.events.push({
|
|
842
|
+
type: "monitor-status-changed",
|
|
843
|
+
title: "Monitor status reverted",
|
|
844
|
+
message: defaultStatusName
|
|
845
|
+
? `Monitor status reverted to "${defaultStatusName}" because no monitoring criteria were met.`
|
|
846
|
+
: "Monitor status reverted to its default state because no monitoring criteria were met.",
|
|
847
|
+
at: OneUptimeDate.getCurrentDate(),
|
|
848
|
+
});
|
|
849
|
+
}
|
|
829
850
|
}
|
|
830
|
-
}
|
|
831
851
|
|
|
832
|
-
|
|
852
|
+
await releaseMutex();
|
|
833
853
|
|
|
834
|
-
|
|
835
|
-
monitorId: monitor.id!,
|
|
836
|
-
projectId: monitor.projectId!,
|
|
837
|
-
dataToProcess: dataToProcess,
|
|
838
|
-
});
|
|
854
|
+
await persistLatestMonitorPayload();
|
|
839
855
|
|
|
840
|
-
|
|
856
|
+
MonitorLogUtil.saveMonitorLog({
|
|
857
|
+
monitorId: monitor.id!,
|
|
858
|
+
projectId: monitor.projectId!,
|
|
859
|
+
dataToProcess: dataToProcess,
|
|
860
|
+
});
|
|
861
|
+
|
|
862
|
+
return response;
|
|
863
|
+
} finally {
|
|
864
|
+
await releaseMutex();
|
|
865
|
+
}
|
|
841
866
|
}
|
|
842
867
|
|
|
843
868
|
@CaptureSpan()
|