Azure Metrics Advisor client library for .NET - version 1.1.0

Azure Cognitive Services Metrics Advisor is a cloud service that uses machine learning to monitor and detect anomalies in time series data. It includes the following capabilities:

  • Analyze multi-dimensional data from multiple data sources.
  • Identify and correlate anomalies.
  • Configure and fine-tune the anomaly detection model used on your data.
  • Diagnose anomalies and help with root cause analysis.

Source code | Package (NuGet) | API reference documentation | Product documentation | Samples

Getting started

Install the package

Install the Azure Metrics Advisor client library for .NET with NuGet:

dotnet add package Azure.AI.MetricsAdvisor

Prerequisites

Create a Metrics Advisor resource

You can create a Metrics Advisor resource using:

Option 1: Azure Portal.

Option 2: Azure CLI.

Below is an example of how you can create a Metrics Advisor resource using the CLI:

# Create a new resource group to hold the Metrics Advisor resource.
# If using an existing resource group, skip this step.
az group create --name <your-resource-name> --location <location>
# Create the Metrics Advisor resource.
az cognitiveservices account create \
    --name <your-resource-name> \
    --resource-group <your-resource-group-name> \
    --kind MetricsAdvisor \
    --sku <sku> \
    --location <location>
    --yes

For more information about creating the resource or how to get the location and sku information see here.

Authenticate the client

In order to interact with the Metrics Advisor service, you'll need to create an instance of the MetricsAdvisorClient or the MetricsAdvisorAdministrationClient classes. You will need an endpoint, a subscription key, and an API key to instantiate a client object.

Get the Endpoint and the Subscription Key

You can obtain the endpoint and the subscription key from the resource information in the Azure Portal.

Alternately, you can use the Azure CLI snippet below to get the subscription key from the Metrics Advisor resource.

az cognitiveservices account keys list --resource-group <your-resource-group-name> --name <your-resource-name>

Get the API Key

You can obtain the API key in the Metrics Advisor Web Portal. You'll be prompted to login for authentication.

Once logged in, fill in your Azure Active Directory, Subscription and Metrics Advisor resource name.

Create a MetricsAdvisorClient or a MetricsAdvisorAdministrationClient

Once you have the subscription and API keys, create a MetricsAdvisorKeyCredential. With the endpoint and the key credential, you can create a MetricsAdvisorClient:

string endpoint = "<endpoint>";
string subscriptionKey = "<subscriptionKey>";
string apiKey = "<apiKey>";
var credential = new MetricsAdvisorKeyCredential(subscriptionKey, apiKey);
var client = new MetricsAdvisorClient(new Uri(endpoint), credential);

You can also create a MetricsAdvisorAdministrationClient to perform administration operations:

string endpoint = "<endpoint>";
string subscriptionKey = "<subscriptionKey>";
string apiKey = "<apiKey>";
var credential = new MetricsAdvisorKeyCredential(subscriptionKey, apiKey);
var adminClient = new MetricsAdvisorAdministrationClient(new Uri(endpoint), credential);

Create a MetricsAdvisorClient or a MetricsAdvisorAdministrationClient with Azure Active Directory

MetricsAdvisorKeyCredential authentication is used in the examples in this getting started guide, but you can also authenticate with Azure Active Directory using the Azure Identity library.

To use the DefaultAzureCredential provider shown below, or other credential providers provided with the Azure SDK, please install the Azure.Identity package:

Install-Package Azure.Identity

You will also need to register a new AAD application and grant access to Metrics Advisor by assigning the "Cognitive Services Metrics Advisor User" role to your service principal. You may want to assign the "Cognitive Services Metrics Advisor Administrator" role instead if administrator privileges are required.

Set the values of the client ID, tenant ID, and client secret of the AAD application as environment variables: AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_CLIENT_SECRET.

Once you have the environment variables set, you can create a MetricsAdvisorClient:

string endpoint = "<endpoint>";
var client = new MetricsAdvisorClient(new Uri(endpoint), new DefaultAzureCredential());

Alternately, you can also create a MetricsAdvisorAdministrationClient to perform administration operations:

