/// <summary>
        /// Records a value to the values array of this sample given the zero-based index of the value definition to be used.
        /// </summary>
        /// <remarks>The value must be defined as part of the event metric definition associated with this sample
        /// or an exception will be thrown.  The data type must also be compatible with the data type configured
        /// on the event metric definition or no data will be recorded.
        /// If called more than once for the same value, the prior value will be replaced.</remarks>
        /// <param name="valueIndex">The zero-based index within the value definition of the value to be recorded.</param>
        /// <param name="value">The value to be recorded.</param>
        public void SetValue(int valueIndex, object value)
        {
            IEventMetricValueDefinitionCollection valueDefinitions = Metric.Definition.Values;

            //we don't have to check that the value index isn't null, but it does have to be in range
            if ((valueIndex < 0) || (valueIndex > (valueDefinitions.Count - 1)))
            {
#if DEBUG
                //if we're compiled in debug mode, tell the user they blew it.
                throw new ArgumentOutOfRangeException(nameof(valueIndex), valueIndex.ToString(CultureInfo.CurrentCulture));
#else
                //log and return, nothing we can do.
                if (!Log.SilentMode)
                {
                    Log.Write(LogMessageSeverity.Warning, LogCategory, "Unable to add metric value to the current sample due to missing value definition",
                              "There is no value definition at index {1} for metric definition {0}",
                              Metric.Definition.Name, valueIndex);
                }
                return;
#endif
            }

            //look up the value in the definition so we can process it
            IEventMetricValueDefinition curValueDefinition = valueDefinitions[valueIndex];

            //and now we can use our one true method to add the value
            SetValue((EventMetricValueDefinition)curValueDefinition, value);
        }
        /// <summary>
        /// Add an existing value definition item to this collection
        /// </summary>
        /// <param name="item">An existing value definition item associated with our metric definition</param>
        public void Add(IEventMetricValueDefinition item)
        {
            //we can't do the read-only check here because we use this method to add existing objects during rehydration

            //make sure the input isn't null
            if (item == null)
            {
                throw new ArgumentNullException(nameof(item));
            }

            //make sure it's associated with our definition
            if ((EventMetricDefinition)item.Definition != m_Definition)
            {
                throw new ArgumentException("The provided value definition item is not associated with our metric definition", nameof(item));
            }

            lock (m_Definition.Lock)
            {
                //and make sure it isn't a duplicate key
                if (m_Dictionary.ContainsKey(item.Name))
                {
                    throw new ArgumentException(
                              string.Format(CultureInfo.CurrentCulture, "There is already a value definition item with the name {0}", item.Name), nameof(item));
                }

                //and finally what the hell, go ahead and add it.
                m_List.Add(item);
                m_Dictionary.Add(item.Name, item);
            }

            //and fire our event, outside the lock
            OnCollectionChanged(new CollectionChangedEventArgs <IEventMetricValueDefinitionCollection, IEventMetricValueDefinition>(this, item, CollectionAction.Added));
        }
        // Note: Apparently this documentation is out of date?  Remove apparently *is* supported unless IsReadOnly.
        /// <summary>
        /// Removing objects is not supported.
        /// </summary>
        /// <remarks>This method is implemented only for ICollection interface support and will throw an exception if called.</remarks>
        /// <param name="item">The EventMetricValueDefinition item to remove.</param>
        public bool Remove(IEventMetricValueDefinition item)
        {
            bool itemRemoved = false;

            lock (m_Definition.Lock)
            {
                if (IsReadOnly)
                {
                    throw new NotSupportedException("The collection is read-only");
                }

                //do a safe remove of the victim in the dictionary and list, if they are still present
                //if they aren't, we have a problem
                if (m_Dictionary.ContainsKey(item.Name))
                {
                    m_Dictionary.Remove(item.Name);
                    itemRemoved = true;
                }

                if (m_List.Contains(item))
                {
                    m_List.Remove(item);
                    itemRemoved = true;
                }
            }

            //and fire our event if there was really something to remove
            if (itemRemoved)
            {
                OnCollectionChanged(new CollectionChangedEventArgs <IEventMetricValueDefinitionCollection, IEventMetricValueDefinition>(this, item, CollectionAction.Removed));
            }

            return(itemRemoved);
        }
        /// <summary>
        /// Indicates whether the collection already contains the specified definition object
        /// </summary>
        /// <remarks>Even if the object doesn't exist in the collection, if another object with the same key exists then
        /// an exception will be thrown if the supplied object is added to the collection.  See Add for more information.</remarks>
        /// <param name="item">The event metric value definition object to look for</param>
        /// <returns>True if the object already exists in the collection, false otherwise</returns>
        public bool Contains(IEventMetricValueDefinition item)
        {
            //here we are relying on the fact that the comment object implements IComparable sufficiently to guarantee uniqueness
            if (IsReadOnly) // Don't need the lock once we're read-only.
            {
                return(m_List.Contains(item));
            }

            lock (m_Definition.Lock) // But we do need the lock when it may still be changing.
            {
                return(m_List.Contains(item));
            }
        }
        /// <summary>
        /// Retrieve an item from the collection by its key if present.  If not present, the default value of the object is returned.
        /// </summary>
        /// <param name="name">The key of the value to get.</param>
        /// <param name="value">When this method returns, contains the value associated with the specified key, if the key is found; otherwise, the default value for the type of the value parameter. This parameter is passed uninitialized.</param>
        /// <returns>true if the collection contains an element with the specified key; otherwise false.</returns>
        public bool TryGetValue(string name, out IEventMetricValueDefinition value)
        {
            if (IsReadOnly) // Don't need the lock once we're read-only.
            {
                //gateway to our inner dictionary try get value
                return(m_Dictionary.TryGetValue(name, out value));
            }

            lock (m_Definition.Lock) // But we do need the lock when it may still be changing.
            {
                //gateway to our inner dictionary try get value
                return(m_Dictionary.TryGetValue(name, out value));
            }
        }
