コード例 #1
0
        private MetricValueCollection OnCalculateValues(MetricSampleInterval interval, int intervals, DateTimeOffset startDateTime, DateTimeOffset endDateTime, IEventMetricValueDefinition trendValue)
        {
            MetricValueCollection newMetricValueCollection;

            //we really have two different algorithms:  If the user specified shortest, then we are just going
            //to use every sample we have and hope for the best (provided they are in the time range)
            //Otherwise, we have a BIG FANCY ALGORYTHM.
            if (interval == MetricSampleInterval.Shortest)
            {
                newMetricValueCollection = OnCalculateValuesShortest(startDateTime, endDateTime, trendValue);
            }
            else
            {
                //since they aren't using shortest, we are going to use the intervals input option which better not be zero or negative.
                if (intervals < 1)
                {
                    throw new ArgumentOutOfRangeException(nameof(intervals), intervals, "The number of intervals must be positive and greater than zero.");
                }

                //forward to our big boy method.
                newMetricValueCollection = OnCalculateValuesInterval(interval, intervals, startDateTime, endDateTime, trendValue);
            }

            //we've ripped through the whole data set and now have our value set.  Return it to our caller
            return(newMetricValueCollection);
        }
コード例 #2
0
        /// <summary>
        /// Calculate displayable values based on the full information captured for this metric
        /// </summary>
        /// <remarks>
        /// The raw values may not be suitable for display depending on the unit the values are captured in, and
        /// depending on how the data was sampled it may not display well because of uneven sampling if processed
        /// directly.
        /// </remarks>
        /// <param name="interval">The requested data sample size</param>
        /// <param name="intervals">The number of intervals to have between each value exactly.</param>
        /// <param name="startDateTime">The earliest date to retrieve data for</param>
        /// <param name="endDateTime">The last date to retrieve data for</param>
        /// <param name="trendValue">The specific event metric value to trend</param>
        /// <returns>A metric value set suitable for display</returns>
        public IMetricValueCollection CalculateValues(MetricSampleInterval interval, int intervals, DateTimeOffset?startDateTime, DateTimeOffset?endDateTime, IEventMetricValueDefinition trendValue)
        {
            DateTimeOffset effectiveStartDateTime = (startDateTime == null ? this.StartDateTime : (DateTimeOffset)startDateTime);
            DateTimeOffset effectiveEndDateTime   = (endDateTime == null ? this.EndDateTime : (DateTimeOffset)endDateTime);

            return(OnCalculateValues(interval, intervals, effectiveStartDateTime, effectiveEndDateTime, trendValue));
        }
コード例 #3
0
        void IPacket.ReadFields(PacketDefinition definition, SerializedPacket packet)
        {
            switch (definition.Version)
            {
            case 1:
                packet.GetField("MetricTypeName", out m_MetricTypeName);
                packet.GetField("CategoryName", out m_CategoryName);
                packet.GetField("CounterName", out m_CounterName);

                int rawSampleType;
                packet.GetField("SampleType", out rawSampleType);
                m_SampleType = (SampleType)rawSampleType;

                packet.GetField("Caption", out m_Caption);
                packet.GetField("Description", out m_Description);

                int rawInterval;
                packet.GetField("Interval", out rawInterval);
                m_Interval = (MetricSampleInterval)rawInterval;

                //and our stuff that we have to calculate
                Name = MetricDefinition.GetKey(MetricTypeName, CategoryName, CounterName); //generate the name

                m_ReadOnly = true;                                                         //if we got read out of a file, we're read only.
                break;

            default:
                throw new GibraltarPacketVersionException(definition.Version);
            }

            //we are NOT live - we came from a serialization reader
            IsLive = false;
        }