string endpoint = "<endpoint>";
var adminClient = new MetricsAdvisorAdministrationClient(new Uri(endpoint), new DefaultAzureCredential());

Key concepts

MetricsAdvisorClient

MetricsAdvisorClient is the primary querying interface for developers using the Metrics Advisor client library. It provides synchronous and asynchronous methods to access a specific use of Metrics Advisor, such as listing incidents, retrieving root causes of incidents, and retrieving time series data.

MetricsAdvisorAdministrationClient

MetricsAdvisorAdministrationClient is the interface responsible for managing entities in the Metrics Advisor resource. It provides synchronous and asynchronous methods for tasks such as creating and updating data feeds, anomaly detection configurations, and anomaly alert configurations.

Data Feed

A DataFeed periodically ingests tables of aggregated data from your data source, such as CosmosDB or a SQL server, and makes it available for the Metrics Advisor service. It's the entry point of data, and therefore, the first required agent to be set before anomaly detection can take place. See the sample Create a data feed from a data source below for more information.

Data Feed Metric

A DataFeedMetric, or simply "metric", is a quantifiable measure used to monitor an assess the status of a specific business process. It could be the cost of a product over the months, or even a daily measure of temperature. The service will monitor how this value varies over time in search of any anomalous behavior. A data feed can ingest multiple metrics from the same data source.

Data Feed Dimension

A DataFeedDimension, or simply "dimension", is a categorical value that characterize a metric. For instance, if a metric represents the cost of a product, the type of product (e.g., shoes, hats) and the city in which these values were measured (e.g., New York, Tokyo) could be used as a dimension. The combination of multiple dimensions identify a particular univariate time series.

Time Series

A time series is a sequence of data points indexed chronologically. These data points describe the variation of the value of a metric over time.

Given a metric, the Metrics Advisor service creates one series for every possible combination of dimension values, which means that multiple time series can be monitored for the same metric.

For example, suppose the following columns of data are returned by your data source:

City Category Cost Revenue
New York Shoes 1045.00 1345.00
New York Hats 670.00 502.00
Delhi Shoes 991.00 1009.00
Delhi Hats 623.00 711.00

Cost and revenue are the metrics you want the service to monitor, while city and category are the dimensions that characterize those metrics. There are 4 possible dimension combinations in this data:

  • City = New York, Category = Shoes
  • City = New York, Category = Hats
  • City = Delhi, Category = Shoes
  • City = Delhi, Category = Hats

For each metric, the service will create 4 time series to monitor data, each one representing one possible dimension combination. Every time a data source ingestion happens, these series will be updated with a new data point, if available in the newly ingested data.

Data Point Anomaly

A DataPointAnomaly, or simply "anomaly", occurs when a data point in a time series behaves unexpectedly. It may occur when a data point value is too high or too low, or when its value changes abruptly between close points. You can specify the conditions a data point must satisfy to be considered an anomaly with an AnomalyDetectionConfiguration. After data ingestion happens, the service applies all existing configurations to the set of new points in search of anomalies. See the sample Create an anomaly detection configuration below for more information.

Anomaly Incident

When there are anomalies detected on multiple time series within one metric at a particular timestamp, the Metrics Advisor service will automatically group anomalies that share the same root cause into one AnomalyIncident, or simply "incident". This will significantly remove the effort to check each individual anomaly and quickly finds the most important contributing factor to an issue.

Anomaly Alert

An AnomalyAlert, or simply "alert", is triggered when a detected anomaly meets a specified criteria. For instance, an alert could be triggered every time an anomaly with high severity is detected. You can specify the conditions an anomaly must satisfy to trigger an alert with an AnomalyAlertConfiguration. After anomaly detection is performed over newly ingested data points, the service applies all existing configurations to the new anomalies, and each configuration fires a single alert for the set of points satisfying the specified criteria. Alert configurations are not set by default, so you need to create one in order to start triggering alerts. See the sample Create an anomaly alert configuration below for more information.

Notification Hook

A NotificationHook, or simply "hook", is a means of subscribing to alert notifications. You can pass a hook to an AnomalyAlertConfiguration and start getting notifications for every alert it creates. See the sample Create a hook for receiving anomaly alerts below for more information.

Thread safety

