コード例 #1
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;
 }
        /// <summary>
        /// Create a new value definition with the supplied name and type.  The name must be unique in this collection
        /// </summary>
        /// <remarks>Internally, only simple type are supported.  Any non-numeric, non-DateTimeOffset type will be converted to a string
        /// using the default ToString capability when it is recorded.</remarks>
        /// <param name="name">The unique name for this value definition</param>
        /// <param name="type">The simple type of this value</param>
        /// <param name="caption">The end-user display caption for this value</param>
        /// <param name="description">The end-user description for this value.</param>
        /// <returns>The newly created value definition</returns>
        public EventMetricValueDefinition Add(string name, Type type, string caption, string description)
        {
            lock (m_Definition.Lock) // Is this really needed?  Can't hurt....
            {
                //if we are read-only, you can't add a new value
                if (IsReadOnly)
                {
                    throw new NotSupportedException("The collection is read-only");
                }

                //make sure we got everything we require
                if (string.IsNullOrEmpty(name))
                {
                    throw new ArgumentNullException(nameof(name));
                }

                if (type == null)
                {
                    throw new ArgumentNullException(nameof(type));
                }

                //make sure the name is unique
                if (m_Dictionary.ContainsKey(name))
                {
                    throw new ArgumentException("There is already a value definition with the provided name.", nameof(name));
                }

                //create a new value definition
                EventMetricValueDefinitionPacket newPacket =
                    new EventMetricValueDefinitionPacket(m_Definition.Packet, name, type, caption, description);
                EventMetricValueDefinition newDefinition = new EventMetricValueDefinition(m_Definition, newPacket);

                //forward the call to our one true add method
                Add(newDefinition);

                //and return the new object to our caller so the have the object we created from their input.
                return(newDefinition);
            }
        }
        internal EventMetricValueDefinition Add(EventMetricValueDefinitionPacket packet)
        {
            //Even though this is an internal method used just during rehydration of data, we are going to
            //enforce all of the integrity checks to be sure we have good data

            //The one thing we CAN'T check is read only, because we're used when the collection IS read only.

            //make sure we got everything we require
            if (string.IsNullOrEmpty(packet.Name))
            {
                throw new ArgumentNullException(nameof(packet));
            }

            if (packet.Type == null)
            {
                throw new ArgumentNullException(nameof(packet));
            }

            lock (m_Definition.Lock)
            {
                //make sure the name is unique
                if (m_Dictionary.ContainsKey(packet.Name))
                {
                    throw new ArgumentException("There is already a value definition with the provided name.", nameof(packet));
                }

                //create a new value definition
                EventMetricValueDefinition newDefinition = new EventMetricValueDefinition(m_Definition, packet);

                //forward the call to our one true add method
                Add(newDefinition);

                //and return the new object to our caller so they have the object we created from their input.
                return(newDefinition);
            }
        }
コード例 #4
0
        /// <summary>
        /// Records a value to the values array of this sample given its value definition.
        /// </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="valueDefinition">The metric value definition object of the value to be recorded.</param>
        /// <param name="value">The value to be recorded.</param>
        public void SetValue(EventMetricValueDefinition valueDefinition, object value)
        {
            //make sure we got a value definition
            if (valueDefinition == null)
            {
                throw new ArgumentNullException(nameof(valueDefinition));
            }

            //look up the numerical index in the collection so we know what offset to put it in the array at
            int valueIndex = Metric.Definition.Values.IndexOf(valueDefinition);

            //if we didn't find it, we're hosed
            if (valueIndex < 0)
            {
#if DEBUG
                //if we're compiled in debug mode, tell the user they blew it.
                throw new ArgumentOutOfRangeException(nameof(valueDefinition), valueDefinition.Name);
#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 named {1} for metric definition {0}",
                              Metric.Definition.Name, valueDefinition.Name);
                }
                return;