コード例 #4
0
 /// <summary>Create a new metric value set.</summary>
 /// <param name="caption">The end-user caption for this metric value set.</param>
 /// <param name="description">The end-user description for this metric value set.</param>
 /// <param name="interval">The interval to bias to.</param>
 /// <param name="intervals">The number of intervals to have between each value exactly.</param>
 /// <param name="unitCaption">An end-user short display caption for the unit axis.</param>
 public MetricValueCollection(string caption, string description, MetricSampleInterval interval, int intervals, string unitCaption)
 {
     //copy our metric's caption and description
     m_Caption     = caption;
     m_Description = description;
     m_Interval    = interval;
     m_Intervals   = intervals;
     m_UnitCaption = unitCaption;
 }
コード例 #5
0
 /// <summary>Create a new metric value set.</summary>
 /// <param name="trendValue">The event metric value this value set relates to.</param>
 /// <param name="interval">The interval to bias to.</param>
 /// <param name="intervals">The number of intervals to have between each value exactly.</param>
 /// <param name="unitCaption">An end-user short display caption for the unit axis.</param>
 public MetricValueCollection(EventMetricValueDefinition trendValue, MetricSampleInterval interval, int intervals, string unitCaption)
 {
     //copy our metric's caption and description
     m_Caption     = trendValue.Caption;
     m_Description = trendValue.Description;
     m_Interval    = interval;
     m_Intervals   = intervals;
     m_UnitCaption = unitCaption;
 }
コード例 #6
0
        private MetricValueCollection OnCalculateValues(MetricSampleInterval interval, int intervals, DateTimeOffset startDateTime, DateTimeOffset endDateTime)
        {
            EnsureSorted();

            MetricValueCollection newMetricValueCollection = new MetricValueCollection("Log Messages", "The number of log messages recorded per interval.", interval, intervals, "Messages");

            //And prep for our process loop
            DateTimeOffset windowStartDateTime = startDateTime;
            DateTimeOffset windowEndDateTime   = CalculateOffset(windowStartDateTime, interval, intervals);


            //because we're doing a simple count by time interval, it's easiest to iterate
            //through all of the intervals and then count the matches within.
            int curSampleIndex = 0;

            //roll through the samples to find our first sample index we care about so we can count from there.
            for (curSampleIndex = 0; curSampleIndex < Count; curSampleIndex++)
            {
                if (this[curSampleIndex].Timestamp >= startDateTime)
                {
                    //bingo!  this is the first one we want
                    break;
                }
            }

            while (windowEndDateTime <= endDateTime)
            {
                //count how many messages we go through to get to our target.
                int curMessageCount = 0;

                while (curSampleIndex < Count)
                {
                    if (this[curSampleIndex].Timestamp >= windowEndDateTime)
                    {
                        //this is the first one in the next interval (or later), so don't count it and stop looping.
                        break;
                    }
                    else
                    {
                        //this bad boy is in our range, count it
                        curMessageCount++;
                    }

                    //and make damn sure we advance our index by one to not get into an infinite loop
                    curSampleIndex++;
                }

                //record off this interval
                new MetricValue(newMetricValueCollection, windowStartDateTime, curMessageCount);

                //and prep for the next loop
                windowStartDateTime = windowEndDateTime;
                windowEndDateTime   = CalculateOffset(windowStartDateTime, interval, intervals);
            }

            return(newMetricValueCollection);
        }