We guarantee that all client instance methods are thread-safe and independent of each other (guideline). This ensures that the recommendation of reusing client instances is always safe, even across threads.

Additional concepts

Client options | Accessing the response | Handling failures | Diagnostics | Mocking | Client lifetime

Examples

The following section provides several code snippets illustrating common patterns used in the Metrics Advisor .NET API. The snippets below make use of asynchronous service calls, but note that the Azure.AI.MetricsAdvisor package supports both synchronous and asynchronous APIs.

Create a data feed from a data source

Metrics Advisor supports multiple types of data sources. In this sample we'll illustrate how to create a DataFeed that extracts data from a SQL server.

string sqlServerConnectionString = "<connectionString>";
string sqlServerQuery = "<query>";

var dataFeed = new DataFeed();

dataFeed.Name = "<dataFeedName>";
dataFeed.DataSource = new SqlServerDataFeedSource(sqlServerConnectionString, sqlServerQuery);
dataFeed.Granularity = new DataFeedGranularity(DataFeedGranularityType.Daily);

dataFeed.Schema = new DataFeedSchema();
dataFeed.Schema.MetricColumns.Add(new DataFeedMetric("cost"));
dataFeed.Schema.MetricColumns.Add(new DataFeedMetric("revenue"));
dataFeed.Schema.DimensionColumns.Add(new DataFeedDimension("category"));
dataFeed.Schema.DimensionColumns.Add(new DataFeedDimension("city"));

dataFeed.IngestionSettings = new DataFeedIngestionSettings(DateTimeOffset.Parse("2020-01-01T00:00:00Z"));

Response<DataFeed> response = await adminClient.CreateDataFeedAsync(dataFeed);

DataFeed createdDataFeed = response.Value;

Console.WriteLine($"Data feed ID: {createdDataFeed.Id}");
Console.WriteLine($"Data feed status: {createdDataFeed.Status.Value}");
Console.WriteLine($"Data feed created time: {createdDataFeed.CreatedOn.Value}");

Console.WriteLine($"Data feed administrators:");
foreach (string admin in createdDataFeed.Administrators)
{
    Console.WriteLine($" - {admin}");
}

Console.WriteLine($"Metric IDs:");
foreach (DataFeedMetric metric in createdDataFeed.Schema.MetricColumns)
{
    Console.WriteLine($" - {metric.Name}: {metric.Id}");
}

Console.WriteLine($"Dimensions:");
foreach (DataFeedDimension dimension in createdDataFeed.Schema.DimensionColumns)
{
    Console.WriteLine($" - {dimension.Name}");
}

Other data source authentication alternatives

Some data sources support multiple types of authentication. For example, a SqlServerDataFeedSource supports connection string, Service Principal, and managed identity. You can check the complete list of data sources and their types of authentication here.

Once you've made sure that your data source supports the authentication you want to use, you need to set the Authentication property when creating or updating the data source:

var dataSoure = new SqlServerDataFeedSource("<connection-string>", "<query>")
{
    Authentication = SqlServerDataFeedSource.AuthenticationType.ManagedIdentity
};

Be aware that, except for the Basic and ManagedIdentity types of authentication, you also need to have the ID of a corresponding DataSourceCredentialEntity in the service. In order to create a credential entity, you need to do:

string credentialName = "<credentialName>";

var credentialEntity = new ServicePrincipalCredentialEntity(credentialName, "<clientId>", "<clientSecret>", "<tenantId>");

Response<DataSourceCredentialEntity> response = await adminClient.CreateDataSourceCredentialAsync(credentialEntity);

DataSourceCredentialEntity createdCredentialEntity = response.Value;

Console.WriteLine($"Credential entity ID: {createdCredentialEntity.Id}");

Once you have the ID, add it to the DataSourceCredentialId property when setting up your data source:

var dataSoure = new SqlServerDataFeedSource("<connection-string>", "<query>")
{
    Authentication = SqlServerDataFeedSource.AuthenticationType.ServicePrincipal,
    DataSourceCredentialId = "<credentialId>"
};

Check the ingestion status of a data feed

Check the ingestion status of a previously created DataFeed.

string dataFeedId = "<dataFeedId>";

