/// <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));
        }
Esempio n. 7
0
        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();
                }
            }
        }
Esempio n. 8
0
        /// <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));
        }
Esempio n. 9
0
        /// <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);
        }
Esempio n. 10
0
        /// <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);
        }
Esempio n. 12
0
        /// <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
        }
Esempio n. 14
0
        /// <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();
            }
        }