Example #1
0
        public AggregatedAlert(StatusResults initialResults)
        {
            StatusAuditReport report = initialResults.Report ?? new StatusAuditReport(initialResults.Time, TimeSpan.Zero, null, StatusAuditAlert.None);

            CommonAlert = report.Alert;
            RatingSum   = report.Alert?.Rating ?? StatusRating.Okay;
            Sources     = new List <string>();
            Sources.Add(RenderSource(initialResults.SourceSystem));
            Target             = RenderTarget(initialResults.TargetSystem);
            TimeRange          = new DateTimeRange(initialResults.Time);
            Report             = report;
            AuditStartRange    = new DateTimeRange(report.AuditStartTime);
            AuditDurationRange = new TimeSpanRange(report.AuditDuration);
            NextAuditTime      = report.NextAuditTime;
            PropertyRanges     = new List <StatusPropertyRange>();
        }
Example #2
0
        public AggregatedAlert(string?source, string?target, DateTime time, StatusAuditReport?initialReport)
        {
            StatusAuditReport report = initialReport ?? new StatusAuditReport(time, TimeSpan.Zero, null, StatusAuditAlert.None);

            CommonAlert = report.Alert;
            RatingSum   = report.Alert?.Rating ?? StatusRating.Okay;
            Sources     = new List <string>();
            Sources.Add(RenderSource(source));
            Target             = RenderTarget(target);
            TimeRange          = new DateTimeRange(time);
            Report             = report;
            AuditStartRange    = new DateTimeRange(report.AuditStartTime);
            AuditDurationRange = new TimeSpanRange(report.AuditDuration);
            NextAuditTime      = report.NextAuditTime;
            PropertyRanges     = new List <StatusPropertyRange>();
        }
Example #3
0
        public void Aggregate(string?source, string target, DateTime time, StatusAuditReport?additionalReport)
        {
            StatusAuditReport report = additionalReport ?? new StatusAuditReport(time, TimeSpan.Zero, null, StatusAuditAlert.None);

            if (CommonAlert != report.Alert)
            {
                throw new InvalidOperationException("Only results with the same alert can be aggregated!");
            }
            if (Target != RenderTarget(target))
            {
                throw new InvalidOperationException("Only results with the same target can be aggregated!");
            }
            RatingSum += report.Alert?.Rating ?? StatusRating.Okay;
            Sources.Add(RenderSource(source));
            TimeRange.AddSample(time);
            AuditStartRange.AddSample(report.AuditStartTime);
            AuditDurationRange.AddSample(report.AuditDuration);
            NextAuditTime  = (NextAuditTime == null) ? report.NextAuditTime : new DateTime(Math.Min(NextAuditTime.Value.Ticks, (report.NextAuditTime ?? DateTime.MaxValue).Ticks));
            PropertyRanges = new List <StatusPropertyRange>();
        }
 /// <summary>
 /// Cosntructs a <see cref="StatusResults"/> from the specified property data (for serialization).
 /// </summary>
 /// <param name="sourceSystem">The name of the source system (if known).</param>
 /// <param name="targetSystem">The name of the target system (if any).</param>
 /// <param name="time">The <see cref="DateTime"/> when the properties were gathered.</param>
 /// <param name="relativeDetailLevel">The relative level of detail provided by the properties at this level.</param>
 /// <param name="properties">An enumeration of <see cref="StatusProperty"/> indicating various properties of the system.</param>
 /// <param name="natureOfSystem">A <see cref="StatusNatureOfSystem"/> indicating if or how audit results from children should be aggregated and how redundancy might be inferred.  Ignored if <paramref name="report"/> is not null.</param>
 /// <param name="children">An enumeration of <see cref="StatusResults"/> for child nodes in the status tree.  Ignored if <paramref name="report"/> is not null.</param>
 /// <param name="report">An optional <see cref="StatusAuditReport"/> containing the results of the most recent audit in case this is an auditable node.</param>
 private StatusResults(string sourceSystem, string targetSystem, DateTime time, int relativeDetailLevel, IEnumerable <StatusProperty> properties, StatusNatureOfSystem natureOfSystem, IEnumerable <StatusResults> children = null, StatusAuditReport report = null)
 {
     _sourceSystem        = sourceSystem;
     _targetSystem        = targetSystem;
     _time                = time;
     _relativeDetailLevel = relativeDetailLevel;
     _properties          = ImmutableArrayExtensions.FromEnumerable(properties);
     if (report != null)
     {
         _report         = report;
         _natureOfSystem = StatusNatureOfSystem.Leaf;
         _children       = ImmutableArray <StatusResults> .Empty;
     }
     else
     {
         _report         = null;
         _natureOfSystem = natureOfSystem;
         _children       = ImmutableArrayExtensions.FromEnumerable(children);
     }
 }
