/// <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> /// 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); }