public GetMetricsCommandTests() { insightsMetricOperationsMock = new Mock<IMetricOperations>(); insightsClientMock = new Mock<InsightsClient>(); commandRuntimeMock = new Mock<ICommandRuntime>(); cmdlet = new GetMetricsCommand() { CommandRuntime = commandRuntimeMock.Object, InsightsClient = insightsClientMock.Object }; response = Utilities.InitializeMetricResponse(); insightsMetricOperationsMock.Setup(f => f.GetMetricsAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>())) .Returns(Task.FromResult<MetricListResponse>(response)) .Callback((string f, string s, CancellationToken t) => { resourceId = f; filter = s; }); insightsClientMock.SetupGet(f => f.MetricOperations).Returns(this.insightsMetricOperationsMock.Object); }
public GetAzureRmMetricTests(Xunit.Abstractions.ITestOutputHelper output) { ServiceManagemenet.Common.Models.XunitTracingInterceptor.AddToContext(new ServiceManagemenet.Common.Models.XunitTracingInterceptor(output)); insightsMetricOperationsMock = new Mock<IMetricOperations>(); insightsClientMock = new Mock<InsightsClient>(); commandRuntimeMock = new Mock<ICommandRuntime>(); cmdlet = new GetAzureRmMetricCommand() { CommandRuntime = commandRuntimeMock.Object, InsightsClient = insightsClientMock.Object }; response = Utilities.InitializeMetricResponse(); insightsMetricOperationsMock.Setup(f => f.GetMetricsAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>())) .Returns(Task.FromResult<MetricListResponse>(response)) .Callback((string f, string s, CancellationToken t) => { resourceId = f; filter = s; }); insightsClientMock.SetupGet(f => f.MetricOperations).Returns(this.insightsMetricOperationsMock.Object); }
public async Task<MetricListResponse> GetMetricsAsync(string resourceId, string filterString, IEnumerable<MetricDefinition> definitions, string invocationId) { MetricFilter filter = MetricFilterExpressionParser.Parse(filterString); var ongoingTasksPerBlob = new Dictionary<string, Task<Dictionary<string, List<MetricValueBlob>>>>(); var metricsPerBlob = new Dictionary<string, 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 (filter != null && filter.TimeGrain != default(TimeSpan) && filter.TimeGrain != availability.TimeGrain) { continue; } if (availability.BlobLocation == null) { continue; } foreach (BlobInfo blobInfo in availability.BlobLocation.BlobInfo) { string blobId = GetBlobEndpoint(blobInfo); if (!metricsPerBlob.ContainsKey(blobId) && !ongoingTasksPerBlob.ContainsKey(blobId)) { ongoingTasksPerBlob.Add(blobId, FetchMetricValuesFromBlob(blobInfo, filter)); } if (ongoingTasksPerBlob.Count == Util.NumberOfParallelCallsForMetricBlobs) { foreach (var blobMetricPair in ongoingTasksPerBlob) { metricsPerBlob[blobMetricPair.Key] = await blobMetricPair.Value; } ongoingTasksPerBlob.Clear(); } } } } foreach (var blobMetricPair in ongoingTasksPerBlob) { metricsPerBlob[blobMetricPair.Key] = await blobMetricPair.Value; } 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 (filter != null && filter.TimeGrain != default(TimeSpan) && filter.TimeGrain != availability.TimeGrain) { continue; } 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].TryGetValue(metricDefinition.Name.Value, out metricsInBlob)) { metricsInBlob.Sort(CompareMetrics); 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; }
private void LogEndGetMetrics(string invocationId, MetricListResponse result) { if (TracingAdapter.IsEnabled) { TracingAdapter.Exit(invocationId, result); } }