예제 #1
0
        public override RuleResult Run(IEnumerable <ServiceCallItem> items, ServiceCallStats stats)
        {
            RuleResult result = InitializeResult(DisplayName, "");

            result.Results.Add("Stats", stats);
            return(result);
        }
        public override RuleResult Run(IEnumerable <ServiceCallItem> items, ServiceCallStats stats)
        {
            RuleResult result = InitializeResult(DisplayName, Description);

            //check invalid log versions
            if (items.Count(item => item.m_logVersion == Constants.Version1509) > 0)
            {
                result.AddViolation(ViolationLevel.Warning, "Data version does not support this rule. You need an updated Xbox Live SDK to support this rule");
                return(result);
            }

            StringBuilder description = new StringBuilder();

            // Traverse through each pattern set found in rule parameter
            foreach (var pattern in m_MatchPatterns)
            {
                Dictionary <ServiceCallItem, int> matchesFoundDict = new Dictionary <ServiceCallItem, int>();

                int patternInstancesFound = 0;
                int lowXUIDInstancesFound = 0;

                // This first section reports on violations which are from batch calls made with not enough XUIDs in the request body
                foreach (ServiceCallItem thisItem in items)
                {
                    Match match = Regex.Match(thisItem.m_uri, pattern.Key.ToString());
                    if (match.Success)
                    {
                        patternInstancesFound++;
                        JObject requestBodyJSON = JObject.Parse(thisItem.m_reqBody);
                        var     values          = requestBodyJSON[pattern.Value.ToString()] as JArray;
                        if (values != null)
                        {
                            matchesFoundDict.Add(thisItem, values.Count);
                            if (values.Count <= m_minBatchXUIDsPerBatchCall)
                            {
                                lowXUIDInstancesFound++;
                                description.Clear();
                                description.AppendFormat("Batch call detected for endpoint for a small sized set of {0} XUIDs.", values.Count);
                                result.AddViolation(ViolationLevel.Warning, description.ToString(), thisItem);
                            }
                        }
                    }
                }  // finished traversing calls made to endpoint

                m_patternInstancesFound.Add(new Tuple <int, int>(patternInstancesFound, lowXUIDInstancesFound));
            } // end of foreach pattern in patterns

            var finalStats = PatternsFoundSumAsTuple();


            result.Results.Add("Total Batch Calls", finalStats.Item1);
            result.Results.Add("Min. Users Allowed", m_minBatchXUIDsPerBatchCall);
            result.Results.Add("Calls Below Count", finalStats.Item2);
            result.Results.Add("% Below Count", (double)(finalStats.Item2) / finalStats.Item1);

            return(result);
        }
        override public RuleResult Run(IEnumerable <ServiceCallItem> items, ServiceCallStats stats)
        {
            RuleResult result = InitializeResult(DisplayName, Description);

            StringBuilder description = new StringBuilder();

            m_avgCallsPerSecond         = 1000.0 * 1.0 / stats.m_avgTimeBetweenReqsMs;
            m_callStdDeviationPerSecond = 1000.0 * 1.0 / Math.Sqrt(stats.m_varTimeBetweenReqsMs);

            const float factor    = 2.0f;
            UInt32      burstSize = (UInt32)Math.Ceiling(m_avgCallsPerSecond) + (UInt32)Math.Ceiling(factor * m_callStdDeviationPerSecond);

            var allBurstsDetected = Utils.GetExcessCallsForTimeWindow(items, m_burstDetectionWindowMs, burstSize);

            // burst - is a list of calls (or just one call) that has exceeded the average requests per second rate
            foreach (var burst in allBurstsDetected)
            {
                if (burst.Count >= m_burstSizeToDetect)
                {
                    description.Clear();
                    description.AppendFormat("Burst increase of {0} calls to endpoint found.", burst.Count);

                    result.AddViolation(ViolationLevel.Warning, description.ToString(), burst);
                }
            }

            if (double.IsInfinity(m_avgCallsPerSecond))
            {
                result.Results.Add("Avg. Calls Per Sec.", "N/A");
                result.Results.Add("Std. Deviation", "N/A");
                result.Results.Add("Burst Size", m_burstSizeToDetect);
                result.Results.Add("Burst Window", m_burstDetectionWindowMs);
                result.Results.Add("Total Bursts", result.ViolationCount);
            }
            else
            {
                result.Results.Add("Avg. Calls Per Sec.", m_avgCallsPerSecond);
                result.Results.Add("Std. Deviation", m_callStdDeviationPerSecond);
                result.Results.Add("Burst Size", m_burstSizeToDetect);
                result.Results.Add("Burst Window", m_burstDetectionWindowMs);
                result.Results.Add("Total Bursts", result.ViolationCount);
            }

            return(result);
        }