#endif
            }

            //coerce it into the right type
            object storedValue;
            if (value == null)
            {
                //you can always store a null.  And we can't really check it more, so there.
                storedValue = null;
            }
            else
            {
                //get the type so we can verify it
                Type valueType = value.GetType();

                //is it close enough to what we're expecting?
                if (valueDefinition.IsTrendable)
                {
                    if (EventMetricDefinition.IsTrendableValueType(valueType))
                    {
                        storedValue = value;
                    }
                    else
                    {
                        //no, it should be trendable and it isn't.  store null.
                        storedValue = null;
                    }
                }
                else
                {
                    //we don't care what it is because we're going to coerce it to a string.
                    storedValue = value.ToString();
                }
            }

            //now write out the value to the correct spot in the array
            Packet.Values[valueIndex] = storedValue;
        }
コード例 #5
0
        /// <summary>
        /// Calculate one effective value from the provided objects
        /// </summary>
        /// <param name="metricValueCollection">Optional.  The value set to add the new value to</param>
        /// <param name="samples">The set of samples to put in this value</param>
        /// <param name="previousValue">The value of the prior sample in time.</param>
        /// <param name="previousCount">The number of event metric samples previously used (for running average)</param>
        /// <param name="timeStamp">The timestamp to use for the sample</param>
        /// <param name="trendValue">The specific event metric value to trend</param>
        internal double CalculateSample(MetricValueCollection metricValueCollection, IList <EventMetricSample> samples, double previousValue, int previousCount, DateTimeOffset timeStamp, EventMetricValueDefinition trendValue)
        {
            double calculatedValue;

            //There are three totally different routes we go:  Either we are calculating an explicit trend value,
            //or we are just going to count the # of events.  This varies depending on whether the caller specified
            //a trend value
            if (trendValue == null)
            {
                //just count them
                calculatedValue = samples.Count;
            }
            //There are two overall ways we trend things:  Either we count the # of non-null values for non-trendables, or
            //we actually make a numeric trend
            else if ((trendValue.IsTrendable == false) || (trendValue.DefaultTrend == EventMetricValueTrend.Count))
            {
                //count the number of things.
                int itemCount = 0;

                if (samples.Count > 0)
                {
                    int valueIndex = Definition.Values.IndexOf(trendValue); //the zero-based index in the value collection of the value we want

                    //Now count all of the samples with a non-null value, including us (inclusive)
                    foreach (EventMetricSample sample in samples)
                    {
                        if (sample.Values[valueIndex] != null)
                        {
                            itemCount++;
                        }
                    }
                }

                calculatedValue = itemCount;
            }
            else
            {
                //ohh kay, now we either sum or average.
                double sumValue   = 0;                                     //sum or average, we need the sum.
                int    items      = samples.Count;                         //for an average we will need the item count.
                int    valueIndex = Definition.Values.IndexOf(trendValue); //the zero-based index in the value collection of the value we want

                //if it's a running value we need to start with the previous sample's state
                if ((trendValue.DefaultTrend == EventMetricValueTrend.RunningAverage) ||
                    (trendValue.DefaultTrend == EventMetricValueTrend.RunningSum))
                {
                    //we need the previous running data.
                    sumValue = previousValue;
                    items   += previousCount;
                }

                //Now add up the effective value of the requested trend line for every sample in the range, inclusive
                foreach (EventMetricSample currentSample in samples)
                {
                    sumValue += currentSample.GetEffectiveValue(valueIndex);
                }

                //figure out the calculated value.  For performance and safety, don't do a divide we don't have to
                if ((items > 1) &&
                    ((trendValue.DefaultTrend == EventMetricValueTrend.Average) ||
                     (trendValue.DefaultTrend == EventMetricValueTrend.RunningAverage)))
                {
                    calculatedValue = sumValue / items;
                }
                else
                {
                    calculatedValue = sumValue;
                }
            }

            //now create & add the value to our values collection.
            if (metricValueCollection != null)
            {
                new MetricValue(metricValueCollection, timeStamp, calculatedValue);
            }

            return(calculatedValue);
        }