コード例 #7
0
        /// <summary>
        /// Calculates the offset date from the provided baseline for the specified interval
        /// </summary>
        /// <remarks>
        /// To calculate a backwards offset (the date that is the specified interval before the baseline) use a negative
        /// number of invervals. For example, -1 intervals will give you one interval before the baseline.
        /// </remarks>
        /// <param name="baseline">The date and time to calculate an offset date and time from</param>
        /// <param name="interval">The interval to add or subtract from the baseline</param>
        /// <param name="intervals">The number of intervals to go forward or (if negative) backwards</param>
        /// <returns></returns>
        private DateTimeOffset CalculateOffset(DateTimeOffset baseline, MetricSampleInterval interval, int intervals)
        {
            DateTimeOffset returnVal;  //just so we're initialized with SOMETHING.
            int            intervalCount = intervals;

            //since they aren't using shortest, we are going to use the intervals input option which better not be zero or negative.
            if ((intervals == 0) && (interval != MetricSampleInterval.Shortest))
            {
                throw new ArgumentOutOfRangeException(nameof(intervals), intervals, "The number of intervals can't be zero if the interval isn't set to Shortest.");
            }

            switch (interval)
            {
            case MetricSampleInterval.Default:     //use how the data was recorded
                //default and ours is default - use second.
                returnVal = CalculateOffset(baseline, MetricSampleInterval.Second, intervalCount);
                break;

            case MetricSampleInterval.Shortest:
                //exlicitly use the shortest value available, 16 milliseconds
                returnVal = baseline.AddMilliseconds(16);     //interval is ignored in the case of the "shortest" configuration
                break;

            case MetricSampleInterval.Millisecond:
                returnVal = baseline.AddMilliseconds(intervalCount);
                break;

            case MetricSampleInterval.Second:
                returnVal = baseline.AddSeconds(intervalCount);
                break;

            case MetricSampleInterval.Minute:
                returnVal = baseline.AddMinutes(intervalCount);
                break;

            case MetricSampleInterval.Hour:
                returnVal = baseline.AddHours(intervalCount);
                break;

            case MetricSampleInterval.Day:
                returnVal = baseline.AddDays(intervalCount);
                break;

            case MetricSampleInterval.Week:
                returnVal = baseline.AddDays(intervalCount * 7);
                break;

            case MetricSampleInterval.Month:
                returnVal = baseline.AddMonths(intervalCount);
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(interval));
            }

            return(returnVal);
        }
コード例 #8
0
ファイル: Listener.cs プロジェクト: vcsjones/Loupe.Agent.Core
        /// <summary>
        /// Determines the number of milliseconds in the provided interval for the timer object.
        /// </summary>
        /// <remarks>The values Default and Shortest are automatically treated as Minute by this function, effectively
        /// making once a minute the system default.</remarks>
        /// <param name="referenceInterval">The interval to calculate milliseconds for</param>
        /// <returns>The number of milliseconds between timer polls</returns>
        private static long GetTimerInterval(MetricSampleInterval referenceInterval)
        {
            //we have to convert the reference interval into the correct # of milliseconds
            long milliseconds = -1; //a safe choice because it means the timer will fire exactly once.

            switch (referenceInterval)
            {
            case MetricSampleInterval.Default:
            case MetricSampleInterval.Shortest:
            case MetricSampleInterval.Millisecond:
                //we won't go below once a second
                milliseconds = 1000;
                break;

            case MetricSampleInterval.Minute:
                milliseconds = 60000;       //sorta by definition
                break;

            case MetricSampleInterval.Second:
                milliseconds = 1000;       //sorta by definition
                break;

            case MetricSampleInterval.Hour:
                milliseconds = 3600000;
                break;

            case MetricSampleInterval.Day:
                milliseconds = 86400000;     //get yer own calculator
                break;

            case MetricSampleInterval.Week:
                milliseconds = 604800000;     //I mean who's going to do that, really. BTW:  Just barely a 32 bit number.
                break;

            case MetricSampleInterval.Month:
                milliseconds = DateTime.DaysInMonth(DateTimeOffset.UtcNow.Year, DateTimeOffset.UtcNow.Month) * 86400000;     //now I'm just being a smartass.
                break;

            default:
                break;
            }

            //before we return:  We poll artificially fast for the first few minutes and first hour.
            long secondsPolling = (long)(DateTimeOffset.Now - m_PollingStarted).TotalSeconds;

            if ((milliseconds > 5000) && (secondsPolling < 120))
            {
                milliseconds = 5000;
            }
            else if ((milliseconds > 15000) && (secondsPolling < 3600))
            {
                milliseconds = 15000;
            }

            return(milliseconds);
        }
