From c85d9b83729e3c0a8a47772b69e425ace608e6c4 Mon Sep 17 00:00:00 2001 From: Simon Larsen Date: Thu, 5 Oct 2023 15:59:10 +0100 Subject: [PATCH] add docs --- .../Utils/Probe/ProbeMonitorResponse.ts | 178 ++++++++++-------- .../Form/Monitor/CriteriaFilter.tsx | 11 +- Docs/Monitor/JavaScriptExpression.md | 29 ++- Probe/Utils/Monitors/Monitor.ts | 2 +- 4 files changed, 124 insertions(+), 96 deletions(-) diff --git a/CommonServer/Utils/Probe/ProbeMonitorResponse.ts b/CommonServer/Utils/Probe/ProbeMonitorResponse.ts index 5e75c4fac8..c7232f5e4a 100644 --- a/CommonServer/Utils/Probe/ProbeMonitorResponse.ts +++ b/CommonServer/Utils/Probe/ProbeMonitorResponse.ts @@ -105,8 +105,7 @@ export default class ProbeMonitorResponseService { // get last log. We do this because there are many monitoring steps and we need to store those. logger.info( - `${dataToProcess.monitorId.toString()} - monitor type ${ - monitor.monitorType + `${dataToProcess.monitorId.toString()} - monitor type ${monitor.monitorType }` ); @@ -133,6 +132,7 @@ export default class ProbeMonitorResponseService { }, }); + if (!monitorProbe) { throw new BadDataException( 'Probe is not assigned to this monitor' @@ -229,7 +229,7 @@ export default class ProbeMonitorResponseService { if (incidentTemplate.autoResolveIncident) { if ( !autoResolveCriteriaInstanceIdIncidentIdsDictionary[ - criteriaInstance.data.id.toString() + criteriaInstance.data.id.toString() ] ) { autoResolveCriteriaInstanceIdIncidentIdsDictionary[ @@ -294,13 +294,11 @@ export default class ProbeMonitorResponseService { if (response.criteriaMetId && response.rootCause) { logger.info( - `${dataToProcess.monitorId.toString()} - Criteria met: ${ - response.criteriaMetId + `${dataToProcess.monitorId.toString()} - Criteria met: ${response.criteriaMetId }` ); logger.info( - `${dataToProcess.monitorId.toString()} - Root cause: ${ - response.rootCause + `${dataToProcess.monitorId.toString()} - Root cause: ${response.rootCause }` ); @@ -315,7 +313,7 @@ export default class ProbeMonitorResponseService { !response.criteriaMetId && monitorSteps.data.defaultMonitorStatusId && monitor.currentMonitorStatusId?.toString() !== - monitorSteps.data.defaultMonitorStatusId.toString() + monitorSteps.data.defaultMonitorStatusId.toString() ) { logger.info( `${dataToProcess.monitorId.toString()} - No criteria met. Change to default status.` @@ -422,7 +420,7 @@ export default class ProbeMonitorResponseService { input.criteriaInstance.data?.changeMonitorStatus && input.criteriaInstance.data?.monitorStatusId && input.criteriaInstance.data?.monitorStatusId.toString() !== - input.monitor.currentMonitorStatusId?.toString() + input.monitor.currentMonitorStatusId?.toString() ) { logger.info( `${input.monitor.id?.toString()} - Change monitor status to ${input.criteriaInstance.data?.monitorStatusId.toString()}` @@ -476,9 +474,9 @@ export default class ProbeMonitorResponseService { openIncidents.find((incident: Incident) => { return ( incident.createdCriteriaId === - input.criteriaInstance.data?.id.toString() && + input.criteriaInstance.data?.id.toString() && incident.createdIncidentTemplateId === - criteriaIncident.id.toString() + criteriaIncident.id.toString() ); }); @@ -644,7 +642,7 @@ export default class ProbeMonitorResponseService { if ( input.autoResolveCriteriaInstanceIdIncidentIdsDictionary[ - input.openIncident.createdCriteriaId?.toString() + input.openIncident.createdCriteriaId?.toString() ] ) { if ( @@ -766,7 +764,7 @@ export default class ProbeMonitorResponseService { if ( FilterCondition.Any === - input.criteriaInstance.data?.filterCondition && + input.criteriaInstance.data?.filterCondition && didMeetCriteria === true ) { finalResult = rootCause; @@ -774,7 +772,7 @@ export default class ProbeMonitorResponseService { if ( FilterCondition.All === - input.criteriaInstance.data?.filterCondition && + input.criteriaInstance.data?.filterCondition && didMeetCriteria === false ) { finalResult = null; @@ -783,7 +781,7 @@ export default class ProbeMonitorResponseService { if ( FilterCondition.All === - input.criteriaInstance.data?.filterCondition && + input.criteriaInstance.data?.filterCondition && didMeetCriteria && rootCause ) { @@ -807,25 +805,45 @@ export default class ProbeMonitorResponseService { let value: number | string | undefined = input.criteriaFilter.value; //check is online filter + + if (input.criteriaFilter.checkOn === CheckOn.JavaScriptExpression) { + + debugger; + let storageMap: JSONObject = { } - if(input.monitor.monitorType === MonitorType.API || input.monitor.monitorType === MonitorType.Website){ + if (input.monitor.monitorType === MonitorType.API || input.monitor.monitorType === MonitorType.Website) { + + // try to parse json + let responseBody: JSONObject | null = null; + try { + responseBody = JSON.parse((input.dataToProcess as ProbeMonitorResponse).responseBody as string || '{}'); + } catch (err) { + responseBody = (input.dataToProcess as ProbeMonitorResponse).responseBody as JSONObject; + } + + + if (typeof responseBody === Typeof.String && (responseBody?.toString()) === '') { + // if empty string then set to empty object. + responseBody = {}; + } + storageMap = { - responseBody: (input.dataToProcess as ProbeMonitorResponse).responseBody, - responseHeaders: (input.dataToProcess as ProbeMonitorResponse).responseHeaders, - responseStatusCode: (input.dataToProcess as ProbeMonitorResponse).responseCode, - responseTimeInMs: (input.dataToProcess as ProbeMonitorResponse).responseTimeInMs, - isOnline: (input.dataToProcess as ProbeMonitorResponse).isOnline, + responseBody: responseBody, + responseHeaders: (input.dataToProcess as ProbeMonitorResponse).responseHeaders, + responseStatusCode: (input.dataToProcess as ProbeMonitorResponse).responseCode, + responseTimeInMs: (input.dataToProcess as ProbeMonitorResponse).responseTimeInMs, + isOnline: (input.dataToProcess as ProbeMonitorResponse).isOnline, }; } - if(input.monitor.monitorType === MonitorType.IncomingRequest){ + if (input.monitor.monitorType === MonitorType.IncomingRequest) { storageMap = { - requestBody: (input.dataToProcess as IncomingMonitorRequest).requestBody, - requestHeaders: (input.dataToProcess as IncomingMonitorRequest).requestHeaders, + requestBody: (input.dataToProcess as IncomingMonitorRequest).requestBody, + requestHeaders: (input.dataToProcess as IncomingMonitorRequest).requestHeaders, }; } @@ -834,16 +852,22 @@ export default class ProbeMonitorResponseService { expression = VMUtil.replaceValueInPlace(storageMap, expression, false); // now pass this to the VM. let code: string = `return Boolean(${expression});`; + let result: any = null; + + try { + result = await VMUtil.runCodeInSandbox(code, { + timeout: 1000, + allowAsync: false, + args: {}, + includeHttpPackage: false + }); + } catch (err) { + logger.error(err); + return null; + } - const result = await VMUtil.runCodeInSandbox(code, { - timeout: 1000, - allowAsync: false, - args: {}, - includeHttpPackage: false - }); - - if(result === false){ - return `JavaScript Expression - ${expression} - returned false.`; + if (result) { + return `JavaScript Expression - ${expression} - evaluated to true.`; } return null; // if true then return null. @@ -895,10 +919,9 @@ export default class ProbeMonitorResponseService { (input.dataToProcess as ProbeMonitorResponse) .responseTimeInMs! > (value as number) ) { - return `Response time is ${ - (input.dataToProcess as ProbeMonitorResponse) - .responseTimeInMs - } ms which is greater than the criteria value of ${value} ms.`; + return `Response time is ${(input.dataToProcess as ProbeMonitorResponse) + .responseTimeInMs + } ms which is greater than the criteria value of ${value} ms.`; } return null; } @@ -910,10 +933,9 @@ export default class ProbeMonitorResponseService { (input.dataToProcess as ProbeMonitorResponse) .responseTimeInMs! < (value as number) ) { - return `Response time is ${ - (input.dataToProcess as ProbeMonitorResponse) - .responseTimeInMs - } ms which is less than the criteria value of ${value} ms.`; + return `Response time is ${(input.dataToProcess as ProbeMonitorResponse) + .responseTimeInMs + } ms which is less than the criteria value of ${value} ms.`; } return null; } @@ -925,10 +947,9 @@ export default class ProbeMonitorResponseService { (input.dataToProcess as ProbeMonitorResponse) .responseTimeInMs === (value as number) ) { - return `Response time is ${ - (input.dataToProcess as ProbeMonitorResponse) - .responseTimeInMs - } ms.`; + return `Response time is ${(input.dataToProcess as ProbeMonitorResponse) + .responseTimeInMs + } ms.`; } return null; } @@ -940,10 +961,9 @@ export default class ProbeMonitorResponseService { (input.dataToProcess as ProbeMonitorResponse) .responseTimeInMs !== (value as number) ) { - return `Response time is ${ - (input.dataToProcess as ProbeMonitorResponse) - .responseTimeInMs - } ms which is not equal to the criteria value of ${value} ms.`; + return `Response time is ${(input.dataToProcess as ProbeMonitorResponse) + .responseTimeInMs + } ms which is not equal to the criteria value of ${value} ms.`; } return null; } @@ -958,10 +978,9 @@ export default class ProbeMonitorResponseService { (input.dataToProcess as ProbeMonitorResponse) .responseTimeInMs! >= (value as number) ) { - return `Response time is ${ - (input.dataToProcess as ProbeMonitorResponse) - .responseTimeInMs - } ms which is greater than or equal to the criteria value of ${value} ms.`; + return `Response time is ${(input.dataToProcess as ProbeMonitorResponse) + .responseTimeInMs + } ms which is greater than or equal to the criteria value of ${value} ms.`; } return null; } @@ -975,10 +994,9 @@ export default class ProbeMonitorResponseService { (input.dataToProcess as ProbeMonitorResponse) .responseTimeInMs! <= (value as number) ) { - return `Response time is ${ - (input.dataToProcess as ProbeMonitorResponse) - .responseTimeInMs - } ms which is less than or equal to the criteria value of ${value} ms.`; + return `Response time is ${(input.dataToProcess as ProbeMonitorResponse) + .responseTimeInMs + } ms which is less than or equal to the criteria value of ${value} ms.`; } return null; } @@ -1010,10 +1028,9 @@ export default class ProbeMonitorResponseService { (input.dataToProcess as ProbeMonitorResponse) .responseCode! > (value as number) ) { - return `Response status code is ${ - (input.dataToProcess as ProbeMonitorResponse) - .responseCode - } which is greater than the criteria value of ${value}.`; + return `Response status code is ${(input.dataToProcess as ProbeMonitorResponse) + .responseCode + } which is greater than the criteria value of ${value}.`; } return null; } @@ -1025,10 +1042,9 @@ export default class ProbeMonitorResponseService { (input.dataToProcess as ProbeMonitorResponse) .responseCode! < (value as number) ) { - return `Response status code is ${ - (input.dataToProcess as ProbeMonitorResponse) - .responseCode - } which is less than the criteria value of ${value}.`; + return `Response status code is ${(input.dataToProcess as ProbeMonitorResponse) + .responseCode + } which is less than the criteria value of ${value}.`; } return null; } @@ -1040,10 +1056,9 @@ export default class ProbeMonitorResponseService { (input.dataToProcess as ProbeMonitorResponse) .responseCode === (value as number) ) { - return `Response status code is ${ - (input.dataToProcess as ProbeMonitorResponse) - .responseCode - }.`; + return `Response status code is ${(input.dataToProcess as ProbeMonitorResponse) + .responseCode + }.`; } return null; } @@ -1055,10 +1070,9 @@ export default class ProbeMonitorResponseService { (input.dataToProcess as ProbeMonitorResponse) .responseCode !== (value as number) ) { - return `Response status code is ${ - (input.dataToProcess as ProbeMonitorResponse) - .responseCode - } which is not equal to the criteria value of ${value}.`; + return `Response status code is ${(input.dataToProcess as ProbeMonitorResponse) + .responseCode + } which is not equal to the criteria value of ${value}.`; } return null; } @@ -1073,10 +1087,9 @@ export default class ProbeMonitorResponseService { (input.dataToProcess as ProbeMonitorResponse) .responseCode! >= (value as number) ) { - return `Response status code is ${ - (input.dataToProcess as ProbeMonitorResponse) - .responseCode - } which is greater than or equal to the criteria value of ${value}.`; + return `Response status code is ${(input.dataToProcess as ProbeMonitorResponse) + .responseCode + } which is greater than or equal to the criteria value of ${value}.`; } return null; } @@ -1090,10 +1103,9 @@ export default class ProbeMonitorResponseService { (input.dataToProcess as ProbeMonitorResponse) .responseCode! <= (value as number) ) { - return `Response status code is ${ - (input.dataToProcess as ProbeMonitorResponse) - .responseCode - } which is less than or equal to the criteria value of ${value}.`; + return `Response status code is ${(input.dataToProcess as ProbeMonitorResponse) + .responseCode + } which is less than or equal to the criteria value of ${value}.`; } return null; } @@ -1139,7 +1151,7 @@ export default class ProbeMonitorResponseService { if (input.criteriaFilter.checkOn === CheckOn.ResponseHeader) { const headerKeys: Array = Object.keys( (input.dataToProcess as ProbeMonitorResponse).responseHeaders || - {} + {} ).map((key: string) => { return key.toLowerCase(); }); @@ -1171,7 +1183,7 @@ export default class ProbeMonitorResponseService { if (input.criteriaFilter.checkOn === CheckOn.ResponseHeaderValue) { const headerValues: Array = Object.values( (input.dataToProcess as ProbeMonitorResponse).responseHeaders || - {} + {} ).map((key: string) => { return key.toLowerCase(); }); diff --git a/Dashboard/src/Components/Form/Monitor/CriteriaFilter.tsx b/Dashboard/src/Components/Form/Monitor/CriteriaFilter.tsx index dfa1b7f4a7..17b7a2785d 100644 --- a/Dashboard/src/Components/Form/Monitor/CriteriaFilter.tsx +++ b/Dashboard/src/Components/Form/Monitor/CriteriaFilter.tsx @@ -11,8 +11,10 @@ import Dropdown, { DropdownValue, } from 'CommonUI/src/Components/Dropdown/Dropdown'; import Input from 'CommonUI/src/Components/Input/Input'; +import Link from 'CommonUI/src/Components/Link/Link'; import DropdownUtil from 'CommonUI/src/Utils/Dropdown'; import React, { FunctionComponent, ReactElement, useEffect } from 'react'; +import URL from 'Common/Types/API/URL'; export interface ComponentProps { initialValue: CriteriaFilter | undefined; @@ -150,7 +152,12 @@ const CriteriaFilterElement: FunctionComponent = ( return i.value === FilterType.EvaluatesToTrue; }); - setValuePlaceholder('{{response.body.result}} === true'); + if (props.monitorType === MonitorType.IncomingRequest) { + setValuePlaceholder('{{requestBody.result}} === true'); + } else { + setValuePlaceholder('{{responseBody.result}} === true'); + } + } if (criteriaFilter?.checkOn === CheckOn.ResponseStatusCode) { @@ -267,7 +274,7 @@ const CriteriaFilterElement: FunctionComponent = ( {criteriaFilter?.checkOn === CheckOn.JavaScriptExpression ? ( -
Some documentation
+
Read documentation for using JavaScript exporession here.
) : ( <> )} diff --git a/Docs/Monitor/JavaScriptExpression.md b/Docs/Monitor/JavaScriptExpression.md index 17dae6dc4f..cc95f79ffe 100644 --- a/Docs/Monitor/JavaScriptExpression.md +++ b/Docs/Monitor/JavaScriptExpression.md @@ -20,24 +20,28 @@ The following variables are available in the context of the monitored object: The following example shows how to use a JavaScript expression to monitor a website for a specific string in the response body: ```javascript -responseBody.item === "hello" +"{{responseBody.item}}" === "hello" // or you can use response headers -responseHeaders.contentType === "text/html" +"{{responseHeaders.contentType}} === "text/html" // you can also use regular expressions -responseBody.match(/hello/) +"{{responseBody.item}}".match(/hello/) // you can also use response status code -responseStatusCode === 200 +{{responseStatusCode}} === 200 // you can combine multiple expressions using logical operators -responseBody.item === "hello" && responseStatusCode === 200 +"{{responseBody.item}}" === "hello" && {{responseStatusCode}} === 200 + +// for arrays you can use the following + +"{{responseBody.items[0].name}}" === "hello" ``` ### Incoming Request monitors @@ -55,21 +59,26 @@ The following variables are available in the context of the monitored object: The following example shows how to use a JavaScript expression to monitor an incoming request for a specific string in the request body: ```javascript -requestBody.item === "hello" +"{{requestBody.item}}" === "hello" // or you can use request headers -requestHeaders.contentType === "text/html" +"{{requestHeaders.contentType}}" === "text/html" // you can also use regular expressions -requestBody.match(/hello/) +"{{requestBody.item}}".match(/hello/) // you can combine multiple expressions using logical operators -requestBody.item === "hello" && requestHeaders.contentType === "text/html" +"{{requestBody.item}"} === "hello" && "{{requestHeaders.contentType}}" === "text/html" + +// you can use the following for arrays + +"{{requestBody.items[0].name}}" === "hello" ``` ### Things to consider -* scripts have a timeout of 1 second, it will return `false` if the script takes longer than 1 second to execute. \ No newline at end of file +* scripts have a timeout of 1 second, it will return `false` if the script takes longer than 1 second to execute. +* `{{var}}` will replace the variable with the value, so if you want to compare a string, you need to wrap it in quotes, e.g. `"{{responseBody.item}}" === "hello"` and if you want to compare a number, you don't need to wrap it in quotes, e.g. `{{responseStatusCode}} === 200` \ No newline at end of file diff --git a/Probe/Utils/Monitors/Monitor.ts b/Probe/Utils/Monitors/Monitor.ts index a411c491d9..0c5fbaff96 100644 --- a/Probe/Utils/Monitors/Monitor.ts +++ b/Probe/Utils/Monitors/Monitor.ts @@ -95,7 +95,7 @@ export default class MonitorUtil { criteria.data?.filters; for (const filter of filters) { - if (filter.checkOn === CheckOn.ResponseBody) { + if (filter.checkOn === CheckOn.ResponseBody || filter.checkOn === CheckOn.JavaScriptExpression) { return false; } }