public async Task <MetricListResponse> GetMetricsAsync(string resourceId, string filterString, IEnumerable <MetricDefinition> definitions, string invocationId) { MetricFilter filter = MetricFilterExpressionParser.Parse(filterString); // Grab all metric definitiions that contain the specific timegrain from the filter. // See the extension class for implementation var timegraindefinitions = from d in definitions where d.MetricAvailabilities.Count > 0 && d.MetricAvailabilities.Contains(filter) select d; // Group definitions by location so we can make one request to each location Dictionary <MetricAvailability, MetricFilter> groups = timegraindefinitions.GroupBy(d => d.MetricAvailabilities.FirstOrDefault()).ToDictionary(g => g.Key, g => new MetricFilter() { TimeGrain = filter.TimeGrain, StartTime = filter.StartTime, EndTime = filter.EndTime, DimensionFilters = g.Select(d => filter.DimensionFilters.FirstOrDefault(df => string.Equals(df.Name, d.Name.Value, StringComparison.OrdinalIgnoreCase)) ?? new MetricDimension() { Name = d.Name.Value }) }, new AvailabilityComparer()); // Verify all groups represent shoebox metrics if (groups.Any(g => g.Key.Location == null)) { throw new ArgumentException("All definitions provided to ShoeboxMetricRetriever must include location information.", "definitions"); } // Get Metrics from each location (group) IEnumerable <Task <MetricListResponse> > locationTasks = groups.Select(g => this.GetMetricsInternalAsync(g.Value, g.Key.Location, invocationId)); // Aggregate metrics from all groups MetricListResponse[] results = (await Task.Factory.ContinueWhenAll(locationTasks.ToArray(), tasks => tasks.Select(t => t.Result))).ToArray(); IEnumerable <Metric> metrics = results.Aggregate <MetricListResponse, IEnumerable <Metric> >( new List <Metric>(), (list, response) => list.Union(response.MetricCollection.Value)); // Return aggregated results (the MetricOperations class will fill in additional info from the MetricDefinitions) return(new MetricListResponse() { RequestId = invocationId, StatusCode = HttpStatusCode.OK, MetricCollection = new MetricCollection() { Value = metrics.ToList() } }); }
public async Task <MetricListResponse> GetMetricsAsync(string resourceUri, string filterString, CancellationToken cancellationToken) { if (resourceUri == null) { throw new System.ArgumentNullException("resourceUri"); } // Generate filter strings MetricFilter filter = MetricFilterExpressionParser.Parse(filterString); string filterStringNamesOnly = filter.DimensionFilters == null ? null : ShoeboxHelper.GenerateMetricDefinitionFilterString(filter.DimensionFilters.Select(df => df.Name)); // Get definitions for requested metrics IList <MetricDefinition> definitions = (await this.Client.MetricDefinitionOperations.GetMetricDefinitionsAsync( resourceUri, filterStringNamesOnly, cancellationToken).ConfigureAwait(false)).MetricDefinitionCollection.Value; // Get Metrics with definitions return(await this.GetMetricsAsync(resourceUri, filterString, definitions, cancellationToken)); }
public Task <MetricListResponse> GetMetricsAsync(string resourceId, string filterString, IEnumerable <MetricDefinition> definitions, string invocationId) { MetricFilter filter = MetricFilterExpressionParser.Parse(filterString); return(Task.Factory.StartNew(() => new MetricListResponse() { RequestId = invocationId, StatusCode = HttpStatusCode.OK, MetricCollection = new MetricCollection() { Value = definitions == null ? new List <Metric>() : definitions.Select(d => new Metric() { Name = d.Name, Unit = d.Unit, ResourceId = resourceId, StartTime = filter.StartTime, EndTime = filter.EndTime, TimeGrain = filter.TimeGrain, MetricValues = new List <MetricValue>(), Properties = new Dictionary <string, string>() }).ToList() } })); }
public async Task <MetricListResponse> GetMetricsAsync(string resourceId, string filterString, IEnumerable <MetricDefinition> definitions, string invocationId) { MetricFilter filter = MetricFilterExpressionParser.Parse(filterString); var metricsPerBlob = new Dictionary <string, Task <Dictionary <string, List <MetricValueBlob> > > >(StringComparer.OrdinalIgnoreCase); // We download all the relevant blobs first and then use the data later, to avoid download the same blob more than once. foreach (MetricDefinition metricDefinition in definitions) { if (!IsMetricDefinitionIncluded(filter, metricDefinition)) { continue; } foreach (MetricAvailability availability in metricDefinition.MetricAvailabilities) { if (availability.BlobLocation == null) { continue; } foreach (BlobInfo blobInfo in availability.BlobLocation.BlobInfo) { string blobId = GetBlobEndpoint(blobInfo); if (!metricsPerBlob.ContainsKey(blobId)) { metricsPerBlob.Add(blobId, FetchMetricValuesFromBlob(blobInfo, filter)); } } } } foreach (var task in metricsPerBlob.Values) { await task; } var result = new MetricListResponse { MetricCollection = new MetricCollection { Value = new List <Metric>() } }; // Populate the metrics result using the data from the blobs. foreach (MetricDefinition metricDefinition in definitions) { if (!IsMetricDefinitionIncluded(filter, metricDefinition)) { continue; } foreach (MetricAvailability availability in metricDefinition.MetricAvailabilities) { if (availability.BlobLocation == null) { continue; } var metricValues = new List <MetricValueBlob>(); foreach (BlobInfo blobInfo in availability.BlobLocation.BlobInfo) { string blobId = GetBlobEndpoint(blobInfo); List <MetricValueBlob> metricsInBlob; if (metricsPerBlob[blobId].Result.TryGetValue(metricDefinition.Name.Value, out metricsInBlob)) { metricValues.AddRange(metricsInBlob); } } var metric = new Metric { Name = new LocalizableString { Value = metricDefinition.Name.Value, LocalizedValue = metricDefinition.Name.LocalizedValue, }, StartTime = filter.StartTime, EndTime = filter.EndTime, MetricValues = GetAggregatedByTimestamp(metricValues), TimeGrain = availability.TimeGrain, }; result.MetricCollection.Value.Add(metric); } } return(result); }
// Alternate method for getting metrics by passing in the definitions public async Task <MetricListResponse> GetMetricsAsync( string resourceUri, string filterString, IEnumerable <MetricDefinition> definitions, CancellationToken cancellationToken) { if (definitions == null) { throw new ArgumentNullException("definitions"); } if (resourceUri == null) { throw new ArgumentNullException("resourceUri"); } // Remove any '/' characters from the start since these are handled by the hydra (thin) client // Don't encode Uri segments here since this will mess up the SAS retrievers (they use the resourceUri directly) resourceUri = resourceUri.TrimStart('/'); MetricListResponse result; string invocationId = TracingAdapter.NextInvocationId.ToString(CultureInfo.InvariantCulture); // If no definitions provided, return empty collection if (!definitions.Any()) { this.LogStartGetMetrics(invocationId, resourceUri, filterString, definitions); result = new MetricListResponse() { RequestId = Guid.NewGuid().ToString("D"), StatusCode = HttpStatusCode.OK, MetricCollection = new MetricCollection() { Value = new Metric[0] } }; this.LogEndGetMetrics(invocationId, result); return(result); } // Parse MetricFilter MetricFilter filter = MetricFilterExpressionParser.Parse(filterString); // Names in filter must match the names in the definitions if (filter.DimensionFilters != null && filter.DimensionFilters.Any()) { IEnumerable <string> filterNames = filter.DimensionFilters.Select(df => df.Name); IEnumerable <string> definitionNames = definitions.Select(d => d.Name.Value); IEnumerable <string> filterOnly = filterNames.Where(fn => !definitionNames.Contains(fn, StringComparer.InvariantCultureIgnoreCase)); IEnumerable <string> definitionOnly = definitionNames.Where(df => !filterNames.Contains(df, StringComparer.InvariantCultureIgnoreCase)); if (filterOnly.Any() || definitionOnly.Any()) { throw new ArgumentException("Set of names specified in filter string must match set of names in provided definitions", "filterString"); } // "Filter out" metrics with unsupported dimensions definitions = definitions.Where(d => SupportsRequestedDimensions(d, filter)); } else { filter = new MetricFilter() { TimeGrain = filter.TimeGrain, StartTime = filter.StartTime, EndTime = filter.EndTime, DimensionFilters = definitions.Select(d => new MetricDimension() { Name = d.Name.Value }) }; } // Parse out provider name and determine if provider is storage string providerName = this.GetProviderFromResourceId(resourceUri); bool isStorageProvider = string.Equals(providerName, "Microsoft.Storage", StringComparison.OrdinalIgnoreCase) || string.Equals(providerName, "Microsoft.ClassicStorage", StringComparison.OrdinalIgnoreCase); // Create supported MetricRetrievers IMetricRetriever proxyRetriever = new ProxyMetricRetriever(this); IMetricRetriever shoeboxRetriever = new ShoeboxMetricRetriever(); IMetricRetriever storageRetriever = new StorageMetricRetriever(); IMetricRetriever blobShoeboxMetricRetriever = new BlobShoeboxMetricRetriever(); IMetricRetriever emptyRetriever = EmptyMetricRetriever.Instance; // Create the selector function here so it has access to the retrievers, filter, and providerName Func <MetricDefinition, IMetricRetriever> retrieverSelector = (d) => { if (!d.MetricAvailabilities.Any()) { return(emptyRetriever); } if (isStorageProvider) { return(storageRetriever); } if (IsBlobSasMetric(d, filter.TimeGrain)) { return(blobShoeboxMetricRetriever); } if (IsTableSasMetric(d, filter.TimeGrain)) { return(shoeboxRetriever); } return(proxyRetriever); }; // Group definitions by retriever so we can make one request to each retriever IEnumerable <IGrouping <IMetricRetriever, MetricDefinition> > groups = definitions.GroupBy(retrieverSelector); // Get Metrics from each retriever (group) IEnumerable <Task <MetricListResponse> > locationTasks = groups.Select(g => g.Key.GetMetricsAsync(resourceUri, GetFilterStringForDefinitions(filter, g), g, invocationId)); // Aggregate metrics from all groups this.LogStartGetMetrics(invocationId, resourceUri, filterString, definitions); MetricListResponse[] results = (await Task.Factory.ContinueWhenAll(locationTasks.ToArray(), tasks => tasks.Select(t => t.Result))).ToArray(); IEnumerable <Metric> metrics = results.Aggregate <MetricListResponse, IEnumerable <Metric> >( new List <Metric>(), (list, response) => list.Union(response.MetricCollection.Value)); this.LogMetricCountFromResponses(invocationId, metrics.Count()); // Fill in values (resourceUri, displayName, unit) from definitions CompleteShoeboxMetrics(metrics, definitions, resourceUri); // Add empty objects for metrics that had no values come back, ensuring a metric is returned for each definition IEnumerable <Metric> emptyMetrics = (await emptyRetriever.GetMetricsAsync( resourceUri, filterString, definitions.Where(d => !metrics.Any(m => string.Equals(m.Name.Value, d.Name.Value, StringComparison.OrdinalIgnoreCase))), invocationId)).MetricCollection.Value; // Create response (merge and wrap metrics) result = new MetricListResponse() { RequestId = Guid.NewGuid().ToString("D"), StatusCode = HttpStatusCode.OK, MetricCollection = new MetricCollection() { Value = metrics.Union(emptyMetrics).ToList() } }; this.LogEndGetMetrics(invocationId, result); return(result); }