예제 #4
0
        public override RuleResult Run(IEnumerable <ServiceCallItem> items, ServiceCallStats stats)
        {
            bool richpresenceFound   = false;
            var  richPresenceJsonObj = new { activity = new Object() };

            foreach (var call in items)
            {
                var richPresenceResult = JsonConvert.DeserializeAnonymousType(call.m_reqBody, richPresenceJsonObj);
                if (richPresenceResult != null && richPresenceResult.activity != null)
                {
                    richpresenceFound = true;
                    break;
                }
            }

            RuleResult result = InitializeResult(DisplayName, "");

            if (!richpresenceFound)
            {
                result.Violations.Add(new Violation());
            }
            return(result);
        }
예제 #5
0
        override public RuleResult Run(IEnumerable <ServiceCallItem> items, ServiceCallStats stats)
        {
            RuleResult result = InitializeResult(DisplayName, Description);

            m_stats = stats;
            m_endpointSustainedViolations = 0;
            m_endpointBurstViolations     = 0;

            // For set of limits, look through items to determine where excess calls occurred
            foreach (var limits in m_rateLimits)
            {
                // Filter the full list of service calls to those which apply to this set of limits
                List <ServiceCallItem> applicableCalls = items.Where(serviceCall =>
                {
                    foreach (var subpath in limits.m_applicableSubpaths)
                    {
                        var subpathRegex = new Regex("^" + Regex.Escape(subpath).Replace("\\?", ".").Replace("\\*", ".*") + "$");
                        if (subpathRegex.IsMatch(new Uri(serviceCall.m_uri).AbsolutePath))
                        {
                            return(true);
                        }
                    }
                    return(false);
                }).ToList();

                var sustainedExcessCallsPerWindow = Utils.GetExcessCallsForTimeWindow(applicableCalls, limits.m_sustainedTimePeriodSeconds * 1000, limits.m_sustainedCallLimit);
                var burstExcessCallsPerWindow     = Utils.GetExcessCallsForTimeWindow(applicableCalls, limits.m_burstTimePeriodSeconds * 1000, limits.m_burstCallLimit);

                foreach (var excessCalls in sustainedExcessCallsPerWindow)
                {
                    if (excessCalls.Count >= limits.m_sustainedCallLimit * 10)
                    {
                        var desc = $"Exceeding rate limits for '{limits.m_description}' required for title certification( limit of {limits.m_sustainedCallLimit * 10} calls with {excessCalls.Count} calls in {limits.m_sustainedTimePeriodSeconds} seconds).  Failure to adhere to the specified limits may block a title from release, and in-production issues with released titles may result in service suspension up to and including title removal.";
                        result.AddViolation(ViolationLevel.Error, desc, excessCalls);
                    }
                    else
                    {
                        var desc = $"Call frequency above the sustained call limit for '{limits.m_description}' (limit of {limits.m_sustainedCallLimit} exceeded with {excessCalls.Count} calls in {limits.m_sustainedTimePeriodSeconds} seconds).";
                        result.AddViolation(ViolationLevel.Warning, desc, excessCalls);
                    }
                    m_endpointSustainedViolations++;
                }

                foreach (var excessCalls in burstExcessCallsPerWindow)
                {
                    var desc = $"Call frequency above the burst call limit for '{limits.m_description}' (limit of {limits.m_burstCallLimit} exceeded with {excessCalls.Count} calls in {limits.m_burstTimePeriodSeconds} seconds).";
                    result.AddViolation(ViolationLevel.Warning, desc, excessCalls);
                    m_endpointBurstViolations++;
                }

                // The following is information that would only be useful for internal purposes.
                if (RulesEngine.m_isInternal)
                {
                    UInt64 avgTimeBetweenReqsMs = stats.m_avgTimeBetweenReqsMs;
                    UInt64 avgElapsedCallTimeMs = stats.m_avgElapsedCallTimeMs;
                    UInt64 maxElapsedCallTimeMs = stats.m_maxElapsedCallTimeMs;


                    if (avgTimeBetweenReqsMs > 0 && avgTimeBetweenReqsMs < limits.m_avgTimeBetweenReqsMs)
                    {
                        result.AddViolation(ViolationLevel.Warning, "Average time of " + avgTimeBetweenReqsMs + "ms between calls is too short");
                    }

                    if (avgElapsedCallTimeMs > 0 && avgElapsedCallTimeMs > limits.m_avgElapsedCallTimeMs)
                    {
                        result.AddViolation(ViolationLevel.Warning, "Calls are taking longer than expected to return " + avgElapsedCallTimeMs + "ms");
                    }

                    if (maxElapsedCallTimeMs > 0 && maxElapsedCallTimeMs > limits.m_maxElapsedCallTimeMs)
                    {
                        result.AddViolation(ViolationLevel.Warning, "The maximum call time for calls is greater than allowed " + maxElapsedCallTimeMs + "ms");
                    }
                }
            }

            result.Results.Add("Total Calls", m_stats == null ? 0 : m_stats.m_numCalls);
            result.Results.Add("Times Sustained Exceeded", m_endpointSustainedViolations);
            result.Results.Add("Times Burst Exceeded", m_endpointBurstViolations);

            return(result);
        }
