/// <summary> /// Run the Smart Detector, by delegating the call to the registered <see cref="ISmartDetectorRunner"/> /// </summary> /// <param name="request">The Smart Detector request</param> /// <param name="cancellationToken">The cancellation token</param> /// <returns>A <see cref="Task{TResult}"/>, returning the alerts presentations generated by the Smart Detector</returns> private static async Task <List <ContractsAlert> > RunSmartDetectorAsync(SmartDetectorExecutionRequest request, CancellationToken cancellationToken) { ISmartDetectorRunner smartDetectorRunner = container.Resolve <ISmartDetectorRunner>(); bool shouldDetectorTrace = bool.Parse(ConfigurationReader.ReadConfig("ShouldDetectorTrace", required: true)); return(await smartDetectorRunner.RunAsync(request, shouldDetectorTrace, cancellationToken)); }
public static async Task <HttpResponseMessage> RunAsync( [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "analyze")] HttpRequestMessage request, TraceWriter log, ExecutionContext context, CancellationToken cancellationToken) { using (IUnityContainer childContainer = Container.CreateChildContainer().WithTracer(log, true)) { // Create a tracer for this run (that will also log to the specified TraceWriter) IExtendedTracer tracer = childContainer.Resolve <IExtendedTracer>(); tracer.TraceInformation($"Analyze function request received with invocation Id {context.InvocationId}"); tracer.AddCustomProperty("FunctionName", context.FunctionName); tracer.AddCustomProperty("InvocationId", context.InvocationId.ToString("N", CultureInfo.InvariantCulture)); try { // Trace app counters (before analysis) tracer.TraceAppCounters(); // Read the request SmartDetectorExecutionRequest smartDetectorExecutionRequest = await request.Content.ReadAsAsync <SmartDetectorExecutionRequest>(cancellationToken); tracer.AddCustomProperty("SmartDetectorId", smartDetectorExecutionRequest.SmartDetectorId); tracer.TraceInformation($"Analyze request received: {JsonConvert.SerializeObject(smartDetectorExecutionRequest)}"); // Process the request ISmartDetectorRunner runner = childContainer.Resolve <ISmartDetectorRunner>(); bool shouldDetectorTrace = bool.Parse(ConfigurationReader.ReadConfig("ShouldDetectorTrace", required: true)); List <ContractsAlert> alertPresentations = await runner.RunAsync(smartDetectorExecutionRequest, shouldDetectorTrace, cancellationToken); tracer.TraceInformation($"Analyze completed, returning {alertPresentations.Count} Alerts"); // Create the response with StringContent to prevent Json from serializing to a string var response = request.CreateResponse(HttpStatusCode.OK); response.Content = new StringContent(JsonConvert.SerializeObject(alertPresentations), Encoding.UTF8, "application/json"); return(response); } catch (AnalysisFailedException afe) { // Handle the exception TopLevelExceptionHandler.TraceUnhandledException(afe, tracer, log); // Return error status return(request.CreateResponse(afe.StatusCode, afe.ReasonPhrase)); } catch (Exception e) { // Handle the exception TopLevelExceptionHandler.TraceUnhandledException(e, tracer, log); // Return error status return(request.CreateResponse(HttpStatusCode.InternalServerError, e.Message)); } finally { // Trace app counters (after analysis) tracer.TraceAppCounters(); } } }
private static ContractsAlert CreateContractsAlert(Alert alert, bool nullQueryRunInfo = false, bool usedLogAnalysisClient = false, bool usedMetricClient = false) { QueryRunInfo queryRunInfo = null; if (!nullQueryRunInfo) { queryRunInfo = new QueryRunInfo { Type = alert.ResourceIdentifier.ResourceType == ResourceType.ApplicationInsights ? TelemetryDbType.ApplicationInsights : TelemetryDbType.LogAnalytics, ResourceIds = new List <string>() { "resourceId1", "resourceId2" } }; } string resourceId = "resourceId"; var request = new SmartDetectorExecutionRequest { ResourceIds = new List <string>() { resourceId }, SmartDetectorId = "smartDetectorId", Cadence = TimeSpan.FromDays(1), }; return(alert.CreateContractsAlert(request, SmartDetectorName, queryRunInfo, usedLogAnalysisClient, usedMetricClient)); }
/// <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)); }
/// <summary> /// Runs the Smart Detector analysis, in a separate process /// </summary> /// <param name="request">The request</param> /// <param name="shouldDetectorTrace">Determines if the detector's traces are emitted</param> /// <param name="cancellationToken">The cancellation token</param> /// <returns>A <see cref="Task{TResult}"/>, returning the generated alerts presentations</returns> public async Task <List <ContractsAlert> > RunAsync(SmartDetectorExecutionRequest request, bool shouldDetectorTrace, CancellationToken cancellationToken) { // Find the executable location string currentDllPath = new Uri(typeof(SmartDetectorRunnerInChildProcess).Assembly.CodeBase).AbsolutePath; string exePath = Path.Combine(Path.GetDirectoryName(currentDllPath) ?? string.Empty, ChildProcessName); if (!File.Exists(exePath)) { this.tracer.TraceError($"Verification of executable path {exePath} failed"); throw new FileNotFoundException("Could not find child process executable", ChildProcessName); } try { // Run the child process return(await this.childProcessManager.RunChildProcessAsync <List <ContractsAlert> >(exePath, request, cancellationToken)); } catch (ChildProcessFailedException e) { if (Enum.IsDefined(typeof(HttpStatusCode), e.ExitCode)) { throw new AnalysisFailedException((HttpStatusCode)e.ExitCode, e.Message, e); } throw new AnalysisFailedException($"Running Smart Detector analysis in child process failed with exit code {e.ExitCode} and message: {e.Message}", e); } }
private ContractsAlert CreatePresentation(Alert alert, bool nullQueryRunInfo = false) { QueryRunInfo queryRunInfo = null; if (!nullQueryRunInfo) { queryRunInfo = new QueryRunInfo { Type = alert.ResourceIdentifier.ResourceType == ResourceType.ApplicationInsights ? TelemetryDbType.ApplicationInsights : TelemetryDbType.LogAnalytics, ResourceIds = new List <string>() { "resourceId1", "resourceId2" } }; } string resourceId = "resourceId"; var request = new SmartDetectorExecutionRequest { ResourceIds = new List <string>() { resourceId }, SmartDetectorId = "smartDetectorId", DataEndTime = DateTime.UtcNow.AddMinutes(-20), Cadence = TimeSpan.FromDays(1), }; return(alert.CreateContractsAlert(request, SmartDetectorName, queryRunInfo)); }
public static async Task <HttpResponseMessage> RunAsync( [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "analyze")] HttpRequestMessage request, TraceWriter log, ExecutionContext context, CancellationToken cancellationToken) { using (IUnityContainer childContainer = Container.CreateChildContainer().WithTracer(log, true)) { // Create a tracer for this run (that will also log to the specified TraceWriter) ITracer tracer = childContainer.Resolve <ITracer>(); tracer.TraceInformation($"Analyze function request received with invocation Id {context.InvocationId}"); tracer.AddCustomProperty("FunctionName", context.FunctionName); tracer.AddCustomProperty("InvocationId", context.InvocationId.ToString("N")); try { // Trace app counters (before analysis) tracer.TraceAppCounters(); // Read the request SmartDetectorExecutionRequest smartDetectorExecutionRequest = await request.Content.ReadAsAsync <SmartDetectorExecutionRequest>(cancellationToken); tracer.AddCustomProperty("SmartDetectorId", smartDetectorExecutionRequest.SmartDetectorId); tracer.TraceInformation($"Analyze request received: {JsonConvert.SerializeObject(smartDetectorExecutionRequest)}"); // Process the request ISmartDetectorRunner runner = childContainer.Resolve <ISmartDetectorRunner>(); List <ContractsAlert> alertPresentations = await runner.RunAsync(smartDetectorExecutionRequest, cancellationToken); tracer.TraceInformation($"Analyze completed, returning {alertPresentations.Count} Alerts"); // Return the generated presentations return(request.CreateResponse(HttpStatusCode.OK, alertPresentations)); } catch (Exception e) { // Handle the exception TopLevelExceptionHandler.TraceUnhandledException(e, tracer, log); // Return error status return(request.CreateResponse(HttpStatusCode.InternalServerError, e.Message)); } finally { // Trace app counters (after analysis) tracer.TraceAppCounters(); } } }
/// <summary> /// Runs the Smart Detector analysis, in a separate process /// </summary> /// <param name="request">The request</param> /// <param name="cancellationToken">The cancellation token</param> /// <returns>A <see cref="Task{TResult}"/>, returning the generated alerts presentations</returns> public async Task <List <ContractsAlert> > RunAsync(SmartDetectorExecutionRequest request, CancellationToken cancellationToken) { // Find the executable location string currentDllPath = new Uri(typeof(SmartDetectorRunnerInChildProcess).Assembly.CodeBase).AbsolutePath; string exePath = Path.Combine(Path.GetDirectoryName(currentDllPath) ?? string.Empty, ChildProcessName); if (!File.Exists(exePath)) { this.tracer.TraceError($"Verification of executable path {exePath} failed"); throw new FileNotFoundException("Could not find child process executable", ChildProcessName); } // Run the child process return(await this.childProcessManager.RunChildProcessAsync <List <ContractsAlert> >(exePath, request, cancellationToken)); }
/// <summary> /// Loads the Smart Detector, runs it, and returns the generated alert presentations /// </summary> /// <param name="request">The Smart Detector request</param> /// <param name="cancellationToken">The cancellation token</param> /// <returns>A <see cref="Task{TResult}"/>, returning the list of Alerts presentations generated by the Smart Detector</returns> public async Task <List <ContractsAlert> > RunAsync(SmartDetectorExecutionRequest request, CancellationToken cancellationToken) { // Read the Smart Detector's package this.tracer.TraceInformation($"Loading Smart Detector package for Smart Detector ID {request.SmartDetectorId}"); SmartDetectorPackage smartDetectorPackage = await this.smartDetectorRepository.ReadSmartDetectorPackageAsync(request.SmartDetectorId, cancellationToken); SmartDetectorManifest smartDetectorManifest = smartDetectorPackage.Manifest; this.tracer.TraceInformation($"Read Smart Detector package, ID {smartDetectorManifest.Id}, Version {smartDetectorManifest.Version}"); // Load the Smart Detector ISmartDetector smartDetector = this.smartDetectorLoader.LoadSmartDetector(smartDetectorPackage); this.tracer.TraceInformation($"Smart Detector instance loaded successfully, ID {smartDetectorManifest.Id}"); // Get the resources on which to run the Smart Detector List <ResourceIdentifier> resources = await this.GetResourcesForSmartDetector(request.ResourceIds, smartDetectorManifest, cancellationToken); // Create state repository IStateRepository stateRepository = this.stateRepositoryFactory.Create(request.SmartDetectorId); // Run the Smart Detector this.tracer.TraceInformation($"Started running Smart Detector ID {smartDetectorManifest.Id}, Name {smartDetectorManifest.Name}"); List <Alert> alerts; try { var analysisRequest = new AnalysisRequest(resources, request.DataEndTime, request.Cadence, request.AlertRuleResourceId, this.analysisServicesFactory, stateRepository); alerts = await smartDetector.AnalyzeResourcesAsync(analysisRequest, this.tracer, cancellationToken); this.tracer.TraceInformation($"Completed running Smart Detector ID {smartDetectorManifest.Id}, Name {smartDetectorManifest.Name}, returning {alerts.Count} alerts"); } catch (Exception e) { this.tracer.TraceInformation($"Failed running Smart Detector ID {smartDetectorManifest.Id}, Name {smartDetectorManifest.Name}: {e.Message}"); throw new SmartDetectorCustomException(e.GetType().ToString(), e.Message, e.StackTrace); } // 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 List <ContractsAlert> results = new List <ContractsAlert>(); foreach (var alert in alerts) { QueryRunInfo queryRunInfo = await this.queryRunInfoProvider.GetQueryRunInfoAsync(new List <ResourceIdentifier>() { alert.ResourceIdentifier }, cancellationToken); results.Add(alert.CreateContractsAlert(request, smartDetectorManifest.Name, queryRunInfo)); } this.tracer.TraceInformation($"Returning {results.Count} results"); return(results); }
/// <summary> /// Creates a presentation from a alert /// </summary> /// <param name="alert">The alert</param> /// <param name="request">The Smart Detector request</param> /// <param name="smartDetectorName">The Smart Detector name</param> /// <param name="queryRunInfo">The query run information</param> /// <returns>The presentation</returns> public static ContractsAlert CreateContractsAlert(this Alert alert, SmartDetectorExecutionRequest request, string smartDetectorName, QueryRunInfo queryRunInfo) { // A null alert has null presentation if (alert == null) { return(null); } // Create presentation elements for each alert property Dictionary <string, string> predicates = new Dictionary <string, string>(); List <AlertProperty> alertProperties = new List <AlertProperty>(); Dictionary <string, string> rawProperties = new Dictionary <string, string>(); foreach (PropertyInfo property in alert.GetType().GetProperties()) { // Get the property value string propertyValue = PropertyValueToString(property.GetValue(alert)); if (string.IsNullOrWhiteSpace(propertyValue)) { // not accepting empty properties continue; } rawProperties[property.Name] = propertyValue; // Check if this property is a predicate if (property.GetCustomAttribute <AlertPredicatePropertyAttribute>() != null) { predicates[property.Name] = propertyValue; } // Get the presentation attribute AlertPresentationPropertyAttribute attribute = property.GetCustomAttribute <AlertPresentationPropertyAttribute>(); if (attribute != null) { // Verify that if the entity is a chart or query, then query run information was provided if (queryRunInfo == null && (attribute.Section == AlertPresentationSection.Chart || attribute.Section == AlertPresentationSection.AdditionalQuery)) { throw new InvalidAlertPresentationException($"The presentation contains an item for the {attribute.Section} section, but no telemetry data client was provided"); } // Get the attribute title and information balloon - support interpolated strings string attributeTitle = Smart.Format(attribute.Title, alert); string attributeInfoBalloon = Smart.Format(attribute.InfoBalloon, alert); // Add the presentation property alertProperties.Add(new AlertProperty { Name = attributeTitle, Value = propertyValue, DisplayCategory = GetDisplayCategoryFromPresentationSection(attribute.Section), InfoBalloon = attributeInfoBalloon }); } } string id = string.Join("##", alert.GetType().FullName, JsonConvert.SerializeObject(request), JsonConvert.SerializeObject(alert)).Hash(); string resourceId = alert.ResourceIdentifier.ToResourceId(); string correlationHash = string.Join("##", predicates.OrderBy(x => x.Key).Select(x => x.Key + "|" + x.Value)).Hash(); // Return the presentation object return(new ContractsAlert { Id = id, Title = alert.Title, ResourceId = resourceId, CorrelationHash = correlationHash, SmartDetectorId = request.SmartDetectorId, SmartDetectorName = smartDetectorName, AnalysisTimestamp = DateTime.UtcNow, AnalysisWindowSizeInMinutes = (int)request.Cadence.TotalMinutes, Properties = alertProperties, RawProperties = rawProperties, QueryRunInfo = queryRunInfo }); }
private void TestInitialize(ResourceType requestResourceType, ResourceType smartDetectorResourceType) { this.testContainer = new UnityContainer(); this.testContainer.RegisterType <ISmartDetectorRunner, SmartDetectorRunner>(); this.testContainer.RegisterInstance(new Mock <IExtendedTracer>().Object); ResourceIdentifier resourceId; switch (requestResourceType) { case ResourceType.Subscription: resourceId = new ResourceIdentifier(requestResourceType, "subscriptionId", string.Empty, string.Empty); break; case ResourceType.ResourceGroup: resourceId = new ResourceIdentifier(requestResourceType, "subscriptionId", "resourceGroup", string.Empty); break; default: resourceId = new ResourceIdentifier(requestResourceType, "subscriptionId", "resourceGroup", "resourceName"); break; } this.resourceIds = new List <string>() { resourceId.ToResourceId() }; this.request = new SmartDetectorExecutionRequest { ResourceIds = this.resourceIds, Cadence = TimeSpan.FromDays(1), SmartDetectorId = "1" }; var smartDetectorManifest = new SmartDetectorManifest("1", "Test Smart Detector", "Test Smart Detector description", Version.Parse("1.0"), "assembly", "class", new List <ResourceType>() { smartDetectorResourceType }, new List <int> { 60 }, null); this.smartDetectorPackage = new SmartDetectorPackage(smartDetectorManifest, new Dictionary <string, byte[]> { ["TestSmartDetectorLibrary"] = Array.Empty <byte>() }); var smartDetectorRepositoryMock = new Mock <ISmartDetectorRepository>(); smartDetectorRepositoryMock .Setup(x => x.ReadSmartDetectorPackageAsync(It.IsAny <string>(), It.IsAny <CancellationToken>())) .ReturnsAsync(() => this.smartDetectorPackage); this.testContainer.RegisterInstance <ISmartDetectorRepository>(smartDetectorRepositoryMock.Object); this.testContainer.RegisterInstance <IInternalAnalysisServicesFactory>(new Mock <IInternalAnalysisServicesFactory>().Object); this.smartDetector = new TestSmartDetector { ExpectedResourceType = smartDetectorResourceType }; var smartDetectorLoaderMock = new Mock <ISmartDetectorLoader>(); smartDetectorLoaderMock .Setup(x => x.LoadSmartDetector(this.smartDetectorPackage)) .Returns(this.smartDetector); this.testContainer.RegisterInstance <ISmartDetectorLoader>(smartDetectorLoaderMock.Object); var azureResourceManagerClientMock = new Mock <IExtendedAzureResourceManagerClient>(); azureResourceManagerClientMock .Setup(x => x.GetAllResourceGroupsInSubscriptionAsync(It.IsAny <string>(), It.IsAny <CancellationToken>())) .ReturnsAsync((string subscriptionId, CancellationToken cancellationToken) => new List <ResourceIdentifier>() { new ResourceIdentifier(ResourceType.ResourceGroup, subscriptionId, "resourceGroupName", string.Empty) }); azureResourceManagerClientMock .Setup(x => x.GetAllResourcesInSubscriptionAsync(It.IsAny <string>(), It.IsAny <IEnumerable <ResourceType> >(), It.IsAny <CancellationToken>())) .ReturnsAsync((string subscriptionId, IEnumerable <ResourceType> resourceTypes, CancellationToken cancellationToken) => new List <ResourceIdentifier>() { new ResourceIdentifier(ResourceType.VirtualMachine, subscriptionId, "resourceGroupName", "resourceName") }); azureResourceManagerClientMock .Setup(x => x.GetAllResourcesInResourceGroupAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <IEnumerable <ResourceType> >(), It.IsAny <CancellationToken>())) .ReturnsAsync((string subscriptionId, string resourceGroupName, IEnumerable <ResourceType> resourceTypes, CancellationToken cancellationToken) => new List <ResourceIdentifier>() { new ResourceIdentifier(ResourceType.VirtualMachine, subscriptionId, resourceGroupName, "resourceName") }); this.testContainer.RegisterInstance <IExtendedAzureResourceManagerClient>(azureResourceManagerClientMock.Object); this.testContainer.RegisterInstance <IQueryRunInfoProvider>(new Mock <IQueryRunInfoProvider>().Object); var stateRepositoryMock = new Mock <IStateRepository>(); var stateRepositoryFactoryMock = new Mock <IStateRepositoryFactory>(); stateRepositoryFactoryMock.Setup(m => m.Create(It.IsAny <string>(), It.IsAny <string>())).Returns(stateRepositoryMock.Object); this.testContainer.RegisterInstance <IStateRepositoryFactory>(stateRepositoryFactoryMock.Object); }
/// <summary> /// Run the Smart Detector, by delegating the call to the registered <see cref="ISmartDetectorRunner"/> /// </summary> /// <param name="request">The Smart Detector request</param> /// <param name="cancellationToken">The cancellation token</param> /// <returns>A <see cref="Task{TResult}"/>, returning the alerts presentations generated by the Smart Detector</returns> private static async Task <List <ContractsAlert> > RunSmartDetectorAsync(SmartDetectorExecutionRequest request, CancellationToken cancellationToken) { ISmartDetectorRunner smartDetectorRunner = container.Resolve <ISmartDetectorRunner>(); return(await smartDetectorRunner.RunAsync(request, cancellationToken)); }
/// <summary> /// Creates a presentation from an alert /// </summary> /// <param name="alert">The alert</param> /// <param name="request">The Smart Detector request</param> /// <param name="smartDetectorName">The Smart Detector name</param> /// <param name="queryRunInfo">The query run information</param> /// <param name="usedLogAnalysisClient">Indicates whether a log analysis client was used to create the alert</param> /// <param name="usedMetricClient">Indicates whether a metric client was used to create the alert</param> /// <returns>The presentation</returns> public static ContractsAlert CreateContractsAlert(this Alert alert, SmartDetectorExecutionRequest request, string smartDetectorName, QueryRunInfo queryRunInfo, bool usedLogAnalysisClient, bool usedMetricClient) { // A null alert has null presentation if (alert == null) { return(null); } // Create presentation elements for each alert property Dictionary <string, string> predicates = new Dictionary <string, string>(); #pragma warning disable CS0612 // Type or member is obsolete; Task to remove obsolete code #1312924 List <AlertPropertyLegacy> alertPropertiesLegacy = new List <AlertPropertyLegacy>(); #pragma warning restore CS0612 // Type or member is obsolete; Task to remove obsolete code #1312924 List <AlertProperty> alertProperties = new List <AlertProperty>(); Dictionary <string, string> rawProperties = new Dictionary <string, string>(); List <string> alertBaseClassPropertiesNames = typeof(Alert).GetProperties().Select(p => p.Name).ToList(); foreach (PropertyInfo property in alert.GetType().GetProperties()) { // Get the property value object propertyValue = property.GetValue(alert); string propertyStringValue = PropertyValueToString(propertyValue); if (string.IsNullOrWhiteSpace(propertyStringValue) || (propertyValue is ICollection value && value.Count == 0)) { // not accepting empty properties continue; } rawProperties[property.Name] = propertyStringValue; // Check if this property is a predicate if (property.GetCustomAttribute <AlertPredicatePropertyAttribute>() != null) { predicates[property.Name] = propertyStringValue; } // Get the v1 presentation attribute AlertPresentationPropertyAttribute presentationAttribute = property.GetCustomAttribute <AlertPresentationPropertyAttribute>(); if (presentationAttribute != null) { alertPropertiesLegacy.Add(CreateAlertPropertyLegacy(alert, presentationAttribute, queryRunInfo, propertyStringValue)); } // Get the v2 presentation attribute AlertPresentationPropertyV2Attribute presentationV2Attribute = property.GetCustomAttribute <AlertPresentationPropertyV2Attribute>(); if (presentationV2Attribute != null) { alertProperties.Add(CreateAlertProperty(alert, presentationV2Attribute, property.Name, propertyValue)); } else if (!alertBaseClassPropertiesNames.Contains(property.Name)) { // Get the raw alert property - a property with no presentation alertProperties.Add(new RawAlertProperty(property.Name, propertyValue)); } } string id = string.Join("##", alert.GetType().FullName, JsonConvert.SerializeObject(request), JsonConvert.SerializeObject(alert)).Hash(); string resourceId = alert.ResourceIdentifier.ToResourceId(); string correlationHash = string.Join("##", predicates.OrderBy(x => x.Key).Select(x => x.Key + "|" + x.Value)).Hash(); // Get the alert's signal type based on the clients used to create the alert SignalType signalType = GetSignalType(usedLogAnalysisClient, usedMetricClient); // Return the presentation object #pragma warning disable CS0612 // Type or member is obsolete; Task to remove obsolete code #1312924 return(new ContractsAlert { Id = id, State = (alert.State == AlertState.Active) ? ContractsAlertState.Active : ContractsAlertState.Resolved, Title = alert.Title, ResourceId = resourceId, CorrelationHash = correlationHash, SmartDetectorId = request.SmartDetectorId, SmartDetectorName = smartDetectorName, AnalysisTimestamp = DateTime.UtcNow, AnalysisWindowSizeInMinutes = (int)request.Cadence.TotalMinutes, Properties = alertPropertiesLegacy, AlertProperties = alertProperties, RawProperties = rawProperties, QueryRunInfo = queryRunInfo, SignalType = signalType }); #pragma warning restore CS0612 // Type or member is obsolete; Task to remove obsolete code #1312924 }
/// <summary> /// Runs the Smart Detector. /// </summary> /// <param name="resources">The resources which the Smart Detector should run on</param> /// <param name="analysisCadence">The analysis cadence</param> /// <param name="startTimeRange">The start time</param> /// <param name="endTimeRange">The end time</param> /// <returns>A task that runs the Smart Detector</returns> public async Task RunAsync(List <ResourceIdentifier> resources, TimeSpan analysisCadence, DateTime startTimeRange, DateTime endTimeRange) { this.cancellationTokenSource = new CancellationTokenSource(); IStateRepository stateRepository = this.stateRepositoryFactory.Create(this.smartDetectorId); List <string> resourceIds = resources.Select(resource => resource.ResourceName).ToList(); this.Alerts.Clear(); try { // Run Smart Detector this.IsSmartDetectorRunning = true; int totalRunsAmount = (int)((endTimeRange.Subtract(startTimeRange).Ticks / analysisCadence.Ticks) + 1); int currentRunNumber = 1; for (var currentTime = startTimeRange; currentTime <= endTimeRange; currentTime = currentTime.Add(analysisCadence)) { this.tracer.TraceInformation($"Start analysis, end of time range: {currentTime}"); var analysisRequest = new AnalysisRequest(resources, currentTime, analysisCadence, null, this.analysisServicesFactory, stateRepository); var newAlerts = await this.smartDetector.AnalyzeResourcesAsync( analysisRequest, this.Tracer, this.cancellationTokenSource.Token); var smartDetectorExecutionRequest = new SmartDetectorExecutionRequest { ResourceIds = resourceIds, SmartDetectorId = this.smartDetectorManifes.Id, Cadence = analysisCadence, DataEndTime = currentTime }; // Show the alerts that were found in this iteration newAlerts.ForEach(async newAlert => { QueryRunInfo queryRunInfo = await this.queryRunInfoProvider.GetQueryRunInfoAsync(new List <ResourceIdentifier>() { newAlert.ResourceIdentifier }, this.cancellationTokenSource.Token); ContractsAlert contractsAlert = newAlert.CreateContractsAlert(smartDetectorExecutionRequest, this.smartDetectorManifes.Name, queryRunInfo); // Create Azure resource identifier ResourceIdentifier resourceIdentifier = ResourceIdentifier.CreateFromResourceId(contractsAlert.ResourceId); this.Alerts.Add(new EmulationAlert(contractsAlert, resourceIdentifier, currentTime)); }); this.tracer.TraceInformation($"completed {currentRunNumber} of {totalRunsAmount} runs"); currentRunNumber++; } string separator = "====================================================================================================="; this.tracer.TraceInformation($"Total alerts found: {this.Alerts.Count} {Environment.NewLine} {separator}"); } catch (OperationCanceledException) { this.Tracer.TraceError("Smart Detector run was canceled."); } catch (Exception e) { this.Tracer.ReportException(e); } finally { this.IsSmartDetectorRunning = false; this.cancellationTokenSource?.Dispose(); } }