var startsOn = DateTimeOffset.Parse("2020-01-01T00:00:00Z");
var endsOn = DateTimeOffset.Parse("2020-09-09T00:00:00Z");
var options = new GetDataFeedIngestionStatusesOptions(startsOn, endsOn)
{
    MaxPageSize = 5
};

Console.WriteLine("Ingestion statuses:");
Console.WriteLine();

int statusCount = 0;

await foreach (DataFeedIngestionStatus ingestionStatus in adminClient.GetDataFeedIngestionStatusesAsync(dataFeedId, options))
{
    Console.WriteLine($"Timestamp: {ingestionStatus.Timestamp}");
    Console.WriteLine($"Status: {ingestionStatus.Status}");
    Console.WriteLine($"Service message: {ingestionStatus.Message}");
    Console.WriteLine();

    // Print at most 5 statuses.
    if (++statusCount >= 5)
    {
        break;
    }
}

Create an anomaly detection configuration

Create an AnomalyDetectionConfiguration to tell the service which data points should be considered anomalies.

string metricId = "<metricId>";
string configurationName = "<configurationName>";

var detectionConfiguration = new AnomalyDetectionConfiguration()
{
    MetricId = metricId,
    Name = configurationName,
    WholeSeriesDetectionConditions = new MetricWholeSeriesDetectionCondition()
};

var detectCondition = detectionConfiguration.WholeSeriesDetectionConditions;

var hardSuppress = new SuppressCondition(1, 100);
detectCondition.HardThresholdCondition = new HardThresholdCondition(AnomalyDetectorDirection.Down, hardSuppress)
{
    LowerBound = 5.0
};

var smartSuppress = new SuppressCondition(4, 50);
detectCondition.SmartDetectionCondition = new SmartDetectionCondition(10.0, AnomalyDetectorDirection.Up, smartSuppress);

detectCondition.ConditionOperator = DetectionConditionOperator.Or;

Response<AnomalyDetectionConfiguration> response = await adminClient.CreateDetectionConfigurationAsync(detectionConfiguration);

AnomalyDetectionConfiguration createdDetectionConfiguration = response.Value;

Console.WriteLine($"Anomaly detection configuration ID: {createdDetectionConfiguration.Id}");

Create a hook for receiving anomaly alerts

Metrics Advisor supports the EmailNotificationHook and the WebNotificationHook classes as means of subscribing to alert notifications. In this example we'll illustrate how to create an EmailNotificationHook. Note that you need to pass the hook to an anomaly alert configuration to start getting notifications. See the sample Create an anomaly alert configuration below for more information.

string hookName = "<hookName>";

var emailHook = new EmailNotificationHook(hookName);

emailHook.EmailsToAlert.Add("email1@sample.com");
emailHook.EmailsToAlert.Add("email2@sample.com");

Response<NotificationHook> response = await adminClient.CreateHookAsync(emailHook);

NotificationHook createdHook = response.Value;

Console.WriteLine($"Hook ID: {createdHook.Id}");

Create an anomaly alert configuration

Create an AnomalyAlertConfiguration to tell the service which anomalies should trigger alerts.

string hookId = "<hookId>";
string anomalyDetectionConfigurationId = "<anomalyDetectionConfigurationId>";
string configurationName = "<configurationName>";

AnomalyAlertConfiguration alertConfiguration = new AnomalyAlertConfiguration()
{
    Name = configurationName
};

alertConfiguration.IdsOfHooksToAlert.Add(hookId);

var scope = MetricAnomalyAlertScope.CreateScopeForWholeSeries();
var metricAlertConfiguration = new MetricAlertConfiguration(anomalyDetectionConfigurationId, scope);

alertConfiguration.MetricAlertConfigurations.Add(metricAlertConfiguration);

Response<AnomalyAlertConfiguration> response = await adminClient.CreateAlertConfigurationAsync(alertConfiguration);

AnomalyAlertConfiguration createdAlertConfiguration = response.Value;

Console.WriteLine($"Alert configuration ID: {createdAlertConfiguration.Id}");

Query detected anomalies and triggered alerts

Look through the alerts created by a given anomaly alert configuration.

string anomalyAlertConfigurationId = "<anomalyAlertConfigurationId>";