예제 #6
0
        public override RuleResult Run(IEnumerable <ServiceCallItem> items, ServiceCallStats stats)
        {
            RuleResult result = InitializeResult(DisplayName, Description);

            if (items.Count() == 0)
            {
                return(result);
            }

            //check invalid log versions
            if (items.Count(item => item.m_logVersion == Constants.Version1509) > 0)
            {
                result.AddViolation(ViolationLevel.Warning, "Data version does not support this rule. You need an updated Xbox Live SDK to support this rule");
                return(result);
            }

            List <ServiceCallItem> allRepeats = new List <ServiceCallItem>();
            var nonShoulderTapItems           = items.Where(item => item.m_isShoulderTap == false);

            List <Sequence> sequences = new List <Sequence>();

            foreach (ServiceCallItem thisItem in nonShoulderTapItems)
            {
                if (thisItem.m_reqHeader.Contains("SocialManager"))
                {
                    continue;
                }

                // Used to skip over already analyzed repeated calls.
                if (allRepeats.Contains(thisItem))
                {
                    continue;
                }

                // Discover all repeats to thisItem
                var myRepeats = from item in nonShoulderTapItems
                                where ((item != thisItem) && (item.m_reqBodyHash == thisItem.m_reqBodyHash) && (item.m_uri == thisItem.m_uri))
                                select item;

                if (myRepeats.Count() > 1)
                {
                    var deltas = BuildDeltas(myRepeats.ToList());
                    sequences.AddRange(GenerateSequences(deltas, m_sameDeltaThresholdPercentage));

                    allRepeats.AddRange(myRepeats);
                }
            }

            if (sequences == null)
            {
                return(result);
            }

            //Process Violations
            StringBuilder description = new StringBuilder();

            foreach (var sequence in sequences.OrderByDescending(s => s.Length))
            {
                description.Clear();

                description.AppendFormat("Polling detected in a sequence of {0} calls at a rate of approximately {1} min:sec",
                                         sequence.Length, TimeSpan.FromTicks((long)sequence.m_averageDelta).ToString(@"mm\:ss\.fff"));

                result.AddViolation(ViolationLevel.Warning, description.ToString(), sequence.m_seqCalls);
            }


            result.Results.Add("Polling Sequences Found", result.ViolationCount);

            return(result);
        }
