Пример #1
0
        /// <summary>
        /// Add a new custom sampled metric sample from the specified sample packet
        /// </summary>
        /// <param name="newMetricSamplePacket">The sample packet to create a new metric sample object from</param>
        internal CustomSampledMetricSample Add(CustomSampledMetricSamplePacket newMetricSamplePacket)
        {
            if (newMetricSamplePacket == null)
            {
                throw new ArgumentNullException(nameof(newMetricSamplePacket), "A new custom sampled metric sample packet object must be provided to add it to the collection.");
            }

            //now we have to create a new sample object to wrap the provided packet
            CustomSampledMetricSample newMetricSample = new CustomSampledMetricSample(m_CustomSampledMetric, newMetricSamplePacket);

            //and forward to our normal add routine
            Add(newMetricSample);

            //returning our new wrapped object
            return(newMetricSample);
        }
        /// <summary>
        /// Compute the counter value for this sample compared with the provided baseline sample (if any)
        /// </summary>
        /// <remarks>
        /// A baseline sample is required when the current metric requires multiple samples to determine results.
        /// The baseline sample must be for a date and time prior to this sample for correct results.
        /// </remarks>
        /// <param name="baselineSample">The previous baseline sample to calculate a difference for</param>
        /// <returns>The calculated counter value</returns>
        public override double ComputeValue(SampledMetricSample baselineSample)
        {
            if ((baselineSample == null) && (RequiresMultipleSamples))
            {
                throw new ArgumentNullException(nameof(baselineSample), "A baseline metric sample is required and none was provided.");
            }

            if ((baselineSample != null) && (baselineSample.Timestamp > Timestamp))
            {
                throw new ArgumentOutOfRangeException(nameof(baselineSample), baselineSample.Timestamp, "The baseline sample must be for a date & time before this sample to be valid for comparison.");
            }

            //Now lets do some math!  The math we have to do depends on the sampled metric type.
            MetricSampleType metricType = Metric.Definition.MetricSampleType;

            //First, eliminate the values that don't need math at all
            if (RequiresMultipleSamples == false)
            {
                return Value;
            }

            //and now we're down to stuff that requires math.
            double calculatedResult;
            CustomSampledMetricSamplePacket baselineSamplePacket = (CustomSampledMetricSamplePacket) baselineSample.Packet;

            if (metricType == MetricSampleType.TotalCount)
            {
                //here we want to calculate the difference between the start and end of our sampled period, ignoring interim samples.
                calculatedResult = Packet.RawValue - baselineSamplePacket.RawValue;
            }
            else if (metricType == MetricSampleType.TotalFraction)
            {
                double valueDelta = Packet.RawValue - baselineSamplePacket.RawValue;
                double baseDelta = Packet.BaseValue - baselineSamplePacket.BaseValue;

                //Protect from a divide by zero case.
                if ((baseDelta == 0) && (valueDelta != 0))
                {
                    throw new DivideByZeroException(string.Format(CultureInfo.InvariantCulture, "The baseline delta is zero however the value delta is not, indicating a data collection problem in the original data.  Value delta: {0}", valueDelta));
                }

                calculatedResult = valueDelta / baseDelta;
            }
            else if (metricType == MetricSampleType.IncrementalCount) 
            {
                //The new value is just the total at the end, so we just get the value property which knows enough to sum things.
                calculatedResult = Value;
            }
            else if (metricType == MetricSampleType.IncrementalFraction)
            {
                double value = Value;
                double baseValue = BaseValue;

                //Protect from a divide by zero case.
                if ((baseValue == 0) && (value != 0))
                {
                    throw new DivideByZeroException(string.Format(CultureInfo.InvariantCulture, "The baseline value is zero however the value is not, indicating a data collection problem in the original data.  Value: {0}", value));
                }

                calculatedResult = value / baseValue;
            }
            else 
            {
                // This is dumb, but FxCop doesn't seem to notice that the duplicate casts are in non-overlapping code paths.
                // So to make it happy, moving the cast outside these last two if's (now nested instead of chained).
                // Note: This will throw an exception if it fails to cast, before we check the MetricSampleType enum.
                CustomSampledMetricSample customSample = (CustomSampledMetricSample)baselineSample;
                if (metricType == MetricSampleType.RawCount)
                {
                    //we need to do a weighted average of the values in the range
                    //now life gets more fun - we have to do a weighted average of everything in between the baseline sample and this sample.
                    CustomSampledMetricSample[] samples = SampleRange(customSample);
                    calculatedResult = CalculateWeightedAverageValue(samples);
                }
                else if (metricType == MetricSampleType.RawFraction)
                {
                    //we do a weighted average of the values in the range, then divide
                    CustomSampledMetricSample[] samples = SampleRange(customSample);
                    double value = CalculateWeightedAverageValue(samples);
                    double baseValue = CalculateWeightedAverageBaseValue(samples);

                    //Protect from a divide by zero case.
                    if ((baseValue == 0) && (value != 0))
                    {
                        throw new DivideByZeroException(string.Format(CultureInfo.InvariantCulture, "The baseline value is zero however the value is not, indicating a data collection problem in the original data.  Value: {0}", value));
                    }

                    calculatedResult = value / baseValue;
                }
                else
                {
                    //oh hell.  We probably should have used a switch statement, but I didn't. Why?  Perhaps someone will 
                    //call that out in code review, but I think it was because of how much code is in each of these cases.
                    throw new ArgumentOutOfRangeException();
                }
            }

            return calculatedResult;
        }
        private double? m_BaseValue; //We calculate this on first reference, then cache the result because it can take time.

        /// <summary>
        /// Create a new sample object for the provided metric and raw sample packet.
        /// </summary>
        /// <remarks>The metric sample is automatically added to the samples collection of the provided metric object.</remarks>
        /// <param name="metric">The metric object this sample applies to.</param>
        /// <param name="metricSamplePacket">The raw sample data packet.</param>
        internal CustomSampledMetricSample(CustomSampledMetric metric, CustomSampledMetricSamplePacket metricSamplePacket)
            : base(metric, metricSamplePacket, (metric.Definition).RequiresMultipleSamples)
        {

        }