Пример #6
0
        /// <summary>
        /// Determines if the provided object is identical to this object.
        /// </summary>
        /// <param name="other">The object to compare this object to</param>
        /// <returns>True if the objects represent the same data.</returns>
        public bool Equals(IEventMetricValueDefinition other)
        {
            //Careful - can be null
            if (other == null)
            {
                return(false); // since we're a live object we can't be equal.
            }

            if (ReferenceEquals(this, other) || ReferenceEquals(m_Packet, ((EventMetricValueDefinition)other).Packet))
            {
                return(true); // If the objects or the underlying packet are the same object, they're the same.
            }
            //We're really just a type cast, refer to our base object
            return(m_Packet.Name.Equals(other.Name));
        }
        /// <summary>
        /// Compute the resultant value for this sample compared with the provided baseline sample.
        /// </summary>
        /// <remarks>
        /// <para>The baseline sample must be for a date and time prior to this sample for correct results.</para>
        /// <para>If the supplied trendValue isn't trendable, the number of samples with a non-null value will be counted.</para>
        /// <para>If the supplied trendValue is trendable, the Default Trend (average or sum) will be calculated for all
        /// samples between the supplied baseline sample and this sample, inclusive.</para>
        /// </remarks>
        /// <param name="baselineSample">The previous baseline sample to calculate a difference for</param>
        /// <param name="trendValue">The definition of the value from this event metric to trend.</param>
        /// <returns>The calculated counter value</returns>
        public double ComputeValue(IEventMetricSample baselineSample, IEventMetricValueDefinition trendValue)
        {
            //we have to figure out all of the samples to include between these points.
            List <EventMetricSample> valueSamples = new List <EventMetricSample>();

            EventMetricSampleCollection samples = Metric.Samples;
            int startIndex = (baselineSample == null) ? 0 : samples.IndexOf(baselineSample);
            int ourIndex   = samples.IndexOf(this);

            for (int sampleIndex = startIndex; sampleIndex <= ourIndex; sampleIndex++)
            {
                valueSamples.Add(samples[sampleIndex]);
            }

            return(Metric.CalculateSample(null, valueSamples, 0, 0, Timestamp, (EventMetricValueDefinition)trendValue));
        }
        internal EventMetricValueDefinition Externalize(IEventMetricValueDefinition valueDefinition)
        {
            if (valueDefinition == null)
            {
                return(null);
            }

            lock (m_Definition.Lock)
            {
                EventMetricValueDefinition externalDefinition;
                if (m_Externalized.TryGetValue(valueDefinition, out externalDefinition) == false)
                {
                    externalDefinition = new EventMetricValueDefinition(m_Definition, (Monitor.EventMetricValueDefinition)valueDefinition);
                    m_Externalized[valueDefinition] = externalDefinition;
                }

                return(externalDefinition);
            }
        }
        /// <summary>
        /// Searches for the specified object and returns the zero-based index of it within the dictionary if it is found.
        /// </summary>
        /// <param name="item">The object to search for</param>
        /// <returns>The zero based index of the object within the dictionary or -1 if not found.</returns>
        public int IndexOf(IEventMetricValueDefinition item)
        {
            if (m_Definition.IsReadOnly) // && ReferenceEquals(item.Definition, Definition))
            {
                int index = ((EventMetricValueDefinition)item).MyIndex;
                if (index < 0)
                {
                    // Wasn't found, do a scan the hard way.
                    index = m_List.IndexOf(item);
                    if (index >= 0)
                    {
                        ((EventMetricValueDefinition)item).MyIndex = index; // And if we found it, remember for next time.
                    }
                }
                return(index);
            }

            // Otherwise, we aren't necessarily final (could be removes?), so punt it the hard way.  We need the lock.
            lock (m_Definition.Lock)
            {
                return(m_List.IndexOf(item));
            }
        }