예제 #7
0
 // Parameters:
 //   - items: List of the ServiceCallItems that describe calls to this rule's endpoint
 //   - stats: Simple statistics that were computed while this set of calls was being processed.
 public abstract RuleResult Run(IEnumerable <ServiceCallItem> items, ServiceCallStats stats);
        public override RuleResult Run(IEnumerable <ServiceCallItem> items, ServiceCallStats stats)
        {
            RuleResult result = InitializeResult(DisplayName, Description);

            m_totalCalls          = items.Count();
            m_throttledCallsCount = items.Where(call => call.m_httpStatusCode == 429).Count();

            // We need to search over all of the calls to the endpoint
            for (int i = 0; i < m_totalCalls;)
            {
                var call = items.ElementAt(i);

                // If its not a throttled call, move to the next call
                if (call.m_httpStatusCode != 429)
                {
                    ++i;
                    continue;
                }

                // If it is throttled, start a list
                List <ServiceCallItem> throttledCallSet = new List <ServiceCallItem>();
                throttledCallSet.Add(items.ElementAt(i));
                var    throttledCall    = throttledCallSet.First();
                string throttleGuidline = string.Empty;

                try
                {
                    if (!string.IsNullOrEmpty(throttledCall.m_rspBody))
                    {
                        JObject response = JObject.Parse(throttledCall.m_rspBody);
                        if (response["maxRequests"] != null && response["periodInSeconds"] != null)
                        {
                            throttleGuidline = $"Allowed: {response["maxRequests"]} over {response["periodInSeconds"]} seconds.";
                        }
                    }
                }
                catch (Exception)
                {
                }


                // If there are 2 or more throttled calls in a row the title is not properly handling the response
                while (++i < m_throttledCallsCount)
                {
                    var nextCall = items.ElementAt(i);

                    if (call.m_httpStatusCode != 429)
                    {
                        ++i;
                        break;
                    }
                    else
                    {
                        throttledCallSet.Add(call);
                    }
                }

                // One call is a warning as we expect that they back off after getting the 429 response
                if (throttledCallSet.Count == 1)
                {
                    result.AddViolation(ViolationLevel.Warning, "Throttled call detected on endpoint. " + throttleGuidline, throttledCall);
                }
                // More that one in a row means that the title didn't handle the 429 and we want them to fix that.
                else
                {
                    result.AddViolation(ViolationLevel.Error, "Sequence of throttled calls detected on endpoint. " + throttleGuidline, throttledCallSet);
                }

                throttledCallSet.Clear();
            }


            result.Results.Add("Total Calls", TotalCalls);
            result.Results.Add("Throttled Calls", ThrottledCallCount);
            result.Results.Add("Percentage", ((double)ThrottledCallCount) / TotalCalls);

            return(result);
        }
        public override RuleResult Run(IEnumerable <ServiceCallItem> items, ServiceCallStats stats)
        {
            var result = InitializeResult("");

            // Check events type
            if (items.Count() == 0)
            {
                return(result);
            }

            var mpEvents      = items.Where(e => e.m_eventName.Contains("MultiplayerRound"));
            var mpStartEvents = mpEvents.Where(e => e.m_eventName.Contains("Start"));
            var mpEndEvents   = mpEvents.Where(e => e.m_eventName.Contains("End"));

            var debugData = mpEvents.Select(e => new { Name = e.m_eventName, ID = e.m_multiplayerCorrelationId });

            var matchEvents = mpEvents.GroupBy(e => e.m_multiplayerCorrelationId);

            // Edge case if a correlation id was reused
            var duplicates = matchEvents.Where(g => g.Count() > 2);

            var matchedTotalCount = matchEvents.Count(g => g.Count() == 2);
            var mismatchedEvents  = matchEvents.Where(g => g.Count() == 1);

            var mismatchedStartEventCount = mismatchedEvents.Count(g => g.Any(c => c.m_eventName.Contains("Start")));
            var mismatchedEndEventCount   = mismatchedEvents.Count(g => g.Any(c => c.m_eventName.Contains("End")));

            foreach (var set in duplicates)
            {
                var starts = set.Count(e => e.m_eventName.Contains("Start"));
                var ends   = set.Count(e => e.m_eventName.Contains("End"));

                if (starts > ends)
                {
                    mismatchedStartEventCount += (starts - ends);
                }
                else if (starts < ends)
                {
                    mismatchedEndEventCount += (ends - starts);
                }
            }

            var mismatchedTotalCount = mismatchedEvents.Count();

            double startToEndRatio     = (double)mpStartEvents.Count() / (double)mpEndEvents.Count();
            double unmatchedStartRatio = (double)mismatchedStartEventCount / (double)mpStartEvents.Count();
            double unmatchedEndRatio   = (double)mismatchedEndEventCount / (double)mpEndEvents.Count();

            if (startToEndRatio < .9 || startToEndRatio > 1.1)
            {
                result.AddViolation(ViolationLevel.Error, $"Ratio of Start and End events is {startToEndRatio:0.0%}. Allowed range is 90-110%.");
            }
            if (unmatchedStartRatio > .1)
            {
                result.AddViolation(ViolationLevel.Error, $"{unmatchedStartRatio:0.0%} of MultiplayerRoundStart events were unmatched. Allowed amount is less than 10%.");
            }
            if (unmatchedEndRatio > .1)
            {
                result.AddViolation(ViolationLevel.Error, $"{unmatchedEndRatio:0.0%} of MultiplayerRoundEnd events were unmatched. Allowed amount is less than 10%.");
            }

            result.Results.Add("TotalStartEvents", mpStartEvents.Count());
            result.Results.Add("TotalEndEvents", mpEndEvents.Count());
            result.Results.Add("StartToEndRatio", startToEndRatio);
            result.Results.Add("UnmatchedStartEventCount", mismatchedStartEventCount);
            result.Results.Add("UnmatchedStartPercentage", unmatchedStartRatio);
            result.Results.Add("UnmatchedEndEventCount", mismatchedEndEventCount);
            result.Results.Add("UnmatchedEndPercentage", unmatchedEndRatio);

            return(result);
        }
