public void ExtractMetrics(ITelemetry fromItem, out bool isItemProcessed) { RequestTelemetry request = fromItem as RequestTelemetry; if (request == null) { isItemProcessed = false; return; } bool isFailed = request.Success.HasValue ? (request.Success.Value == false) : false; MetricV1 metric = isFailed ? this.responseFailureTimeMetric : this.responseSuccessTimeMetric; if (metric != null) { isItemProcessed = true; metric.Track(request.Duration.TotalMilliseconds); } else { isItemProcessed = false; } }
public void InitializeExtractor(MetricManagerV1 metricManager) { this.responseSuccessTimeMetric = metricManager.CreateMetric( MetricTerms.Autocollection.Metric.RequestDuration.Name, new Dictionary <string, string>() { [MetricTerms.Autocollection.Request.PropertyNames.Success] = Boolean.TrueString, [MetricTerms.Autocollection.MetricId.Moniker.Key] = MetricTerms.Autocollection.Metric.RequestDuration.Id, }); this.responseFailureTimeMetric = metricManager.CreateMetric( MetricTerms.Autocollection.Metric.RequestDuration.Name, new Dictionary <string, string>() { [MetricTerms.Autocollection.Request.PropertyNames.Success] = Boolean.FalseString, [MetricTerms.Autocollection.MetricId.Moniker.Key] = MetricTerms.Autocollection.Metric.RequestDuration.Id, }); }
public SucceessAndFailureMetrics(MetricV1 successMetric, MetricV1 failureMetric) { this.Success = successMetric; this.Failure = failureMetric; }
/// <summary> /// Extracts appropriate data points for auto-collected, pre-aggregated metrics from a single <c>DependencyTelemetry</c> item. /// </summary> /// <param name="fromItem">The telemetry item from which to extract the metric data points.</param> /// <param name="isItemProcessed">Whether of not the specified item was processed (aka not ignored) by this extractor.</param> public void ExtractMetrics(ITelemetry fromItem, out bool isItemProcessed) { //// If this item is not a DependencyTelemetry, we will not process it: DependencyTelemetry dependencyCall = fromItem as DependencyTelemetry; if (dependencyCall == null) { isItemProcessed = false; return; } MetricManagerV1 thisMetricManager = this.metricManager; MetricsCache thisMetrics = this.metrics; //// If there is no MetricManager, then this extractor has not been properly initialized yet: if (thisMetricManager == null) { //// This will be caught and properly logged by the base class: throw new InvalidOperationException("Cannot execute ExtractMetrics because this metrics extractor has not been initialized (no metrics manager)."); } //// Get dependency call success status: bool dependencyFailed = (dependencyCall.Success != null) && (dependencyCall.Success == false); //// Now we need to determine which data series to use: MetricV1 metricToTrack = null; if (thisMetrics.MaxDependencyTypesToDiscover == 0) { //// If auto-discovering dependency types is disabled, just pick series based on success status: metricToTrack = dependencyFailed ? thisMetrics.Default.Failure : thisMetrics.Default.Success; } else { //// Pick series based on dependency type (and success status): string dependencyType = dependencyCall.Type; if (dependencyType == null || dependencyType.Equals(string.Empty, StringComparison.OrdinalIgnoreCase)) { //// If dependency type is not set, we use "Unknown": metricToTrack = dependencyFailed ? thisMetrics.Unknown.Failure : thisMetrics.Unknown.Success; } else { //// See if we have already discovered the current dependency type: bool previouslyDiscovered = thisMetrics.ByType.TryGetValue(dependencyType, out SucceessAndFailureMetrics typeMetrics); if (previouslyDiscovered) { metricToTrack = dependencyFailed ? typeMetrics.Failure : typeMetrics.Success; } else { //// We have not seen the current dependency type yet: if (thisMetrics.ByType.Count >= thisMetrics.MaxDependencyTypesToDiscover) { //// If the limit of types to discover is already reached, just use "Other": metricToTrack = dependencyFailed ? thisMetrics.Default.Failure : thisMetrics.Default.Success; } else { //// So we have not yet reached the limit. //// We will need to take a lock to make sure that the number of discovered types is used correctly as a limit. //// Note: this is a very rare case. It is expected to occur only MaxDependencyTypesToDiscover times. //// In case of very high contention, this may happen a little more often, //// but will no longer happen once the MaxDependencyTypesToDiscover limit is reached. const string TypeDiscoveryLimitReachedMessage = "Cannot discover more dependency types because the MaxDependencyTypesToDiscover limit" + " is reached. This is a control-flow exception that should not propagate outside " + "the metric extraction logic."; try { typeMetrics = thisMetrics.ByType.GetOrAdd( dependencyType, (depType) => { lock (thisMetrics.TypeDiscoveryLock) { if (thisMetrics.DependencyTypesDiscoveredCount >= thisMetrics.MaxDependencyTypesToDiscover) { throw new InvalidOperationException(TypeDiscoveryLimitReachedMessage); } thisMetrics.DependencyTypesDiscoveredCount++; return(new SucceessAndFailureMetrics( thisMetricManager.CreateMetric( MetricTerms.Autocollection.Metric.DependencyCallDuration.Name, new Dictionary <string, string>() { [MetricTerms.Autocollection.DependencyCall.PropertyNames.Success] = Boolean.TrueString, // SUCCESS metric [MetricTerms.Autocollection.MetricId.Moniker.Key] = MetricTerms.Autocollection.Metric.DependencyCallDuration.Id, [MetricTerms.Autocollection.DependencyCall.PropertyNames.TypeName] = depType, }), thisMetricManager.CreateMetric( MetricTerms.Autocollection.Metric.DependencyCallDuration.Name, new Dictionary <string, string>() { [MetricTerms.Autocollection.DependencyCall.PropertyNames.Success] = Boolean.FalseString, // FAILURE metric [MetricTerms.Autocollection.MetricId.Moniker.Key] = MetricTerms.Autocollection.Metric.DependencyCallDuration.Id, [MetricTerms.Autocollection.DependencyCall.PropertyNames.TypeName] = depType, }))); } }); } catch (InvalidOperationException ex) { if (!ex.Message.Equals(TypeDiscoveryLimitReachedMessage, StringComparison.Ordinal)) { ExceptionDispatchInfo.Capture(ex).Throw(); } //// Limit was reached concurrently. We will use "Other" after all: metricToTrack = dependencyFailed ? thisMetrics.Default.Failure : thisMetrics.Default.Success; } //// Use the newly created metric for this newly discovered dependency type: metricToTrack = dependencyFailed ? typeMetrics.Failure : typeMetrics.Success; } } } } //// Now that we selected the right metric, track the value: isItemProcessed = true; metricToTrack.Track(dependencyCall.Duration.TotalMilliseconds); }