Пример #10
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);
        }
Пример #11
0
        private MetricValueCollection OnCalculateValuesShortest(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, MetricSampleInterval.Shortest, 0, unitCaption);
            }
            else
            {
                //initialize with our trend for trend-specific captions and descriptions
                newMetricValueCollection = new MetricValueCollection((EventMetricValueDefinition)trendValue, MetricSampleInterval.Shortest, 0, unitCaption);
            }

            double lastValue = 0.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 < Samples.Count; curSampleIndex++)
            {
                //get the sample on deck
                EventMetricSample curSample = Samples[curSampleIndex];

                //Is this sample in our range?
                if (curSample.Timestamp >= startDateTime)
                {
                    //Go ahead and calculate the value, adding it to our set.  We don't use a baseline because we're looking at each individual value.
                    CalculateSample(newMetricValueCollection, new List <EventMetricSample>(new[] { curSample }), lastValue, curSampleIndex, curSample.Timestamp, (EventMetricValueDefinition)trendValue);
                }
                else if (curSample.Timestamp > endDateTime)
                {
                    //we're done - there are no more samples to consider, break out of the for loop
                    break;
                }
            }

            return(newMetricValueCollection);
        }
Пример #12
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);
        }
Пример #13
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));
        }
 ///<summary>Inserting objects by index is not supported because the collection is sorted.</summary>
 ///<remarks>This method is implemented only for IList interface support and will throw an exception if called.</remarks>
 public void Insert(int index, IEventMetricValueDefinition item)
 {
     //we don't support setting an object by index; we are sorted.
     throw new NotSupportedException();
 }
        /// <summary>
        /// Retrieve the index of a metric value definition by its name
        /// </summary>
        /// <param name="name">The value name to locate in the collection</param>
        /// <remarks>Items are identified using ordinal, case insensitive string comparisons.  If no value exists with the provided name an exception will be thrown.</remarks>
        /// <exception cref="System.ArgumentNullException">Thrown if no value exists with the provided name.</exception>
        public int IndexOf(string name)
        {
            IEventMetricValueDefinition value = this[name];

            return(IndexOf(value));
        }