예제 #10
0
        override public RuleResult Run(IEnumerable <ServiceCallItem> items, ServiceCallStats stats)
        {
            RuleResult result = InitializeResult(DisplayName, Description);

            if (items.Count() == 0)
            {
                return(result);
            }

            //check invalid log versions
            if (items.Count(item => item.m_logVersion == Constants.Version1509) > 0)
            {
                result.AddViolation(ViolationLevel.Warning, "Data version does not support this rule. You need an updated Xbox Live SDK to support this rule");
                return(result);
            }

            StringBuilder description = new StringBuilder();

            List <ServiceCallItem> repeats = new List <ServiceCallItem>();

            m_totalCallsChecked = items.Count();

            foreach (ServiceCallItem thisItem in items.Where(item => item.m_isShoulderTap == false))
            {
                if (thisItem.m_reqHeader.Contains("SocialManager"))
                {
                    continue;
                }

                if (repeats.Contains(thisItem))
                {
                    continue;
                }

                var timeWindow = from item in items.Where(item => item.m_isShoulderTap == false)
                                 where (item.m_reqTimeUTC > thisItem.m_reqTimeUTC && ((item.m_reqTimeUTC - thisItem.m_reqTimeUTC) / TimeSpan.TicksPerMillisecond) < m_minAllowedRepeatIntervalMs)
                                 select item;

                List <ServiceCallItem> repeatedCalls = new List <ServiceCallItem>();

                repeatedCalls.Add(thisItem);

                foreach (var call in timeWindow)
                {
                    if (thisItem.m_reqBodyHash == call.m_reqBodyHash && thisItem.m_uri == call.m_uri)
                    {
                        repeatedCalls.Add(call);
                    }
                }

                if (repeatedCalls.Count > 1)
                {
                    description.Clear();
                    description.AppendFormat("Repeated call found {0} other times in calls to endpoint.", repeatedCalls.Count, thisItem.m_id);

                    result.AddViolation(ViolationLevel.Warning, description.ToString(), repeatedCalls);

                    repeats.AddRange(repeatedCalls);
                }
            }

            m_numberOfRepeats = repeats.Count;


            result.Results.Add("Total Calls", m_totalCallsChecked);
            result.Results.Add("Duplicates", m_numberOfRepeats);
            result.Results.Add("Percentage", ((double)m_numberOfRepeats) / m_totalCallsChecked);

            return(result);
        }
