/// <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 }
#pragma warning restore CS0612 // Type or member is obsolete; Task to remove obsolete code #1312924 /// <summary> /// Creates an <see cref="AlertProperty"/> based on an alert presentation V2 property /// </summary> /// <param name="alert">The alert</param> /// <param name="presentationAttribute">The attribute defining the presentation V2 of the alert property</param> /// <param name="propertyDefaultName">The property default name</param> /// <param name="propertyValue">The property value</param> /// <returns>An <see cref="AlertProperty"/></returns> private static AlertProperty CreateAlertProperty(Alert alert, AlertPresentationPropertyV2Attribute presentationAttribute, string propertyDefaultName, object propertyValue) { // Get the attribute display name string displayName = StringExtensions.EvaluateInterpolatedString(presentationAttribute.DisplayName, alert); // Get the property name string propertyName = string.IsNullOrWhiteSpace(presentationAttribute.PropertyName) ? propertyDefaultName : presentationAttribute.PropertyName; // Return the presentation property according to the property type switch (presentationAttribute) { case AlertPresentationChartAttribute chartAttribute: if (!(propertyValue is IList <ChartPoint> listValues)) { throw new ArgumentException("An AlertPresentationChartAttribute can only be applied to properties of type IList<ChartPoint>"); } return(new ChartAlertProperty( propertyName, displayName, presentationAttribute.Order, ConvertChartTypeToContractsChartType(chartAttribute.ChartType), ConvertChartAxisTypeToContractsChartType(chartAttribute.XAxisType), ConvertChartAxisTypeToContractsChartType(chartAttribute.YAxisType), listValues.Select(point => new ContractsChartPoint(point.X, point.Y)).ToList())); case AlertPresentationLongTextAttribute longTextAttribute: return(new LongTextAlertProprety(propertyName, displayName, presentationAttribute.Order, PropertyValueToString(propertyValue))); case AlertPresentationTextAttribute textAttribute: return(new TextAlertProperty(propertyName, displayName, presentationAttribute.Order, PropertyValueToString(propertyValue))); case AlertPresentationUrlAttribute urlAttribute: if (!(propertyValue is Uri uriValue)) { throw new ArgumentException("An AlertPresentationUrlAttribute can only be applied to properties of type Uri"); } if (!uriValue.IsAbsoluteUri) { throw new ArgumentException("The URI supplied must be absolute"); } string linkText = StringExtensions.EvaluateInterpolatedString(urlAttribute.LinkText, alert); return(new TextAlertProperty(propertyName, displayName, presentationAttribute.Order, $"<a href=\"{uriValue.ToString()}\">{linkText}</a>")); case AlertPresentationKeyValueAttribute keyValueAttribute: if (!(propertyValue is IDictionary <string, string> keyValuePropertyValue)) { throw new ArgumentException("An AlertPresentationKeyValueAttribute can only be applied to properties of type IDictionary<string, string>"); } if (keyValueAttribute.ShowHeaders) { string keyHeaderName = StringExtensions.EvaluateInterpolatedString(keyValueAttribute.KeyHeaderName, alert); string valueHeaderName = StringExtensions.EvaluateInterpolatedString(keyValueAttribute.ValueHeaderName, alert); return(new KeyValueAlertProperty(propertyName, displayName, presentationAttribute.Order, keyHeaderName, valueHeaderName, keyValuePropertyValue)); } else { return(new KeyValueAlertProperty(propertyName, displayName, presentationAttribute.Order, keyValuePropertyValue)); } case AlertPresentationSingleColumnTableAttribute singleColumnTableAttribute: if (!(propertyValue is IList singleColumnTablePropertyValue)) { throw new ArgumentException("An AlertPresentationSingleColumnTableAttribute can only be applied to properties of type IList"); } return(new TableAlertProperty(propertyName, displayName, presentationAttribute.Order, singleColumnTableAttribute.ShowHeaders, singleColumnTablePropertyValue)); case AlertPresentationTableAttribute tableAttribute: if (!(propertyValue is IList tablePropertyValue)) { throw new ArgumentException("An AlertPresentationTableAttribute can only be applied to properties of type IList"); } Type tableRowType = GetGenericListType(propertyValue.GetType()); if (tableRowType == null) { throw new ArgumentException("An AlertPresentationTableAttribute can only be applied to properties of type IList<>"); } return(new TableAlertProperty(propertyName, displayName, presentationAttribute.Order, tableAttribute.ShowHeaders, CreateTableColumnsFromRowType(tableRowType), tablePropertyValue)); default: throw new InvalidEnumArgumentException($"Unable to handle presentation attribute of type {presentationAttribute.GetType().Name}"); } }