Forecast with Davis AI
The latest Dynatrace platform provides general-purpose AI/ML services covering various functionalities. In this guide, you'll learn the intricacies of using the Davis® predictive and causal AI platform service from your Dynatrace® Apps.
Get available analyzers
Before getting started, one of the main questions to answer is what Davis® AI analyzers you have at your disposal. To get the available analyzers, you have two options:
-
Check out the
/analyzers
endpoint in the . It's the easiest way of accessing every option of the different endpoints. -
Use the Davis® AI analyzers SDK in your app:
import { analyzersClient } from '@dynatrace-sdk/client-davis-analyzers';
const { analyzers, totalCount, nextPageKey } = await analyzersClient.queryAnalyzers({
filter: "name contains 'statistic'",
addFields: 'baseAnalyzer, type, input',
});TipThis operation requires the scope
davis:analyzers:read
. Read more about scopes in this guide.NoteTo use
await
in React components, you need to wrap the asynchronous invocation in anasync
function. Read more about it in this guide.
Once you've decided which analyzer better fits your use case, you need to understand the subtleties of that analyzer, which we'll see in the next section.
Analyzers input and output
All Davis® AI analyzers have a base standard set of input parameters, like timeframe
or logVerbosity
. Additionally, each analyzer needs a specific set of input parameters, which vary from one to another. There are a couple of ways of getting this information:
-
Using the .
-
Use the SDK to get the analyzer definition:
const analyzer = await analyzersClient.getAnalyzer({
analyzerName: 'dt.statistics.GenericForecastAnalyzer',
});TipThis operation requires the scope
davis:analyzers:read
. Read more about scopes in this guide.NoteTo use
await
in React components, you need to wrap the asynchronous invocation in anasync
function. Read more about it in this guide.
The output of each analyzer can be very different as well. You need to query the analyzer definition using any of the two methods above to get the output definition.
Time series forecast analysis
At this point, we know the analyzer we want to use and understand its input parameters and its output definition. Now, we get to use it. Let's look at a complete example of how you would use the dt.statistics.GenericForecastAnalyzer
analyzer to get a forecast of any time series metric.
Execute analyzer
This operation requires the scope davis:analyzers:execute
. Read more about scopes in this guide.
Let's begin by creating a function that will request the forecast analysis:
import { analyzersClient } from '@dynatrace-sdk/client-davis-analyzers';
export const loadForecast = async (query: string) => {
const analyzerName = 'dt.statistics.GenericForecastAnalyzer';
const response = await analyzersClient.executeAnalyzer({
analyzerName,
body: {
timeSeriesData: {
expression: query,
},
},
});
// ...
};
Depending on the chosen analyzer and the analyzer input, additional scopes might be required, for example, storage:buckets:read
and storage:metrics:read
to enable the analyzer to read time series data from Grail™.
This function receives a DQL query as a parameter and triggers an async forecast analysis on the results of running said query via the executeAnalyzer
function from the analyzersClient
. If the analysis takes more than two seconds to finish, the response will contain a requestToken
that will allow you to poll until the results are available.
Poll analyzer execution
Let's create a new pollExecution
function to handle the polling logic.
import { AnalyzerResult, AnalyzerResultExecutionStatus, analyzersClient } from '@dynatrace-sdk/client-davis-analyzers';
export const pollExecution = async (analyzerName: string, requestToken: string): Promise<AnalyzerResult> => {
const MAX_ATTEMPTS = 10;
const INTERVAL_MS = 1000;
let attempts = 0;
while (attempts < MAX_ATTEMPTS) {
await new Promise((resolve) => setTimeout(resolve, INTERVAL_MS));
const { result } = await analyzersClient.pollAnalyzerExecution({
analyzerName,
requestToken,
});
if (result.executionStatus === AnalyzerResultExecutionStatus.Completed) {
return result;
}
if (result.executionStatus === AnalyzerResultExecutionStatus.Aborted) {
throw new Error('The analyzer execution was aborted');
}
attempts++;
}
const cancelResponse = await analyzersClient.cancelAnalyzerExecution({
analyzerName,
requestToken,
});
if (cancelResponse && cancelResponse.result.executionStatus === AnalyzerResultExecutionStatus.Completed) {
return cancelResponse.result;
}
throw new Error('Max polling retries reached');
};
Aside from the simple polling implementation, we've introduced two new functions:
pollAnalyzerExecution
: This function allows you to check the analysis execution status with the analyzer name and the request token you got in the initial request.cancelAnalyzerExecution
: Once we've reached the max polling attempts, we recommend canceling the analysis execution. If the analysis finishes between the last poll and the cancellation, this function will return the analysis results. Otherwise, the response will beundefined
.
Handle analyzer output
We can now use pollExecution
in our main function and extract the forecasting information as a TimeseriesBand
from the analysis output:
import {
AnalyzerResultExecutionStatus,
analyzersClient,
} from '@dynatrace-sdk/client-davis-analyzers';
import { convertToTimeseriesBand } from '@dynatrace/strato-components-preview/conversion-utilities';
import { TimeseriesBand } from '@dynatrace/strato-components-preview/charts';
import { pollExecution } from './pollExecution';
export const loadForecast = async (query: string): Promise<TimeseriesBand> => {
const analyzerName = 'dt.statistics.GenericForecastAnalyzer';
const response = await analyzersClient.executeAnalyzer({
analyzerName,
body: {
timeSeriesData: {
expression: query,
},
},
});
const analysisResult = response.requestToken
? await pollExecution(analyzerName, response.requestToken)
: response.result;
if (analysisResult.executionStatus === AnalyzerResultExecutionStatus.Completed) {
const analyzerOutput = analysisResult.output[0];
const timeseriesBandData = convertToTimeseriesBand(
analyzerOutput.timeSeriesDataWithPredictions.records[0],
analyzerOutput.timeSeriesDataWithPredictions.types[0],
);
if (timeseriesBandData) {
return timeseriesBandData.timeseriesBand;
}
throw new Error('Unexpected error');
}
throw new Error('The analyzer execution was aborted');
};
Your loadForecast
function is now ready. You can provide any time series DQL query to this function, and it will handle the forecast analysis and return it in TimeseriesBand
format, which you can use to visualize it.
You can learn more about visualizing a TimeseriesBand
from the TimeseriesChart
reference page.
Troubleshooting
Davis® AI analyzer executions might fail for different reasons. In these cases, the response will contain a log array that you can use to figure out why the analysis was unsuccessful. For instance, if the provided query doesn't return enough data points, the response will look something like this:
{
"result": {
"resultId": "4e1a8a1efd560193",
"resultStatus": "FAILED",
"executionStatus": "COMPLETED",
"input": {
...
},
"logs": [
{
"level": "WARNING",
"message": "More historical data is required to generate a reliable forecast. Increase the timeframe or adapt the resolution to include a minimum of 14 non-NaN observations.",
"analyzerName": "dt.statistics.GenericForecastAnalyzer"
},
{
"level": "SEVERE",
"message": "The analysis of the data was not successful.",
"analyzerName": "dt.statistics.GenericForecastAnalyzer"
}
],
"output": []
}
}
Related links
- Visit the
- Learn more about Davis AI service
- Learn more about Forecast analysis