예제 #11
0
        public override RuleResult Run(IEnumerable <ServiceCallItem> items, ServiceCallStats stats)
        {
            RuleResult result = InitializeResult(DisplayName, Description);

            //check invalid log versions
            if (items.Count(item => item.m_logVersion == Constants.Version1509) > 0)
            {
                result.AddViolation(ViolationLevel.Warning, "Data version does not support this rule. You need an updated Xbox Live SDK to support this rule");
                return(result);
            }

            StringBuilder description = new StringBuilder();

            // Traverse through each pattern set found in rule parameter
            foreach (var pattern in m_MatchPatterns)
            {
                Dictionary <ServiceCallItem, int> matchesFoundDict = new Dictionary <ServiceCallItem, int>();

                foreach (ServiceCallItem thisItem in items)
                {
                    Match match = Regex.Match(thisItem.m_uri, pattern.Key);
                    if (match.Success)
                    {
                        JObject requestBodyJSON = JObject.Parse(thisItem.m_reqBody);
                        var     values          = requestBodyJSON.SelectToken(pattern.Value) as JArray;
                        if (values != null)
                        {
                            matchesFoundDict.Add(thisItem, values.Count);
                        }
                    }
                }  // finished traversing calls made to endpoint

                m_totalBatchCallCount = (UInt32)matchesFoundDict.Count;

                // For all the matches found, report on batch sets which happened within a specific time window
                int numDictItems = matchesFoundDict.Count;
                if (numDictItems >= 2)
                {
                    int startWindowIdx = 0;
                    List <ServiceCallItem> callsWithinWindow = new List <ServiceCallItem>();
                    int totalXUIDsForWindow = 0;
                    totalXUIDsForWindow += matchesFoundDict.Values.ElementAt(startWindowIdx);
                    callsWithinWindow.Add(matchesFoundDict.Keys.ElementAt(startWindowIdx));
                    for (int endWindowIdx = 1; endWindowIdx < matchesFoundDict.Count(); ++endWindowIdx)
                    {
                        UInt64 timeElapsed = (UInt64)Math.Abs((float)
                                                              (matchesFoundDict.Keys.ElementAt(endWindowIdx).m_reqTimeUTC - matchesFoundDict.Keys.ElementAt(startWindowIdx).m_reqTimeUTC) / TimeSpan.TicksPerMillisecond);
                        if (timeElapsed <= m_BatchSetDetectionWindowsMs)
                        {
                            callsWithinWindow.Add(matchesFoundDict.Keys.ElementAt(endWindowIdx));
                            totalXUIDsForWindow += matchesFoundDict.Values.ElementAt(endWindowIdx);
                        }
                        else //exceeded window
                        {
                            if (callsWithinWindow.Count >= 2)
                            {
                                result.AddViolation(ViolationLevel.Warning, $"A set of {callsWithinWindow.Count} Batch Calls was found within a time window of ({m_BatchSetDetectionWindowsMs}ms) to endpoint. Total XUID count ({totalXUIDsForWindow}). Consider combining into one call.", callsWithinWindow);
                            }

                            startWindowIdx = endWindowIdx; // shift window
                            //reset figures
                            totalXUIDsForWindow = 0;
                            callsWithinWindow.Clear();
                        }
                    }
                    // in case we exited the last for early because we never exceeded the time window, then call
                    // the following function once more to handle any dangling reports.
                    if (callsWithinWindow.Count >= 2)
                    {
                        result.AddViolation(ViolationLevel.Warning, $"A set of {callsWithinWindow.Count} Batch Calls was found within a time window of ({m_BatchSetDetectionWindowsMs}ms) to endpoint. Total XUID count ({totalXUIDsForWindow}). Consider combining into one call.", callsWithinWindow);
                    }
                }
            } // end of foreach pattern in patterns


            result.Results.Add("Total Batch Calls", m_totalBatchCallCount);
            result.Results.Add("Allowed Time Between Calls in ms", m_BatchSetDetectionWindowsMs);
            result.Results.Add("Times Exceeded", result.ViolationCount);
            result.Results.Add("Potential Reduced Call Count", m_totalBatchCallCount - result.ViolationCount);

            return(result);
        }
