/// <summary>Creates a new metric definition from the provided information, or returns an existing matching definition if found.</summary>
        /// <remarks>If the metric definition doesn't exist, it will be created.
        /// If the metric definition does exist, but is not a Custom Sampled Metric (or a derived class) an exception will be thrown.
        /// Definitions are looked up and added to the provided definitions dictionary.</remarks>
        /// <param name="definitions">The definitions dictionary this definition is a part of</param>
        /// <param name="metricTypeName">The unique metric type</param>
        /// <param name="categoryName">The name of the category with which this definition is associated.</param>
        /// <param name="counterName">The name of the definition within the category.</param>
        public static EventMetricDefinition AddOrGet(MetricDefinitionCollection definitions, string metricTypeName, string categoryName, string counterName)
        {
            //we must have a definitions collection, or we have a problem
            if (definitions == null)
            {
                throw new ArgumentNullException(nameof(definitions));
            }

            //we need to find the definition, adding it if necessary
            string            definitionKey = GetKey(metricTypeName, categoryName, counterName);
            IMetricDefinition definition;

            //We need to grab a lock so our try get & the create are done as one lock.
            lock (definitions.Lock)
            {
                if (definitions.TryGetValue(definitionKey, out definition))
                {
                    //if the metric definition exists, but is of the wrong type we have a problem.
                    if ((definition is CustomSampledMetricDefinition) == false)
                    {
                        throw new ArgumentException("A metric already exists with the provided type, category, and counter name but it is not compatible with being an event metric.  Please use a different counter name.", nameof(counterName));
                    }
                }
                else
                {
                    //we didn't find one, make a new one
                    definition = new EventMetricDefinition(definitions, metricTypeName, categoryName, counterName);
                    definitions.Add(definition); // Add it to the collection, no longer done in the constructor.
                    // ToDo: Reconsider this implementation; putting incomplete event metric definitions in the collection is not ideal.
                }
            }
            return((EventMetricDefinition)definition);
        }
Exemplo n.º 2
0
 /// <summary>
 /// Create a new sampled metric object from the provided raw data packet.
 /// </summary>
 /// <remarks>The metric definition <b>will</b> be automatically added to the provided collection.</remarks>
 /// <param name="definitions">The definitions dictionary this definition is a part of.</param>
 /// <param name="packet">The packet to create a definition from.</param>
 internal SampledMetricDefinition(MetricDefinitionCollection definitions, SampledMetricDefinitionPacket packet)
     : base(definitions, packet)
 {
     // After the base constructor, auto-add ourself to the definition collection
     SetReadOnly();         // Make sure we're read-only before we're added to the collection.
     definitions.Add(this); // ToDo: Determine whether to keep or discard this behavior for sampled metrics.
 }