コード例 #9
0
        /// <summary>Create a new metric value set.</summary>
        /// <param name="caption">The end-user caption for this metric value set.</param>
        /// <param name="description">The end-user description for this metric value set.</param>
        /// <param name="interval">The interval.</param>
        /// <param name="unitCaption">An end-user short display caption for the unit axis.</param>
        public MetricValueCollection(string caption, string description, TimeSpan interval, string unitCaption)
        {
            //copy our metric's caption and description
            m_Caption     = caption;
            m_Description = description;

            // TODO: We should probably store the TimeSpan instead of the MetricSampleInterval
            m_Interval    = MetricSampleInterval.Millisecond;
            m_Intervals   = (int)interval.TotalMilliseconds;
            m_UnitCaption = unitCaption;
        }
コード例 #10
0
ファイル: Metric.cs プロジェクト: vcsjones/Loupe.Agent.Core
        /// <summary>
        /// Calculate displayable values based on the full information captured for this metric with the specified interval
        /// for all dates available
        /// </summary>
        /// <remarks>
        /// The raw values may not be suitable for display depending on the unit the values are captured in, and
        /// depending on how the data was sampled it may not display well because of uneven sampling if processed
        /// directly.
        /// </remarks>
        /// <param name="interval">The requested data sample size</param>
        /// <param name="intervals">The number of intervals to have between each value exactly.</param>
        /// <returns>A metric value set suitable for display</returns>
        public IMetricValueCollection CalculateValues(MetricSampleInterval interval, int intervals)
        {
            //handle the special case where there are no samples so we can't figure out start & end.
            if (m_Samples.Count == 0)
            {
                return(CalculateValues(interval, intervals, null, null));
            }

            //forward to our grander overload
            return(CalculateValues(interval, intervals, this.StartDateTime, this.EndDateTime));
        }
コード例 #11
0
ファイル: Metric.cs プロジェクト: vcsjones/Loupe.Agent.Core
        /// <summary>
        /// Calculates the amount we will "pull forward" a future sample by to fit it to our requested interval.
        /// </summary>
        /// <remarks>Tolerance allows for us to ignore small variations in exact timestamps for the purposes of fitting the best data.</remarks>
        /// <param name="interval"></param>
        /// <returns></returns>
        public static TimeSpan CalculateOffsetTolerance(MetricSampleInterval interval)
        {
            TimeSpan returnVal;

            switch (interval)
            {
            case MetricSampleInterval.Default:
            case MetricSampleInterval.Shortest:
            case MetricSampleInterval.Millisecond:
                //same as millisecond; we will use 1 clock tick
                returnVal = new TimeSpan(1);
                break;

            case MetricSampleInterval.Second:
                //10 milliseconds
                returnVal = new TimeSpan(0, 0, 0, 0, 10);
                break;

            case MetricSampleInterval.Minute:
                //2 seconds
                returnVal = new TimeSpan(0, 0, 0, 2);
                break;

            case MetricSampleInterval.Hour:
                //1 minute
                returnVal = new TimeSpan(0, 1, 0);
                break;

            case MetricSampleInterval.Day:
                //30 minutes
                returnVal = new TimeSpan(0, 30, 0);
                break;

            case MetricSampleInterval.Week:
                //12 hours
                returnVal = new TimeSpan(12, 0, 0);
                break;

            case MetricSampleInterval.Month:
                //two days
                returnVal = new TimeSpan(2, 0, 0, 0);
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(interval));
            }

            return(returnVal);
        }