예제 #12
0
        override public RuleResult Run(IEnumerable <ServiceCallItem> items, ServiceCallStats stats)
        {
            RuleResult result = InitializeResult(DisplayName, Description);

            m_stats = stats;
            m_endpointSustainedViolations = 0;
            m_endpointBurstViolations     = 0;

            // Look through items to determine where excess calls occurred
            var sustainedExcessCallsPerWindow = Utils.GetExcessCallsForTimeWindow(items, m_sustainedTimePeriodSeconds * 1000, m_sustainedCallLimit);
            var burstExcessCallsPerWindow     = Utils.GetExcessCallsForTimeWindow(items, m_burstTimePeriodSeconds * 1000, m_burstCallLimit);

            foreach (var excessCalls in sustainedExcessCallsPerWindow)
            {
                if (excessCalls.Count >= m_sustainedCallLimit * 10)
                {
                    var desc = $"Exceeding service rate limits required for title certification( limit of {m_sustainedCallLimit * 10} calls with {excessCalls.Count} calls in {m_sustainedTimePeriodSeconds} seconds).  Failure to adhere to the specified limits may block a title from release, and in-production issues with released titles may result in service suspension up to and including title removal.";
                    result.AddViolation(ViolationLevel.Error, desc, excessCalls);
                }
                else
                {
                    var desc = $"Call frequency above the sustained call limit of {m_sustainedCallLimit} with {excessCalls.Count} calls in {m_sustainedTimePeriodSeconds} seconds to endpoint.";
                    result.AddViolation(ViolationLevel.Warning, desc, excessCalls);
                }
                m_endpointSustainedViolations++;
            }

            foreach (var excessCalls in burstExcessCallsPerWindow)
            {
                var desc = $"Call frequency above the burst call limit of {m_burstCallLimit} with {excessCalls.Count} calls {m_burstTimePeriodSeconds} seconds to endpoint.";
                result.AddViolation(ViolationLevel.Warning, desc, excessCalls);
                m_endpointBurstViolations++;
            }

            // The following is information that would only be useful for internal purposes.
            if (RulesEngine.m_isInternal)
            {
                UInt64 avgTimeBetweenReqsMs = stats.m_avgTimeBetweenReqsMs;
                UInt64 avgElapsedCallTimeMs = stats.m_avgElapsedCallTimeMs;
                UInt64 maxElapsedCallTimeMs = stats.m_maxElapsedCallTimeMs;


                if (avgTimeBetweenReqsMs > 0 && avgTimeBetweenReqsMs < m_avgTimeBetweenReqsMs)
                {
                    result.AddViolation(ViolationLevel.Warning, "Average time of " + avgTimeBetweenReqsMs + "ms between calls is too short");
                }

                if (avgElapsedCallTimeMs > 0 && avgElapsedCallTimeMs > m_avgElapsedCallTimeMs)
                {
                    result.AddViolation(ViolationLevel.Warning, "Calls are taking longer than expected to return " + avgElapsedCallTimeMs + "ms");
                }

                if (maxElapsedCallTimeMs > 0 && maxElapsedCallTimeMs > m_maxElapsedCallTimeMs)
                {
                    result.AddViolation(ViolationLevel.Warning, "The maximum call time for calls is greater than allowed " + maxElapsedCallTimeMs + "ms");
                }
            }


            result.Results.Add("Total Calls", m_stats == null ? 0 : m_stats.m_numCalls);
            result.Results.Add("Sustained Call Period", m_sustainedTimePeriodSeconds.ToString() + "sec.");
            result.Results.Add("Sustained Call Limit", m_sustainedCallLimit);
            result.Results.Add("Times Sustained Exceeded", m_endpointSustainedViolations);
            result.Results.Add("Burst Call Period", m_burstTimePeriodSeconds.ToString() + "sec.");
            result.Results.Add("Burst Call Limit", m_burstCallLimit);
            result.Results.Add("Times Burst Exceeded", m_endpointBurstViolations);

            return(result);
        }