Example #5
0
        public void ComputeOverallRatingAndSort(string target = "")
        {
            float?            worstRating      = null;
            StatusRatingRange worstRatingRange = StatusRatingRange.Superlative + 1;
            bool childPending = false;

            // keep track of the worst property rating
            StatusAuditAlert?   worstAlert = null;
            StatusPropertyRange?worstAlertPropertyRange = null;

            foreach (StatusPropertyRange propertyRange in _propertyRanges)
            {
                string propertyPath = ComputeTarget(target, propertyRange.Name).TrimStart('/');
                // is there a thresholds to use to rate a property here or are there defaults?
                StatusPropertyThresholds?thresholds = (_thresholds ?? StatusPropertyThresholds.DefaultPropertyThresholds).GetThresholds(propertyPath);
                // is there a numeric value for which thresholds can be applied?
                float?minValue = null;
                if (!string.IsNullOrEmpty(propertyRange.MinValue))
                {
                    float f;
                    if (float.TryParse(propertyRange.MinValue, out f))
                    {
                        minValue = f;
                    }
                }
                float?maxValue = null;
                if (!string.IsNullOrEmpty(propertyRange.MaxValue))
                {
                    float f;
                    if (float.TryParse(propertyRange.MaxValue, out f))
                    {
                        maxValue = f;
                    }
                }
                // are there thresholds AND range values?
                if (thresholds != null && minValue != null && maxValue != null)
                {
                    // rate based on the value and the thresholds--is this now the worst rating?
                    StatusAuditAlert alert = thresholds.Rate(propertyRange.Name, minValue.Value, maxValue.Value);
                    if (Object.ReferenceEquals(worstAlert, null) || alert.Rating < worstAlert.Rating)
                    {
                        worstAlert = alert;
                        worstAlertPropertyRange = propertyRange;
                    }
                }
            }
            WorstPropertyAlert = worstAlert;
            WorstPropertyRange = worstAlertPropertyRange;

            StatusAuditAlert?assignedAlert        = OverallReport?.Alert;
            float?           assignedRating       = assignedAlert?.Rating;
            float?           worstThresholdRating = WorstPropertyAlert?.Rating;

            // the overall rating will depend on the type of system we're rating
            switch (NatureOfSystem)
            {
            case StatusNatureOfSystem.ChildrenIrrelevant:
                // there shouldn't be a report here--we don't care!
                System.Diagnostics.Debug.Assert(OverallReport == null);
                // let's rate the children anyway so we can add it to the report even if it doesn't affect the rating here
                foreach (StatusResultsOrganizer child in _children)
                {
                    // child not rated yet?
                    if (child.OverallRating == null)
                    {
                        child.ComputeOverallRatingAndSort(ComputeTarget(target, child.Target));
                    }
                    // pending?
                    if (child.SomeRatingsPending)
                    {
                        childPending = true;
                    }
                }
                OverallRating = StatusRating.Okay;
                break;

            case StatusNatureOfSystem.Leaf:
                // is there neither an explicitly-assigned rating nor a rating based on property thresholds?  bail out now without setting a new overall report
                if (assignedRating == null && worstThresholdRating == null)
                {
                    return;
                }
                OverallRating = assignedRating;
                break;

            default:
            case StatusNatureOfSystem.ChildrenHeterogenous:
                // find the worst child rating
                foreach (StatusResultsOrganizer child in _children)
                {
                    // child not rated yet?
                    if (child.OverallRating == null)
                    {
                        child.ComputeOverallRatingAndSort(ComputeTarget(target, child.Target));
                    }
                    if (child.OverallRating != null)
                    {
                        // aggregate results for each child
                        float childRating = child.OverallRating.Value;
                        if (worstRating == null || childRating < worstRating)
                        {
                            worstRating = childRating;
                        }
                        StatusRatingRange childRatingRange = StatusRating.FindRange(childRating);
                        if (childRatingRange < worstRatingRange)
                        {
                            worstRatingRange = childRatingRange;
                        }
                    }
                    // pending?
                    if (child.SomeRatingsPending)
                    {
                        childPending = true;
                    }
                }
                OverallRating = assignedRating = worstRating ?? StatusRating.Okay;
                break;

            case StatusNatureOfSystem.ChildrenHomogenous:
                // compute both ways because we don't know up front what the distribution of status rating ranges is
                float ratingSum        = 0.0f;
                float clampedRatingSum = 0.0f;
                int   ratedChildCount  = 0;
                // first count how many reports are in each clamped rating class
                int[] childrenWithRating = new int[StatusRating.Ranges];
                // make sure that if the number of clamped rating ranges is exactly three (we have to change the code here if this changes)
                System.Diagnostics.Debug.Assert(ClampedRating(StatusRating.Catastrophic) - ClampedRating(StatusRating.Okay) <= 2);
                // check all the child groups
                foreach (StatusResultsOrganizer child in Children)
                {
                    // child not rated yet?
                    if (child.OverallRating == null)
                    {
                        child.ComputeOverallRatingAndSort(ComputeTarget(target, child.Target));
                    }
                    if (child.OverallRating != null)
                    {
                        float             childRating   = child.OverallRating.Value;
                        float             clampedRating = ClampedRating(childRating);
                        StatusRatingRange range         = StatusRating.FindRange(clampedRating);
                        clampedRatingSum += clampedRating;
                        ratingSum        += childRating;
                        ++ratedChildCount;
                        System.Diagnostics.Debug.Assert(range >= StatusRatingRange.Fail && range <= StatusRatingRange.Okay);
                        ++childrenWithRating[(int)range];
                    }
                    // pending?
                    if (child.SomeRatingsPending)
                    {
                        childPending = true;
                    }
                }
                float rating;
#pragma warning disable CA1508  // this check is explicitly to make sure that the subsequent condition is changed if the number of ranges changes
                System.Diagnostics.Debug.Assert(StatusRating.Ranges == 5);
#pragma warning restore CA1508
                // are all of the ratings in the same range?
                if (childrenWithRating[(int)StatusRatingRange.Okay] == ratedChildCount || childrenWithRating[(int)StatusRatingRange.Alert] == ratedChildCount || childrenWithRating[(int)StatusRatingRange.Fail] == ratedChildCount)
                {
                    // the rating is the average of all the children
                    rating = ratingSum / ratedChildCount;
                }
                else     // we have ratings in more than one range, so the overall rating will be in the StatusRating.Alert range
                {
                    // the average clamped rating cannot be out of range because it's clamped, and it cannot be on a boundary because one of the children was not in the same range with the others!
                    System.Diagnostics.Debug.Assert(clampedRatingSum / ratedChildCount > -1.0f && clampedRatingSum / ratedChildCount < 3.0f);
                    rating = StatusRating.Fail + ((clampedRatingSum / ratedChildCount) + 1.0f) / 4.0f;
                }
                OverallRating = assignedRating = rating;
                break;
            }
            // is there a child that is pending (or is this node pending)?
            if (childPending || float.IsNaN(OverallReport?.Alert?.Rating ?? 0.0f))
            {
                SomeRatingsPending = true;
            }

            // only one child and it counts?
            if (_children.Count == 1 && NatureOfSystem != StatusNatureOfSystem.ChildrenIrrelevant)
            {
                // move everything from that child up into us
                StatusResultsOrganizer child = _children[0];
                _propertyRanges.Clear();
                _propertyRanges.AddRange(child.PropertyRanges);
                _children.Clear();
                _children.AddRange(child.Children);
                NatureOfSystem = child.NatureOfSystem;
                OverallRating  = child.OverallRating;
                OverallReport  = child.OverallReport;
                Source         = child.Source ?? Source;
                Target         = ComputeTarget(Target, child.Target);
                // note that the child's children should already be sorted
            }
            else if (_children.Count > 1) // sort the children (if any)
            {
                _children.Sort((a, b) => (a.OverallRating ?? StatusRating.Okay).CompareTo(b.OverallRating ?? StatusRating.Okay));
            }
            // is the threshold rating worse than the assigned rating?
            if (worstThresholdRating < OverallRating)
            {
                System.Diagnostics.Debug.Assert(worstThresholdRating == WorstPropertyAlert?.Rating);
                OverallRating = worstThresholdRating;
                // was there no report before
                if (OverallReport == null)
                {
                    // create a new report with the worst property value
                    OverallReport = new StatusAuditReport(AmbientClock.UtcNow, TimeSpan.Zero, null, WorstPropertyAlert);
                }
                else // there was an existing report
                {
                    // replace that report with a new one with the alert from the worst property rating
                    OverallReport = new StatusAuditReport(OverallReport.AuditStartTime, OverallReport.AuditDuration, OverallReport.NextAuditTime, WorstPropertyAlert);
                }
            }
            // still no rating?  that's okay (literally)
            else if (OverallRating == null)
            {
                OverallRating = StatusRating.Okay;
            }
        }