コード例 #12
0
        /// <summary>
        /// Calculate the number of messages per interval present in the specified time range.
        /// </summary>
        /// <param name="interval">The requested data sample size</param>
        /// <param name="intervals">The number of intervals to have between each value exactly.</param>
        /// <param name="startDateTime">The earliest date to retrieve data for</param>
        /// <param name="endDateTime">The last date to retrieve data for</param>
        /// <returns>A metric value set suitable for display</returns>
        public MetricValueCollection CalculateValues(MetricSampleInterval interval, int intervals, DateTimeOffset?startDateTime, DateTimeOffset?endDateTime)
        {
            DateTimeOffset effectiveStartDateTime = (startDateTime == null ? m_Session.Summary.StartDateTime : (DateTimeOffset)startDateTime);
            DateTimeOffset effectiveEndDateTime   = (endDateTime == null ? m_Session.Summary.EndDateTime : (DateTimeOffset)endDateTime);

            //HOLD UP - enforce our floor for sensible intervals
            if ((intervals < 0) || ((interval != MetricSampleInterval.Shortest) && (intervals == 0)))
            {
                throw new ArgumentOutOfRangeException(nameof(intervals), intervals, "Negative intervals are not supported for calculating values.  Specify an interval count greater than zero, except for the Shortest interval where the interval count is ignored.");
            }

            if ((interval == MetricSampleInterval.Millisecond) && (intervals < 16))
            {
                intervals = 16;
            }

            return(OnCalculateValues(interval, intervals, effectiveStartDateTime, effectiveEndDateTime));
        }
コード例 #13
0
ファイル: Metric.cs プロジェクト: vcsjones/Loupe.Agent.Core
        /// <summary>
        /// Calculate displayable values based on the full information captured for this metric
        /// </summary>
        /// <remarks>
        /// The raw values may not be suitable for display depending on the unit the values are captured in, and
        /// depending on how the data was sampled it may not display well because of uneven sampling if processed
        /// directly.
        /// </remarks>
        /// <param name="interval">The requested data sample size</param>
        /// <param name="intervals">The number of intervals to have between each value exactly.</param>
        /// <param name="startDateTime">The earliest date to retrieve data for</param>
        /// <param name="endDateTime">The last date to retrieve data for</param>
        /// <returns>A metric value set suitable for display</returns>
        public IMetricValueCollection CalculateValues(MetricSampleInterval interval, int intervals, DateTimeOffset?startDateTime, DateTimeOffset?endDateTime)
        {
            //we want to substitute in defaults, but be wary of what happens when we don't have any samples...
            DateTimeOffset effectiveStartDateTime = (startDateTime.HasValue ? (DateTimeOffset)startDateTime
                : (m_Samples.Count > 0) ? StartDateTime : DateTimeOffset.MinValue);
            DateTimeOffset effectiveEndDateTime = (endDateTime.HasValue ? (DateTimeOffset)endDateTime
                : (m_Samples.Count > 0) ? EndDateTime : DateTimeOffset.MinValue);

            //HOLD UP - enforce our floor for sensible intervals
            if ((intervals < 0) || ((interval != MetricSampleInterval.Shortest) && (intervals == 0)))
            {
                throw new ArgumentOutOfRangeException(nameof(intervals), intervals, "Negative intervals are not supported for calculating values.  Specify an interval count greater than zero, except for the Shortest interval where the interval count is ignored.");
            }

            if ((interval == MetricSampleInterval.Millisecond) && (intervals < 16))
            {
                intervals = 16;
            }
            return(OnCalculateValues(interval, intervals, effectiveStartDateTime, effectiveEndDateTime));
        }