예제 #13
0
        override public RuleResult Run(IEnumerable <ServiceCallItem> items, ServiceCallStats stats)
        {
            RuleResult result = InitializeResult(DisplayName, Description);

            StringBuilder description = new StringBuilder();

            m_stats = stats;
            m_endpointSustainedViolations = 0;
            m_endpointBurstViolations     = 0;

            // Look through items to determine where excess calls occurred
            var sustainedExcessCallsPerWindow = Utils.GetExcessCallsForTimeWindow(items, m_sustainedTimePeriodSeconds * 1000, (UInt32)(m_sustainedCallLimit * .9));
            var burstExcessCallsPerWindow     = Utils.GetExcessCallsForTimeWindow(items, m_burstTimePeriodSeconds * 1000, (UInt32)(m_burstCallLimit * .9));

            foreach (var excessCalls in sustainedExcessCallsPerWindow)
            {
                description.Clear();
                if (excessCalls.Count < m_sustainedCallLimit)
                {
                    description.AppendFormat("Call frequency nearing the sustained call limit of {0} with {1} calls to endpoint.", m_sustainedCallLimit, excessCalls.Count);
                    result.AddViolation(ViolationLevel.Warning, description.ToString(), excessCalls);
                }
                else
                {
                    m_endpointSustainedViolations++;
                    description.AppendFormat("Call frequency above the sustained call limit of {0} with {1} calls to endpoint.", m_sustainedCallLimit, excessCalls.Count);
                    result.AddViolation(ViolationLevel.Error, description.ToString(), excessCalls);
                }
            }

            foreach (var excessCalls in burstExcessCallsPerWindow)
            {
                description.Clear();
                if (excessCalls.Count < m_burstCallLimit)
                {
                    description.AppendFormat("Call frequency nearing the burst call limit of {0} with {1} calls to endpoint.", m_burstCallLimit, excessCalls.Count);
                    result.AddViolation(ViolationLevel.Warning, description.ToString(), excessCalls);
                }
                else
                {
                    m_endpointBurstViolations++;
                    description.AppendFormat("Call frequency above the burst call limit of {0} with {1} calls to endpoint.", m_burstCallLimit, excessCalls.Count);
                    result.AddViolation(ViolationLevel.Error, description.ToString(), excessCalls);
                }
            }

            // The following is information that would only be useful for internal purposes.
            if (RulesEngine.m_isInternal)
            {
                UInt64 avgTimeBetweenReqsMs = stats.m_avgTimeBetweenReqsMs;
                UInt64 avgElapsedCallTimeMs = stats.m_avgElapsedCallTimeMs;
                UInt64 maxElapsedCallTimeMs = stats.m_maxElapsedCallTimeMs;


                if (avgTimeBetweenReqsMs > 0 && avgTimeBetweenReqsMs < m_avgTimeBetweenReqsMs)
                {
                    result.AddViolation(ViolationLevel.Warning, "Average time of " + avgTimeBetweenReqsMs + "ms between calls is too short");
                }

                if (avgElapsedCallTimeMs > 0 && avgElapsedCallTimeMs > m_avgElapsedCallTimeMs)
                {
                    result.AddViolation(ViolationLevel.Warning, "Calls are taking longer than expected to return " + avgElapsedCallTimeMs + "ms");
                }

                if (maxElapsedCallTimeMs > 0 && maxElapsedCallTimeMs > m_maxElapsedCallTimeMs)
                {
                    result.AddViolation(ViolationLevel.Warning, "The maximum call time for calls is greater than allowed " + maxElapsedCallTimeMs + "ms");
                }
            }


            result.Results.Add("Total Calls", m_stats == null ? 0 : m_stats.m_numCalls);
            result.Results.Add("Sustained Call Period", m_sustainedTimePeriodSeconds.ToString() + "sec.");
            result.Results.Add("Sustained Call Limit", m_sustainedCallLimit);
            result.Results.Add("Times Sustained Exceeded", m_endpointSustainedViolations);
            result.Results.Add("Burst Call Period", m_burstTimePeriodSeconds.ToString() + "sec.");
            result.Results.Add("Burst Call Limit", m_burstCallLimit);
            result.Results.Add("Times Burst Exceeded", m_endpointBurstViolations);

            return(result);
        }