// 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 ProcessMetricRequests() { _logger.Debug("Beginning to process metric requests"); var storageEngine = new SqliteStorageEngine(ApplicationSettings.DatabaseName); // Start the webserver _logger.Debug("Beginning webserver on port {0}", _webPortNumber); var bootstrapper = new OverlookBootStrapper(storageEngine); var uri = new Uri("http://localhost:" + _webPortNumber); var webServer = new NancyHost(uri, bootstrapper); webServer.Start(); _logger.Debug("Web server started"); var retrievers = new IMetricRetriever[] { new OpenProcessMetricRetriever(), new OpenHardwareMonitorMetricRetriever() }; UpdateDisplays(storageEngine); var lastSnapshotTime = DateTime.MinValue; var secondsBetweenChecks = ApplicationSettings.SecondsBetweenSnapshots; while (!_cancellationTokenSource.Token.IsCancellationRequested) { if ((DateTime.Now - lastSnapshotTime).TotalSeconds > secondsBetweenChecks) { _logger.Debug("Generating snapshot"); var snapshot = new Snapshot { Date = DateTime.Now, MetricValues = retrievers.SelectMany(x => x.GetCurrentMetricValues()) .ToArray() }; _logger.Debug("Storing Snapshot"); storageEngine.StoreSnapshot(snapshot); _logger.Debug("Snapshot stored"); UpdateDisplays(storageEngine); lastSnapshotTime = DateTime.Now; } else { Thread.Sleep(100); } } _logger.Debug("Stopping webserver"); webServer.Stop(); _logger.Debug("Webserver stopped"); }