コード例 #14
0
        private MetricValueCollection OnCalculateValuesInterval(MetricSampleInterval interval, int intervals, DateTimeOffset startDateTime, DateTimeOffset endDateTime, IEventMetricValueDefinition trendValue)
        {
            //there are two possibilities for unit caption:  Either use the caption from the trend definition or, if that's null, we'll just do Count.
            string unitCaption = null;

            if (trendValue != null)
            {
                unitCaption = trendValue.UnitCaption;
            }

            if (string.IsNullOrEmpty(unitCaption))
            {
                unitCaption = "Events";
            }

            MetricValueCollection newMetricValueCollection;

            if (trendValue == null)
            {
                //initialize with our metric object for default caption/description behavior
                newMetricValueCollection = new MetricValueCollection(this, interval, intervals, unitCaption);
            }
            else
            {
                //initialize with our trend for trend-specific captions and descriptions
                newMetricValueCollection = new MetricValueCollection((EventMetricValueDefinition)trendValue, interval, intervals, unitCaption);
            }

            //And prep for our process loop
            DateTimeOffset windowStartDateTime = startDateTime;
            DateTimeOffset windowEndDateTime   = CalculateOffset(windowStartDateTime, interval, intervals);
            double         lastValue           = 0.0;

            //now loop through all of the intervals in the range to create the sample ranges.
            int lastUsedSampleIndex = 0;

            while (windowStartDateTime < endDateTime)
            {
                //find all of the samples in the current range...
                List <EventMetricSample> samples = new List <EventMetricSample>();
                for (int curSampleIndex = lastUsedSampleIndex; curSampleIndex < Samples.Count; curSampleIndex++)
                {
                    //get the sample on deck
                    EventMetricSample curSample = Samples[curSampleIndex];

                    //if we're outside of the window (before or after) then break out because we've found this whole bucket.
                    if ((curSample.Timestamp < windowStartDateTime) || (curSample.Timestamp > windowEndDateTime))
                    {
                        //we'll need to look at this sample in the next window to see if it fits.
                        lastUsedSampleIndex = curSampleIndex;
                        break;
                    }

                    //this sample is in the bucket
                    samples.Add(curSample);
                }

                //add a metric value for this bucket now that we know everything in it.
                lastValue = CalculateSample(newMetricValueCollection, samples, lastValue, lastUsedSampleIndex, windowEndDateTime, (EventMetricValueDefinition)trendValue);

                //and now we have recorded a metric value for the requested date & time if possible, move that forward.
                windowStartDateTime = windowEndDateTime; //we're moving on to the next window
                windowEndDateTime   = CalculateOffset(windowEndDateTime, interval, intervals);

                //if the target is beyond our end date & time, set to the end date and time so we calculate our last sample
                if (windowEndDateTime > endDateTime)
                {
                    windowEndDateTime = endDateTime;
                }
            }

            return(newMetricValueCollection);
        }
コード例 #15
0
 /// <summary>
 /// Determines what specific samples to use and then calculates the effective values for each sample, returning the results in the provided
 /// new metric value set
 /// </summary>
 /// <remarks>Data covering the provided start and end date will be returned when possible with the goal being that the first metric value returned
 /// will coincide with the start date, and the last sample will be less than or equal to the end date.  Even if there are raw samples available coincident
 /// with the start date it may not be possible to provide a metric value for that date due to the need to have multiple samples to calculate most
 /// metrics.</remarks>
 /// <param name="interval">The interval to bias to.</param>
 /// <param name="intervals">The number of intervals to have between each value exactly.</param>
 /// <param name="startDateTime">The exact date and time desired to start the value set.</param>
 /// <param name="endDateTime">The exact end date and time to not exceed.</param>
 /// <returns>A new metric value set with all calculated values.</returns>
 protected override MetricValueCollection OnCalculateValues(MetricSampleInterval interval, int intervals, DateTimeOffset startDateTime, DateTimeOffset endDateTime)
 {
     //forward the call to our somewhat more elaborate common routine, substituting the default trend.
     return(OnCalculateValues(interval, intervals, startDateTime, endDateTime, Definition.DefaultValue));
 }
コード例 #16
0
 /// <summary>
 /// Calculate the number of messages per interval present in the entire messages collection.
 /// </summary>
 /// <param name="interval">The requested data sample size</param>
 /// <param name="intervals">The number of intervals to have between each value exactly.</param>
 /// <returns>A metric value set suitable for display</returns>
 public MetricValueCollection CalculateValues(MetricSampleInterval interval, int intervals)
 {
     //forward to our grander overload
     return(CalculateValues(interval, intervals, m_Session.Summary.StartDateTime, m_Session.Summary.EndDateTime));
 }
