Dynatrace API
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

api for extract state of monitoring process

gasperetta
Frequent Guest


hi, 

in the community i have downloaded this runbook very helpful,
but i need to exract only the process that have monitoring state different from "ok".

How can change the code?

 

 

/*
* This function will run in the DYNATRACE JavaScript runtime.
* For information visit https://dt-url.net/functions-help
*/
import { monitoredEntitiesMonitoringStateClient } from "@dynatrace-sdk/client-classic-environment-v2";
import { queryExecutionClient } from "@dynatrace-sdk/client-query";


// **** Dynatrace API ****
async function fetchAllMonitoringStates(pgID) {
const pgID_string = `${pgID.map(id => `"${id}"`).join(",")}`;
let nextPageKey = null;
const monitoringStates = [];
do {
const params = nextPageKey
? { nextPageKey }
: { entitySelector: `entityId(${pgID_string})`};
const result = await monitoredEntitiesMonitoringStateClient.getStates(params);
monitoringStates.push(...result.monitoringStates);
nextPageKey = result.nextPageKey;
} while (nextPageKey);
return monitoringStates
}
export default async function () {
const now = new Date();
const twentyMinutesAgo = new Date(now.getTime() - 20 * 60 * 1000);
const formatDate = (date) => date.toISOString();
const $dt_timeframe_from = formatDate(twentyMinutesAgo);
const $dt_timeframe_to = formatDate(now);


// **** DQL Query ****
const dqlQuery = `
fetch dt.entity.process_group_instance
| fieldsAdd host.id=belongs_to[dt.entity.host], pg_id=instance_of[dt.entity.process_group], cgi_id=(belongs_to[dt.entity.container_group_instance])
| lookup [fetch dt.entity.host], sourceField:host.id, lookupField:id, fields:{host.name=entity.name, host.hostGroupName=hostGroupName}
| lookup [fetch dt.entity.process_group], sourceField:pg_id, lookupField:id, fields:{process.name=entity.name}
| lookup [fetch dt.entity.container_group_instance
| fieldsAdd pod_id=belongs_to[dt.entity.cloud_application_instance], namespace_id=belongs_to[dt.entity.cloud_application_namespace], node_id=belongs_to[dt.entity.host]
| lookup [fetch dt.entity.cloud_application_instance], sourceField:pod_id, lookupField:id, fields:{pod_name=entity.name}
| lookup [fetch dt.entity.cloud_application_namespace], sourceField:namespace_id, lookupField:id, fields:{namespace=entity.name}
| lookup [fetch dt.entity.host], sourceField:node_id, lookupField:id, fields:{node_name=entity.name}], sourceField:cgi_id, lookupField:id, fields:{pod_name, namespace, node_name}
| fields managementZones, host.id, host.name, host.hostGroupName, process.name, pod_name, namespace, node_name, id
| sort process.name desc
//| filter host.hostGroupName == "bet-booker"
`;


// **** Execution Performance Limits ****
// const queryExecution = await queryExecutionClient.queryExecute({ body: { query: dqlQuery } });
const queryExecution = await queryExecutionClient.queryExecute({ body: {
query: dqlQuery,
scanLimitGBytes: -1
// fetchTimeoutSeconds:5000,
// defalutScanLimitsGbytes: 500000,
// maxResultsBytes: 100000000,
// maxResultsRecords: 300000000
} });
let dqlResults = [];
while (true) {
const queryPollResult = await queryExecutionClient.queryPoll({ requestToken: queryExecution.requestToken });
if (queryPollResult.state !== "RUNNING") {
dqlResults = queryPollResult.result.records;
break;
}
}
let pgID = dqlResults.map(item => item.id);
const processAllChunks = async () => {
const allMonitoringStates = [];
for (let i = 0; i < pgID.length; i += 50) {
const chunk = pgID.slice(i, i + 50);
const chunkStates = await fetchAllMonitoringStates(chunk);
allMonitoringStates.push(...chunkStates);
}
return allMonitoringStates;
};
const monitoringStates = await processAllChunks();
const mergedResults = dqlResults.map(dqlItem => {
const match = monitoringStates.find(apiItem => apiItem.entityId === dqlItem.id);
return match ? { ...dqlItem, severity: match.severity, state: match.state } : dqlItem;
});
return mergedResults
}

6 REPLIES 6

t_pawlak
Leader

Hi,
try this:
Total number of calls over the selected time range (sum of all minutes)

timeseries calls_per_min = sum(dt.service.request.count, rate:1m),
  by:{endpoint.name, dt.entity.service, dt.host_group.id},
  interval: 1m
| fieldsAdd service_name = entityName(dt.entity.service)
| fieldsAdd endpoint_key = concat(service_name, " :: ", endpoint.name, " :: ", dt.host_group.id)
| filter in(endpoint_key,
  "CustomerFrontendREST :: Images :: et-large",
  "JourneyService :: findJourneys :: et-large"
)
| fieldsAdd total_calls_row = arraySum(calls_per_min)
| summarize total_calls = sum(total_calls_row)

comm1.jpg

 

Current total (last datapoint),  combined calls/min at the end of the chart

timeseries calls_per_min = sum(dt.service.request.count, rate:1m),
  by:{endpoint.name, dt.entity.service, dt.host_group.id},
  interval: 1m
| fieldsAdd service_name = entityName(dt.entity.service)
| fieldsAdd endpoint_key = concat(service_name, " :: ", endpoint.name, " :: ", dt.host_group.id)
| filter in(endpoint_key,
  "CustomerFrontendREST :: Images :: et-large",
  "JourneyService :: findJourneys :: et-large"
)
| fieldsAdd last_cpm_row = arrayLast(calls_per_min)
| summarize last_cpm_total = sum(last_cpm_row)

comm2.jpg

 

Sorry, wrong thread

(-: is my request too

t_pawlak
Leader

Hi,

I don’t have a ton of experience with this, but it seems to me that you don’t touch the DQL, only after merging the results (DQL + Monitoring State API) you apply a filter to keep only the processes where state != "OK".
Change return mergedResults to 

const mergedResults = dqlResults.map(dqlItem => {
  const match = monitoringStates.find(apiItem => apiItem.entityId === dqlItem.id);
  return match ? { ...dqlItem, severity: match.severity, state: match.state } : dqlItem;
});

//Only proccesses !== "OK"
const onlyNotOk = mergedResults.filter(item => {
  // jeśli dla jakiegoś wpisu nie ma state (API nie zwróciło), to:
  if (!item.state) return true; 
  return item.state.toUpperCase() !== "OK";
});

return onlyNotOk;

If you want to drop records with no state and keep only “real” non-OK ones:

return mergedResults.filter(item => item.state && item.state.toUpperCase() !== "OK");

That’s it. It’s best to filter by state after the merge, because state comes from monitoredEntitiesMonitoringStateClient.getStates()

gasperetta
Frequent Guest

is possible have timeseries? because, in this case i have only the last value and i can't use line widget.

thanks a lot

Hi,
IMO yes, timeseries is possible, but not from getStates().
I am pretty sure, that monitoredEntitiesMonitoringStateClient.getStates() returns a point-in-time snapshot. Like monitoring state. So you’ll always have only a single latest value.
Mabye chang state to number (OK=0, WARNING=1, ERROR=2) and send it as custom metric. Thanks to that you can show it in line widget

Featured Posts