/// <summary>
        /// Return the matched sampling rule name if the sampler finds one
        /// and decide to sample. If no sampling rule matched, it falls back
        /// to <see cref="LocalizedSamplingStrategy"/> "ShouldTrace" implementation.
        /// All optional arguments are extracted from incoming requests by
        /// X-Ray middleware to perform path based sampling.
        /// </summary>
        /// <param name="input">Instance of <see cref="SamplingInput"/>.</param>
        /// <returns>Instance of <see cref="SamplingResponse"/>.</returns>
        public SamplingResponse ShouldTrace(SamplingInput input)
        {
            if (!_isPollerStarted) // Start pollers lazily
            {
                Start();
            }

            if (string.IsNullOrEmpty(input.ServiceType))
            {
                input.ServiceType = AWSXRayRecorder.Instance.Origin;
            }

            TimeStamp    time       = TimeStamp.CurrentTime();
            SamplingRule sampleRule = _ruleCache.GetMatchedRule(input, time);

            if (sampleRule != null)
            {
                _logger.DebugFormat("Rule {0} is selected to make a sampling decision.", sampleRule.RuleName);
                return(ProcessMatchedRule(sampleRule, time));
            }
            else
            {
                _logger.InfoFormat("No effective centralized sampling rule match. Fallback to local rules.");
                return(_localFallbackRules.ShouldTrace(input));
            }
        }
        /// <summary>
        /// Returns matched rule for the given <see cref="SamplingInput"/>.
        /// </summary>
        /// <param name="input">Instance of <see cref="SamplingInput"/>.</param>
        /// <param name="time">Current time.</param>
        /// <returns>Instance of <see cref="SamplingRule"/>.</returns>
        public SamplingRule GetMatchedRule(SamplingInput input, TimeStamp time)
        {
            if (IsExpired(time))
            {
                return(null);
            }

            SamplingRule matchedRule = null;

            _cacheLock.EnterReadLock();
            try
            {
                foreach (var item in _cache)
                {
                    var rule = item.Value;
                    if (matchedRule != null)
                    {
                        break;
                    }

                    if (rule.Match(input) || rule.IsDefault())
                    {
                        matchedRule = rule;
                    }
                }
            }
            finally
            {
                _cacheLock.ExitReadLock();
            }

            return(matchedRule);
        }
        /// <summary>
        /// Determines whether or not this sampling rule applies to the incoming
        /// request based on some of the request's parameters.
        /// </summary>
        /// <param name="input">Instance of <see cref="SamplingInput"/>.</param>
        /// <returns>True if the rule matches.</returns>
        internal bool Match(SamplingInput input)
        {
            try
            {
                return(StringExtension.IsMatch(input.ServiceName, ServiceName) && StringExtension.IsMatch(input.Method, HTTPMethod) && StringExtension.IsMatch(input.Url, URLPath) && StringExtension.IsMatch(input.Host, Host) && StringExtension.IsMatch(input.ServiceType, ServiceType));
            }
            catch (RegexMatchTimeoutException e)
            {
                _logger.Error(e, "Match rule timeout. Rule: serviceName = {0}, urlPath = {1}, httpMethod = {2}, host = {3}, serviceType = {4}. Input: serviceNameToMatch = {5}, urlPathToMatch = {6}, httpMethodToMatch = {7}, hostToMatch = {8}, serviceTypeToMatch = {9}.", ServiceName, URLPath,
                              HTTPMethod, Host, ServiceType, input.ServiceName, input.Url, input.Method, input.Host, input.ServiceType);

                return(false);
            }
        }