コード例 #17
0
        /// <summary>
        /// Calculate the value set for the provided date range inclusive with samples exactly on the provided interval.
        /// </summary>
        /// <remarks></remarks>
        /// <param name="interval">The interval to bias to.</param>
        /// <param name="intervals">The number of intervals to have between each value exactly.</param>
        /// <param name="startDateTime">The exact date and time desired to start the value set.</param>
        /// <param name="endDateTime">The exact end date and time to not exceed.</param>
        /// <returns>A new metric value set with all calculated values.</returns>
        private MetricValueCollection OnCalculateValuesOnInterval(MetricSampleInterval interval, int intervals, DateTimeOffset startDateTime, DateTimeOffset endDateTime)
        {
            MetricValueCollection newMetricValueCollection = new MetricValueCollection(this, interval, intervals, Definition.UnitCaption);

            //based on the requested interval, calculate the delta between each sample and the tolerance (how close we have to be
            //to the requested time to be pulled forward in time as the best sample)
            TimeSpan sampleTolerance = CalculateOffsetTolerance(interval);

            DateTimeOffset targetDateTime          = startDateTime;
            DateTimeOffset targetToleranceDateTime = targetDateTime + sampleTolerance;

            SampledMetricSample baselineSample = null;
            double previousMetricValue         = 0;
            int    firstSampleIndex            = 0;

            //First, we need to find the value for the start date & time and the sample index into the collection.
            for (int curSampleIndex = 0; curSampleIndex < base.Samples.Count; curSampleIndex++)
            {
                SampledMetricSample curSample = (SampledMetricSample)Samples[curSampleIndex];

                //is this the sample that exactly covers our target date & time?  It is if it's equal to our target, or
                //it is a more exact fit than the next sample.
                if ((curSample.Timestamp == targetDateTime) ||
                    ((curSample.Timestamp < targetToleranceDateTime) && (Samples[curSampleIndex + 1].Timestamp > targetToleranceDateTime)))
                {
                    //yes, this sample is the best fit for our start date & time.  The next one is after our "pull forward" tolerance.
                    //but to get a value, we may have to back up one more interval from this sample to establish its value
                    if (curSample.RequiresMultipleSamples)
                    {
                        //back up as much as we can - as close to one full interval as possible so we get the most accurate initial value sample
                        DateTimeOffset baselineTargetDateTime = CalculateOffset(targetDateTime, interval, -intervals);

                        //start with the first sample before us... if there is one.
                        for (int baselineSampleIndex = curSampleIndex - 1; baselineSampleIndex >= 0; baselineSampleIndex--)
                        {
                            //keep walking back until we are before our target (or run out of choices)
                            baselineSample = (SampledMetricSample)Samples[curSampleIndex];
                            if (baselineSample.Timestamp <= baselineTargetDateTime)
                            {
                                //this is our best fit - it's the first that covers our baseline date time.
                                break;
                            }
                        }
                    }

                    //we either got our baseline or we didn't - if we didn't and we need it we can't calculate value.
                    if ((baselineSample != null) || (curSample.RequiresMultipleSamples == false))
                    {
                        //Calculate the initial metric value sample and add it to the collection.
                        previousMetricValue =
                            CalculateSample(newMetricValueCollection, baselineSample, curSample, startDateTime);
                    }

                    //and this sample becomes our baseline into the next routine
                    baselineSample   = curSample;
                    firstSampleIndex = curSampleIndex;
                    break;  //and we're done - we only wanted to get the start value.
                }
            }

            //Now that we've found our first sample, and the offset into the collection for the first sample, we can go on (provide there are more samples)
            firstSampleIndex++;   //because we used the current sample in the for loop above.
            if (firstSampleIndex < (Samples.Count - 1))
            {
                //we now want to look for the first sample after the start date.  If the user was silly and requested an end date that is less
                //than one interval from the start date, we'll never get into our while loop this way.
                targetDateTime          = CalculateOffset(targetDateTime, interval, intervals);
                targetToleranceDateTime = targetDateTime + sampleTolerance;

                int curSampleIndex            = firstSampleIndex; //we start with the first sample after what was used above.
                SampledMetricSample curSample = null;

                //keep looping until we fill up the timespan or run out of samples.
                while ((targetDateTime <= endDateTime) && (curSampleIndex < (Samples.Count - 1)))
                {
                    //if we have no sample on deck, we must have used it in the last pass of the loop (or this is the first pass)
                    //so get it now.
                    if (curSample == null)
                    {
                        curSample = (SampledMetricSample)Samples[curSampleIndex];
                    }

                    //is this the sample that exactly covers our target date & time?  It is if it's equal to our target, or
                    //it is a more exact fit than the next sample.
                    if ((curSample.Timestamp == targetDateTime) ||
                        ((curSample.Timestamp < targetToleranceDateTime) && (Samples[curSampleIndex + 1].Timestamp > targetToleranceDateTime)))
                    {
                        //yes, this sample is the best fit for our start date & time.  The next one is after our "pull forward" tolerance.
                        if ((baselineSample != null) || (curSample.RequiresMultipleSamples == false))
                        {
                            //Calculate the next metric value sample and add it to the collection.
                            previousMetricValue =
                                CalculateSample(newMetricValueCollection, baselineSample, curSample, targetDateTime);
                        }

                        //and this sample becomes our baseline into the next round
                        baselineSample = curSample;

                        //and we need a new current sample.
                        curSample = null;
                        curSampleIndex++;

                        //and now we have recorded a metric value for the requested date & time if possible, move that forward.
                        targetDateTime          = CalculateOffset(targetDateTime, interval, intervals);
                        targetToleranceDateTime = targetDateTime + sampleTolerance;
                    }
                    else if (curSample.Timestamp < targetToleranceDateTime)
                    {
                        //this sample AND the next sample are both before target tolerance - we're going to skip this guy and record nothing
                        //(because we have more samples than we need for the interval we want)
                        curSample = null;
                        curSampleIndex++;
                    }
                    else
                    {
                        //the sample on deck doesn't apply yet - it's in the future.  We need to "invent" a sample for the current date and time.
                        //we'll just re-record the last metric value
                        new MetricValue(newMetricValueCollection, targetDateTime, previousMetricValue);

                        //and now we have definitely recorded a metric value for the requested date & time, move that forward.
                        targetDateTime          = CalculateOffset(targetDateTime, interval, intervals);
                        targetToleranceDateTime = targetDateTime + sampleTolerance;
                    }
                }
            }

            return(newMetricValueCollection);
        }
コード例 #18
0
ファイル: Metric.cs プロジェクト: vcsjones/Loupe.Agent.Core
 /// <summary>
 /// Determines what specific samples to use and then calculates the effective values for each sample, returning the results in the provided
 /// new metric value set
 /// </summary>
 /// <remarks><para>Data covering the provided start and end date will be returned when possible with the goal being that the first metric value returned
 /// will coincide with the start date, and the last sample will be less than or equal to the end date.  Even if there are raw samples available coincident
 /// with the start date it may not be possible to provide a metric value for that date due to the need to have multiple samples to calculate most
 /// metrics.</para>
 /// <para>When there are no samples available an empty collection should be returned.  In this case the start and end date may be outside the range of the session.</para></remarks>
 /// <param name="interval">The interval to bias to.</param>
 /// <param name="intervals">The number of intervals to have between each value exactly.</param>
 /// <param name="startDateTime">The exact date and time desired to start the value set.</param>
 /// <param name="endDateTime">The exact end date and time to not exceed.</param>
 /// <returns>A new metric value set with all calculated values.</returns>
 protected abstract MetricValueCollection OnCalculateValues(MetricSampleInterval interval, int intervals, DateTimeOffset startDateTime,
                                                            DateTimeOffset endDateTime);