Exemplo n.º 3
0
        /// <summary>Creates a new metric instance or returns an existing one from the provided definition information, or returns any existing instance if found.</summary>
        /// <remarks>If the metric definition doesn't exist, it will be created.  If the metric doesn't exist, it will be created.
        /// If the metric definition does exist, but is not an Event Metric (or a derived class) an exception will be thrown.</remarks>
        /// <param name="definitions">The definitions dictionary this definition is a part of</param>
        /// <param name="metricTypeName">The unique metric type</param>
        /// <param name="categoryName">The name of the category with which this definition is associated.</param>
        /// <param name="counterName">The name of the definition within the category.</param>
        /// <param name="instanceName">The unique name of this instance within the metric's collection.</param>
        /// <returns>The event metric object for the specified event metric instance.</returns>
        public static EventMetric AddOrGet(MetricDefinitionCollection definitions, string metricTypeName, string categoryName, string counterName, string instanceName)
        {
            //we must have a definitions collection, or we have a problem
            if (definitions == null)
            {
                throw new ArgumentNullException(nameof(definitions));
            }

            //we need to find the definition, adding it if necessary
            string            definitionKey = MetricDefinition.GetKey(metricTypeName, categoryName, counterName);
            IMetricDefinition definition;

            if (definitions.TryGetValue(definitionKey, out definition))
            {
                //if the metric definition exists, but is of the wrong type we have a problem.
                if ((definition is EventMetricDefinition) == false)
                {
                    throw new ArgumentException("A metric already exists with the provided type, category, and counter name but it is not compatible with being an event metric.  Please use a different counter name.", nameof(counterName));
                }
            }
            else
            {
                //we didn't find one, make a new one
                definition = new EventMetricDefinition(definitions, metricTypeName, categoryName, counterName);
                definitions.Add(definition); // Add it to the collection, no longer done in the constructor.
                // ToDo: Reconsider this implementation; putting incomplete event metric definitions in the collection is not ideal,
                // and creating a metric from an empty event metric definition is fairly pointless.
            }

            //now we have our definition, proceed to create a new metric if it doesn't exist
            string  metricKey = MetricDefinition.GetKey(metricTypeName, categoryName, counterName, instanceName);
            IMetric metric;

            //see if we can get the metric already.  If not, we'll create it
            lock (((MetricCollection)definition.Metrics).Lock) //make sure the get & add are atomic
            {
                if (definition.Metrics.TryGetValue(metricKey, out metric) == false)
                {
                    metric = new EventMetric((EventMetricDefinition)definition, instanceName);
                }
            }

            return((EventMetric)metric);
        }
        /// <summary>
        /// Register this instance as a completed definition and return the valid usable definition for this event metric.
        /// </summary>
        /// <remarks>This call is necessary to complete a new event metric definition (created by calls to AddValue) before
        /// it can be used, and it signifies that all desired value columns have been added to the definition.  Only the
        /// first registration of a metric definition with a given Key (metrics system, category name, and counter name)
        /// will be effective and return the same definition object; subsequent calls (perhaps by another thread) will
        /// instead return the existing definition already registered.  If a definition already registered with that Key
        /// can not be an event metric (e.g. a sampled metric is defined with that Key) or if this instance defined value
        /// columns not present as compatible value columns in the existing registered definition with that Key, then an
        /// ArgumentException will be thrown to signal your programming mistake.</remarks>
        /// <returns>The actual usable definition with the same metrics system, category name, and counter name as this instance.</returns>
        public EventMetricDefinition Register()
        {
            EventMetricDefinition      officialDefinition;
            MetricDefinitionCollection definitionCollection = (MetricDefinitionCollection)Definitions;

            // We need to lock the collection while we check for an existing definition and maybe add this one to it.
            lock (definitionCollection.Lock)
            {
                IMetricDefinition rawDefinition;
                if (definitionCollection.TryGetValue(MetricTypeName, CategoryName, CounterName, out rawDefinition) == false)
                {
                    // There isn't already one by that Key.  Great!  Register ourselves.
                    SetReadOnly(); // Mark this definition as completed.
                    officialDefinition = this;
                    definitionCollection.Add(this);
                }
                else
                {
                    // Oooh, we found one already registered.  We'll want to do some checking on this, but outside the lock.
                    officialDefinition = rawDefinition as EventMetricDefinition;
                }
            } // End of collection lock

            if (officialDefinition == null)
            {
                throw new ArgumentException(
                          string.Format(
                              "There is already a metric definition for the same metrics system ({0}), category name ({1}), and counter name ({2}), but it is not an event metric.",
                              MetricTypeName, CategoryName, CounterName));
            }
            else if (this != officialDefinition)
            {
                // There was one other than us, make sure it's compatible with us.
                IEventMetricValueDefinitionCollection officialValues = officialDefinition.Values;
                foreach (EventMetricValueDefinition ourValue in Values)
                {
                    IEventMetricValueDefinition officialValue;
                    if (officialValues.TryGetValue(ourValue.Name, out officialValue) == false)
                    {
                        // It doesn't have one of our value columns!
                        throw new ArgumentException(
                                  string.Format(
                                      "There is already an event metric definition for the same metrics system ({0}), category name ({1}), and counter name ({2}), but it is not compatible; it does not define value column \"{3}\".",
                                      MetricTypeName, CategoryName, CounterName, ourValue.Name));
                    }
                    else if (ourValue.SerializedType != ((EventMetricValueDefinition)officialValue).SerializedType)
                    {
                        throw new ArgumentException(
                                  string.Format(
                                      "There is already an event metric definition for the same metrics system ({0}), category name ({1}), and counter name ({2}), but it is not compatible; " +
                                      "it defines value column \"{3}\" with type {4} rather than type {5}.",
                                      MetricTypeName, CategoryName, CounterName, ourValue.Name, officialValue.Type.Name, ourValue.Type.Name));
                    }
                }

                // We got through all the values defined in this instance?  Then we're okay to return the official one.
            }
            // Otherwise, it's just us, so we're all good.

            return(officialDefinition);
        }