Also return result of the evaluation

-Maximum compatibility with @chakflying's existing json-query monitor code.
This commit is contained in:
Matt Visnovsky 2024-06-06 10:09:35 -06:00
parent 10d3188dd3
commit eaa935cba0
4 changed files with 33 additions and 23 deletions

View file

@ -609,13 +609,13 @@ class Monitor extends BeanModel {
} }
} }
const result = await evaluateJsonQuery(data, this.jsonPath, this.jsonPathOperator, this.expectedValue); const { status, evaluation } = await evaluateJsonQuery(data, this.jsonPath, this.jsonPathOperator, this.expectedValue);
if (result) { if (status) {
bean.msg += ", expected value is found"; bean.msg += ", expected value is found";
bean.status = UP; bean.status = UP;
} else { } else {
throw new Error(`${bean.msg}, but value is not equal to expected value, value was: [${result}]`); throw new Error(`${bean.msg}, but value is not equal to expected value, value was: [${evaluation}]`);
} }
} }

View file

@ -44,12 +44,12 @@ class SNMPMonitorType extends MonitorType {
// We restrict querying to one OID per monitor, therefore `varbinds[0]` will always contain the value we're interested in. // We restrict querying to one OID per monitor, therefore `varbinds[0]` will always contain the value we're interested in.
const value = varbinds[0].value; const value = varbinds[0].value;
const result = await evaluateJsonQuery(value, monitor.jsonPath, monitor.jsonPathOperator, monitor.expectedValue); const { status, evaluation } = await evaluateJsonQuery(value, monitor.jsonPath, monitor.jsonPathOperator, monitor.expectedValue);
heartbeat.status = result ? UP : DOWN; heartbeat.status = status ? UP : DOWN;
heartbeat.msg = `SNMP value ${result ? "passes" : "does not pass"} `; heartbeat.msg = `SNMP value ${status ? "passes" : "does not pass"} `;
heartbeat.msg += (monitor.jsonPathOperator === "custom") heartbeat.msg += (monitor.jsonPathOperator === "custom")
? `custom query. Query result: ${result}. Expected Value: ${monitor.expectedValue}.` ? `custom query. Query result: ${evaluation}. Expected Value: ${monitor.expectedValue}.`
: `comparison: ${value.toString()} ${monitor.jsonPathOperator} ${monitor.expectedValue}.`; : `comparison: ${value.toString()} ${monitor.jsonPathOperator} ${monitor.expectedValue}.`;
} catch (err) { } catch (err) {

View file

@ -440,9 +440,12 @@ async function evaluateJsonQuery(data, jsonPath, jsonPathOperator, expectedValue
if (evaluation === undefined) { if (evaluation === undefined) {
throw new Error("Query evaluation returned undefined. Check your query syntax and the structure of the response data."); throw new Error("Query evaluation returned undefined. Check your query syntax and the structure of the response data.");
} }
const result = (jsonPathOperator === "custom") const status = (jsonPathOperator === "custom")
? evaluation.toString() === expected.toString() ? evaluation.toString() === expected.toString()
: evaluation; : evaluation;
return result; return {
status,
evaluation
};
} }
exports.evaluateJsonQuery = evaluateJsonQuery; exports.evaluateJsonQuery = evaluateJsonQuery;

View file

@ -651,20 +651,18 @@ export function intHash(str : string, length = 10) : number {
* @param jsonPath The JSON path or custom JSON query expression. * @param jsonPath The JSON path or custom JSON query expression.
* @param jsonPathOperator The operator to use for comparison. * @param jsonPathOperator The operator to use for comparison.
* @param expectedValue The expected value to compare against. * @param expectedValue The expected value to compare against.
* @returns The result of the evaluation. * @returns An object containing the status and the evaluation result.
* @throws Error if the evaluation returns undefined. * @throws Error if the evaluation returns undefined.
*/ */
export async function evaluateJsonQuery(data: any, jsonPath: string, jsonPathOperator: string, expectedValue: any): Promise<boolean> { export async function evaluateJsonQuery(data: any, jsonPath: string, jsonPathOperator: string, expectedValue: any): Promise<{ status: boolean; evaluation: any }> {
// Check if inputs are numeric. If not, re-parse as strings. This ensures comparisons are handled correctly. // Check if inputs are numeric. If not, re-parse as strings. This ensures comparisons are handled correctly.
const expected = isNaN(expectedValue) ? expectedValue.toString() : parseFloat(expectedValue); const expected = isNaN(expectedValue) ? expectedValue.toString() : parseFloat(expectedValue);
let response = isNaN(data) ? data.toString() : parseFloat(data);
let response: any;
try { try {
// Attempt to parse data as JSON response = JSON.parse(data);
response = JSON.parse(response); } catch {
} catch (_) { response = typeof data === "number" || typeof data === "object" ? data : data.toString();
// Failed to parse as JSON, continue with the original value
} }
let jsonQueryExpression; let jsonQueryExpression;
@ -690,18 +688,27 @@ export async function evaluateJsonQuery(data: any, jsonPath: string, jsonPathOpe
// Evaluate the JSON Query Expression // Evaluate the JSON Query Expression
const expression = jsonata(jsonQueryExpression); const expression = jsonata(jsonQueryExpression);
const evaluation = await expression.evaluate({
let evaluation;
if (jsonPathOperator === "custom") {
evaluation = await expression.evaluate(response);
} else {
evaluation = await expression.evaluate({
value: response, value: response,
control: expected control: expectedValue
}); });
}
if (evaluation === undefined) { if (evaluation === undefined) {
throw new Error("Query evaluation returned undefined. Check your query syntax and the structure of the response data."); throw new Error("Query evaluation returned undefined. Check your query syntax and the structure of the response data.");
} }
const result = (jsonPathOperator === "custom") const status = (jsonPathOperator === "custom")
? evaluation.toString() === expected.toString() ? evaluation.toString() === expected.toString()
: evaluation; : evaluation;
return result; return {
status,
evaluation
};
} }