var startsOn = DateTimeOffset.Parse("2020-01-01T00:00:00Z");
var endsOn = DateTimeOffset.UtcNow;
var options = new GetAlertsOptions(startsOn, endsOn, AlertQueryTimeMode.AnomalyDetectedOn)
{
    MaxPageSize = 5
};

int alertCount = 0;

await foreach (AnomalyAlert alert in client.GetAlertsAsync(anomalyAlertConfigurationId, options))
{
    Console.WriteLine($"Alert created at: {alert.CreatedOn}");
    Console.WriteLine($"Alert at timestamp: {alert.Timestamp}");
    Console.WriteLine($"Id: {alert.Id}");
    Console.WriteLine();

    // Print at most 5 alerts.
    if (++alertCount >= 5)
    {
        break;
    }
}

Once you know an alert's ID, list the anomalies that triggered this alert.

string alertConfigurationId = "<alertConfigurationId>";
string alertId = "<alertId>";

var options = new GetAnomaliesForAlertOptions() { MaxPageSize = 3 };

int anomalyCount = 0;

await foreach (DataPointAnomaly anomaly in client.GetAnomaliesForAlertAsync(alertConfigurationId, alertId, options))
{
    Console.WriteLine($"Anomaly detection configuration ID: {anomaly.DetectionConfigurationId}");
    Console.WriteLine($"Data feed ID: {anomaly.DataFeedId}");
    Console.WriteLine($"Metric ID: {anomaly.MetricId}");
    Console.WriteLine($"Anomaly value: {anomaly.Value}");

    if (anomaly.ExpectedValue.HasValue)
    {
        Console.WriteLine($"Anomaly expected value: {anomaly.ExpectedValue}");
    }

    Console.WriteLine($"Anomaly at timestamp: {anomaly.Timestamp}");
    Console.WriteLine($"Anomaly detected at: {anomaly.CreatedOn}");
    Console.WriteLine($"Status: {anomaly.Status}");
    Console.WriteLine($"Severity: {anomaly.Severity}");
    Console.WriteLine("Series key:");

    foreach (KeyValuePair<string, string> dimension in anomaly.SeriesKey)
    {
        Console.WriteLine($"  Dimension '{dimension.Key}': {dimension.Value}");
    }

    Console.WriteLine();

    // Print at most 3 anomalies.
    if (++anomalyCount >= 3)
    {
        break;
    }
}

Troubleshooting

General

When you interact with the Cognitive Services Metrics Advisor client library using the .NET SDK, errors returned by the service will result in a RequestFailedException with the same HTTP status code returned by the REST API request.

For example, if you try to get a data feed from the service with a non-existent ID, a 404 error is returned, indicating "Not Found".

string dataFeedId = "00000000-0000-0000-0000-000000000000";

try
{
    Response<DataFeed> response = await adminClient.GetDataFeedAsync(dataFeedId);
}
catch (RequestFailedException ex)
{
    Console.WriteLine(ex.ToString());
}

Note that additional information is logged, such as the error message returned by the service.

Azure.RequestFailedException: Service request failed.
Status: 404 (Not Found)

Content:
{"code":"ERROR_INVALID_PARAMETER","message":"datafeedId is invalid."}

Headers:
X-Request-ID: REDACTED
x-envoy-upstream-service-time: REDACTED
apim-request-id: REDACTED
Strict-Transport-Security: REDACTED
X-Content-Type-Options: REDACTED
Date: Thu, 08 Oct 2020 09:04:31 GMT
Content-Length: 69
Content-Type: application/json; charset=utf-8

Setting up console logging

The simplest way to see the logs is to enable console logging.

To create an Azure SDK log listener that outputs messages to the console use the AzureEventSourceListener.CreateConsoleLogger method.

// Set up a listener to monitor logged events.
using AzureEventSourceListener listener = AzureEventSourceListener.CreateConsoleLogger();

To learn more about other logging mechanisms see Diagnostics Samples.

Next steps

Samples showing how to use the Cognitive Services Metrics Advisor library are available in this GitHub repository. Samples are provided for each main functional area:

Contributing

This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit cla.microsoft.com.

When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.

This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.