/// <summary> /// Creating a new instance of <see cref="EmulationAlert"/> for unit tests. /// </summary> /// <param name="alert">The alert to wrap</param> /// <returns>An emulation alert</returns> public static EmulationAlert CreateEmulationAlert(Alert alert) { string resourceId = alert.ResourceIdentifier.ResourceType == ResourceType.ApplicationInsights ? appInsightsResourceId : virtualMachineResourceId; QueryRunInfo queryRunInfo = new QueryRunInfo { Type = alert.ResourceIdentifier.ResourceType == ResourceType.ApplicationInsights ? TelemetryDbType.ApplicationInsights : TelemetryDbType.LogAnalytics, ResourceIds = new List <string>() { resourceId } }; var request = new SmartDetectorExecutionRequest { ResourceIds = new List <string>() { resourceId }, SmartDetectorId = "smartDetectorId", Cadence = TimeSpan.FromDays(1), }; ContractsAlert contractsAlert = alert.CreateContractsAlert(request, "smartDetectorName", queryRunInfo, usedLogAnalysisClient: false, usedMetricClient: false); return(new EmulationAlert(contractsAlert, ExtendedDateTime.UtcNow)); }
private void AssertAlertProperties(ContractsAlert contractsAlert) { Assert.AreEqual(4, contractsAlert.AlertProperties.Count); int propertyIndex = 0; Assert.AreEqual("Predicate", contractsAlert.AlertProperties[propertyIndex].PropertyName); Assert.AreEqual(AlertPropertyType.Raw, contractsAlert.AlertProperties[propertyIndex].Type); Assert.AreEqual("AlertTitle", ((RawAlertProperty)contractsAlert.AlertProperties[propertyIndex]).Value); propertyIndex++; Assert.AreEqual("RawProperty", contractsAlert.AlertProperties[propertyIndex].PropertyName); Assert.AreEqual(AlertPropertyType.Raw, contractsAlert.AlertProperties[propertyIndex].Type); Assert.AreEqual(1, ((RawAlertProperty)contractsAlert.AlertProperties[propertyIndex]).Value); propertyIndex++; Assert.AreEqual("LongTextPropertyName", contractsAlert.AlertProperties[propertyIndex].PropertyName); Assert.AreEqual(AlertPropertyType.LongText, contractsAlert.AlertProperties[propertyIndex].Type); Assert.AreEqual("LongTextDisplayName", ((LongTextAlertProperty)contractsAlert.AlertProperties[propertyIndex]).DisplayName); Assert.AreEqual(0, ((LongTextAlertProperty)contractsAlert.AlertProperties[propertyIndex]).Order); Assert.AreEqual("LongTextValue", ((LongTextAlertProperty)contractsAlert.AlertProperties[propertyIndex]).Value); propertyIndex++; Assert.AreEqual("TextValue", contractsAlert.AlertProperties[propertyIndex].PropertyName); Assert.AreEqual(AlertPropertyType.Text, contractsAlert.AlertProperties[propertyIndex].Type); Assert.AreEqual("TextDisplayName", ((TextAlertProperty)contractsAlert.AlertProperties[propertyIndex]).DisplayName); Assert.AreEqual(1, ((TextAlertProperty)contractsAlert.AlertProperties[propertyIndex]).Order); Assert.AreEqual("TextValue", ((TextAlertProperty)contractsAlert.AlertProperties[propertyIndex]).Value); }
public void WhenProcessingAlertWithV2PresentationThenTheContractsAlertIsCreatedCorrectly() { ContractsAlert contractsAlert = CreateContractsV2Alert(new PresentationTestAlert()); Assert.AreEqual(ContractsAlertState.Active, contractsAlert.State); Assert.IsTrue(contractsAlert.AnalysisTimestamp <= DateTime.UtcNow, "Unexpected analysis timestamp in the future"); Assert.IsTrue(contractsAlert.AnalysisTimestamp >= DateTime.UtcNow.AddMinutes(-1), "Unexpected analysis timestamp - too back in the past"); Assert.AreEqual(24 * 60, contractsAlert.AnalysisWindowSizeInMinutes, "Unexpected analysis window size"); Assert.AreEqual(SmartDetectorName, contractsAlert.SmartDetectorName, "Unexpected Smart Detector name"); Assert.AreEqual("AlertTitle", contractsAlert.Title, "Unexpected title"); Assert.AreEqual(default(ResourceIdentifier).ToResourceId(), contractsAlert.ResourceId, "Unexpected ResourceId"); Assert.AreEqual(SignalType.Log, contractsAlert.SignalType, "Unexpected signal type"); Assert.AreEqual(10, contractsAlert.AlertProperties.Count, "Unexpected number of properties"); // Verify raw alert properties VerifyPresentationTestAlertRawProperty(contractsAlert.AlertProperties, "Predicate"); VerifyPresentationTestAlertRawProperty(contractsAlert.AlertProperties, "RawProperty"); // Verify displayed alert properties VerifyPresentationTestAlertDisplayedProperty(contractsAlert.AlertProperties, "LongTextPropertyName", "LongTextDisplayName", 0); VerifyPresentationTestAlertDisplayedProperty(contractsAlert.AlertProperties, "UrlValue", "UrlDisplayName", 1); VerifyPresentationTestAlertDisplayedProperty(contractsAlert.AlertProperties, "TextValue", "TextDisplayName", 2); VerifyPresentationTestAlertDisplayedProperty(contractsAlert.AlertProperties, "KeyValue", "KeyValueDisplayName", 3); VerifyPresentationTestAlertDisplayedProperty(contractsAlert.AlertProperties, "KeyValueWithHeaders", "KeyValueWithHeadersDisplayName", 4); VerifyPresentationTestAlertDisplayedProperty(contractsAlert.AlertProperties, "Table", "TableDisplayName", 5); VerifyPresentationTestAlertDisplayedProperty(contractsAlert.AlertProperties, "SingleColumnTable", "SingleColumnTableDisplayName", 6); VerifyPresentationTestAlertDisplayedProperty(contractsAlert.AlertProperties, "DataPoints", "ChartDisplayName", byte.MaxValue); }
public void WhenCreatingContractsAlertThenAlertDataIsCorrect() { var resourceId = new ResourceIdentifier(ResourceType.ApplicationInsights, "subscription", "resourceGroup", "myApp"); var alert = new TestAlert(resourceIdentifier: resourceId); ContractsAlert contractsAlert = alert.CreateContractsAlert(this.analysisRequest, SmartDetectorName, false, false); Assert.AreEqual("AlertTitle", contractsAlert.Title); Assert.AreEqual("/subscriptions/subscription/resourceGroups/resourceGroup/providers/Microsoft.Insights/components/myApp", contractsAlert.ResourceId); Assert.AreEqual(alert.OccurenceTime, contractsAlert.OccurenceTime); Assert.AreEqual("smartDetectorId", contractsAlert.SmartDetectorId); Assert.AreEqual(SmartDetectorName, contractsAlert.SmartDetectorName); Assert.AreEqual((int)this.analysisRequest.Cadence.TotalMinutes, contractsAlert.AnalysisWindowSizeInMinutes); Assert.AreEqual(SignalType.Log, contractsAlert.SignalType); Assert.IsNull(contractsAlert.ResolutionParameters); this.AssertAlertProperties(contractsAlert); }
public void WhenProcessingAlertThenTheContractsAlertIsCreatedCorrectly() { ContractsAlert contractsAlert = CreateContractsAlert(new TestAlert()); Assert.AreEqual(ContractsAlertState.Active, contractsAlert.State); Assert.IsTrue(contractsAlert.AnalysisTimestamp <= DateTime.UtcNow, "Unexpected analysis timestamp in the future"); Assert.IsTrue(contractsAlert.AnalysisTimestamp >= DateTime.UtcNow.AddMinutes(-1), "Unexpected analysis timestamp - too back in the past"); Assert.AreEqual(24 * 60, contractsAlert.AnalysisWindowSizeInMinutes, "Unexpected analysis window size"); Assert.AreEqual(SmartDetectorName, contractsAlert.SmartDetectorName, "Unexpected Smart Detector name"); Assert.AreEqual("Test title", contractsAlert.Title, "Unexpected title"); Assert.AreEqual(SignalType.Log, contractsAlert.SignalType, "Unexpected signal type"); Assert.AreEqual(8, contractsAlert.Properties.Count, "Unexpected number of properties"); VerifyProperty(contractsAlert.Properties, "Machine name", AlertPresentationSection.Property, "strongOne", "The machine on which the CPU had increased", 1); VerifyProperty(contractsAlert.Properties, "CPU over the last 7 days", AlertPresentationSection.Chart, "<the query>", "CPU chart for machine strongOne, showing increase of 22.4"); VerifyProperty(contractsAlert.Properties, "CPU increased", AlertPresentationSection.Property, "22.4", "CPU increase on machine strongOne"); VerifyProperty(contractsAlert.Properties, "Another query 1", AlertPresentationSection.AdditionalQuery, "<query1>", "Info balloon for another query 1"); VerifyProperty(contractsAlert.Properties, "Another query 2", AlertPresentationSection.AdditionalQuery, "<query2>", "Info balloon for another query 2"); VerifyProperty(contractsAlert.Properties, "Analysis 1", AlertPresentationSection.Analysis, "analysis1", "Info balloon for analysis 1"); VerifyProperty(contractsAlert.Properties, "Analysis 2", AlertPresentationSection.Analysis, "analysis2", "Info balloon for analysis 2"); VerifyProperty(contractsAlert.Properties, "Analysis 3", AlertPresentationSection.Analysis, new DateTime(2012, 11, 12, 17, 22, 37).ToString("u", CultureInfo.InvariantCulture), "Info balloon for analysis 3"); Assert.AreEqual("no show", contractsAlert.RawProperties["NoPresentation"]); Assert.AreEqual(TelemetryDbType.LogAnalytics, contractsAlert.QueryRunInfo.Type, "Unexpected telemetry DB type"); CollectionAssert.AreEqual(new[] { "resourceId1", "resourceId2" }, contractsAlert.QueryRunInfo.ResourceIds.ToArray(), "Unexpected resource IDs"); }
/// <summary> /// Runs the Smart Detector's analysis flow. /// </summary> /// <param name="request">The Smart Detector analysis request</param> /// <param name="smartDetector">The Smart Detector to run</param> /// <param name="smartDetectorManifest">The Smart Detector's manifest</param> /// <param name="detectorTracer">The tracer to provider for the Smart Detector</param> /// <param name="cancellationToken">The cancellation token</param> /// <returns>A <see cref="Task{TResult}"/>, returning the list of Alerts generated by the Smart Detector.</returns> private async Task <List <ContractsAlert> > AnalyzeAsync( SmartDetectorAnalysisRequest request, ISmartDetector smartDetector, SmartDetectorManifest smartDetectorManifest, ITracer detectorTracer, CancellationToken cancellationToken) { // Create state repository IStateRepository stateRepository = this.stateRepositoryFactory.Create(request.SmartDetectorId, request.AlertRuleResourceId); // Create the input for the Smart Detector AnalysisRequestParameters analysisRequestParameters = await this.CreateAnalysisRequestParametersAsync(DateTime.UtcNow, request, smartDetectorManifest, true, cancellationToken); var analysisRequest = new AnalysisRequest(analysisRequestParameters, this.analysisServicesFactory, stateRepository); // Run the Smart Detector this.tracer.TraceInformation($"Started running Smart Detector ID {smartDetectorManifest.Id}, Name {smartDetectorManifest.Name}"); List <Alert> alerts; try { alerts = await smartDetector.AnalyzeResourcesAsync(analysisRequest, detectorTracer, cancellationToken); this.tracer.TraceInformation( $"Completed running Smart Detector ID {smartDetectorManifest.Id}, Name {smartDetectorManifest.Name}, returning {alerts.Count} alerts"); } catch (DetectorNotReadyException dnre) { this.tracer.TraceWarning($"Smart Detector is not ready to run analysis yet, aborting analysis: {dnre.Message}"); return(new List <ContractsAlert>()); } catch (Exception e) { this.tracer.TraceError($"Failed running Smart Detector ID {smartDetectorManifest.Id}, Name {smartDetectorManifest.Name}: {e}"); throw new FailedToRunSmartDetectorException($"Calling Smart Detector '{smartDetectorManifest.Name}' failed with exception of type {e.GetType()} and message: {e.Message}", e); } // Verify that each alert belongs to one of the types declared in the Smart Detector manifest foreach (Alert alert in alerts) { if (!smartDetectorManifest.SupportedResourceTypes.Contains(alert.ResourceIdentifier.ResourceType)) { throw new UnidentifiedAlertResourceTypeException(alert.ResourceIdentifier); } } // Trace the number of alerts of each type foreach (var alertType in alerts.GroupBy(x => x.GetType().Name)) { this.tracer.TraceInformation($"Got {alertType.Count()} Alerts of type '{alertType.Key}'"); this.tracer.ReportMetric("AlertType", alertType.Count(), new Dictionary <string, string>() { { "AlertType", alertType.Key } }); } // Create results bool detectorSupportsAlertResolution = smartDetector is IResolvableAlertSmartDetector; List <ContractsAlert> results = new List <ContractsAlert>(); foreach (var alert in alerts) { ContractsAlert contractsAlert = alert.CreateContractsAlert( request, smartDetectorManifest.Name, this.analysisServicesFactory.UsedLogAnalysisClient, this.analysisServicesFactory.UsedMetricClient); // Handle resolution parameters in the alerts: // If the detector supports resolution - save the predicates for the resolution checks // If the detector doesn't support resolution - drop the resolution parameters (since they are useless) and error trace if (contractsAlert.ResolutionParameters != null) { if (detectorSupportsAlertResolution) { this.tracer.TraceInformation($"Alert {contractsAlert.CorrelationHash} has resolution parameters, so saving alert details for later use"); await stateRepository.StoreStateAsync( GetResolutionStateKey(contractsAlert.CorrelationHash), new ResolutionState { AnalysisRequestTime = analysisRequestParameters.RequestTime, AlertPredicates = alert.ExtractPredicates() }, cancellationToken); } else { this.tracer.TraceError($"Dropping resolution parameters from alert {contractsAlert.CorrelationHash}"); contractsAlert.ResolutionParameters = null; } } // And add the alert to the results results.Add(contractsAlert); } this.tracer.TraceInformation($"Returning {results.Count} results"); return(results); }
public void WhenProcessingAlertWithStateResolvedThenTheContractsAlertIsCreatedWithCorrectState() { ContractsAlert contractsAlert = CreateContractsAlert(new TestAlert(AlertState.Resolved)); Assert.AreEqual(ContractsAlertState.Resolved, contractsAlert.State); }
public void WhenProcessingAlertAndLogAndMetricClientsWereUsedThenTheSignalTypeIsCorrent() { ContractsAlert contractsAlert = CreateContractsAlert(new TestAlert(), usedLogAnalysisClient: true, usedMetricClient: true); Assert.AreEqual(SignalType.Multiple, contractsAlert.SignalType, "Unexpected signal type"); }
public void WhenProcessingAlertAndMetricClientWasUsedThenTheSignalTypeIsCorrect() { ContractsAlert contractsAlert = CreateContractsV2Alert(new PresentationTestAlert(), usedMetricClient: true); Assert.AreEqual(SignalType.Metric, contractsAlert.SignalType, "Unexpected signal type"); }
public void WhenProcessingAlertWithStateResolvedThenTheContractsAlertIsCreatedWithCorrectState() { ContractsAlert contractsAlert = CreateContractsV2Alert(new PresentationTestAlert("AlertTitle", default(ResourceIdentifier), AlertState.Resolved)); Assert.AreEqual(ContractsAlertState.Resolved, contractsAlert.State); }