示例#1
0
 // Creates a TableQuery for each named metric and returns a dictionary mapping each name to its query
 // Note: The overall start and end times are used in each query since this reduces processing and the query will still work the same on each Nday table
 private static Dictionary <string, TableQuery> GenerateMetricNameQueries(IEnumerable <string> names, string partitionKey, DateTime startTime, DateTime endTime)
 {
     return(names.ToDictionary(name => ShoeboxHelper.TrimAndEscapeKey(name) + "__").ToDictionary(kvp => kvp.Value, kvp =>
                                                                                                 GenerateMetricQuery(
                                                                                                     partitionKey,
                                                                                                     kvp.Key + (DateTime.MaxValue.Ticks - endTime.Ticks).ToString("D19"),
                                                                                                     kvp.Key + (DateTime.MaxValue.Ticks - startTime.Ticks).ToString("D19"))));
 }
 private string GetFilterStringForDefinitions(MetricFilter filter, IEnumerable <MetricDefinition> definitions)
 {
     return(ShoeboxHelper.GenerateMetricFilterString(new MetricFilter()
     {
         TimeGrain = filter.TimeGrain,
         StartTime = filter.StartTime,
         EndTime = filter.EndTime,
         DimensionFilters = filter.DimensionFilters.Where(df =>
                                                          definitions.Any(d => string.Equals(df.Name, d.Name.Value, StringComparison.OrdinalIgnoreCase)))
     }));
 }
        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));
        }
示例#4
0
 // This method tries to figure out the original name of the metric from the encoded name
 // Note: Will unescape the name if it is not in the list, but it will not be able to unhash it if it was hashed
 private static string FindMetricName(string encodedName, IEnumerable <string> names)
 {
     return(names.FirstOrDefault(n => string.Equals(ShoeboxHelper.TrimAndEscapeKey(n), encodedName, StringComparison.OrdinalIgnoreCase)) ??
            ShoeboxHelper.UnEscapeKey(encodedName));
 }
示例#5
0
        // Generates queries for all metrics by timestamp (timestamp-name rowKey format) and filters the results to the requested metrics (if any)
        // Note: Does not populate Metric fields unrelated to query (i.e. "display name", resourceUri, and properties)
        private static async Task <MetricCollection> GetMetricsByTimestampAsync(MetricFilter filter, MetricLocation location, string invocationId)
        {
            // Find all the tables that fall partially or fully within the timerange
            IEnumerable <CloudTable> tables = GetNdayTables(filter, location);

            // Generate a query for the partition key and time range
            TableQuery query = GenerateMetricTimestampQuery(location.PartitionKey, filter.StartTime, filter.EndTime);

            // Get all the entities for the query
            IEnumerable <DynamicTableEntity> entities = await GetEntitiesAsync(tables, query, invocationId).ConfigureAwait(false);

            ICollection <string> dimensionFilterNames = null;

            if (filter.DimensionFilters != null)
            {
                dimensionFilterNames = new HashSet <string>(filter.DimensionFilters.Select(df => ShoeboxHelper.TrimAndEscapeKey(df.Name)));
            }

            var metricWraps = new Dictionary <string, MetricWrap>();
            var metrics     = new List <Metric>();

            // Iterate over the instances to do conversion and aggregation when needed.
            foreach (var entity in entities)
            {
                string encodedName = GetMetricNameFromRowKeyByTimestampByMetricName(entity.RowKey);

                // When there is filter, skip entities not included in the filter.
                if (dimensionFilterNames != null && !dimensionFilterNames.Contains(encodedName, StringComparer.OrdinalIgnoreCase))
                {
                    continue;
                }

                MetricWrap metricWrap;
                if (!metricWraps.TryGetValue(encodedName, out metricWrap))
                {
                    metricWrap = new MetricWrap
                    {
                        Metric = new Metric()
                        {
                            Name = new LocalizableString()
                            {
                                Value = encodedName
                            },
                            StartTime    = filter.StartTime,
                            EndTime      = filter.EndTime,
                            TimeGrain    = filter.TimeGrain,
                            MetricValues = new List <MetricValue>()
                        },
                        InstanceMetrics = new List <MetricValue>(),
                        GlobalMetrics   = new List <DynamicTableEntity>()
                    };

                    metricWraps[encodedName] = metricWrap;
                    metrics.Add(metricWrap.Metric);
                }

                // Skip aggregated entities
                if (!IsInstanceMetric(entity.RowKey))
                {
                    // We ignore the aggergated metrics if there are instance metrics.
                    if (metricWrap.InstanceMetrics.Count == 0)
                    {
                        metricWrap.GlobalMetrics.Add(entity);
                    }

                    continue;
                }

                MetricValue lastMetricValue = metricWrap.InstanceMetrics.LastOrDefault();
                if (lastMetricValue == null)
                {
                    metricWrap.InstanceMetrics.Add(ResolveMetricEntity(entity));
                }
                else
                {
                    if (lastMetricValue.Timestamp.Ticks == GetTimestampFromIndexTimestampMetricName(entity))
                    {
                        Aggregate(lastMetricValue, entity);
                    }
                    else
                    {
                        metricWrap.InstanceMetrics.Add(ResolveMetricEntity(entity));
                    }
                }
            }

            foreach (var metricWrap in metricWraps.Values)
            {
                // Decide whether to return the aggregation of the instance metrics on the fly or the final value in the storage account
                // If there are instance metrics, the aggregation on the fly is used.
                Metric metric = metricWrap.Metric;
                metric.Name.Value = FindMetricName(metric.Name.Value, dimensionFilterNames);
                if (metricWrap.InstanceMetrics.Count > 0)
                {
                    foreach (var metricValue in metricWrap.InstanceMetrics)
                    {
                        metricValue.Average = metricValue.Total / metricValue.Count;
                    }

                    metric.MetricValues = metricWrap.InstanceMetrics;
                }
                else
                {
                    metric.MetricValues = metricWrap.GlobalMetrics.Select(me => ResolveMetricEntity(me)).ToList();
                }
            }

            return(new MetricCollection()
            {
                Value = metrics
            });
        }
        public async Task <MetricDefinitionListResponse> GetMetricDefinitionsAsync(string resourceUri, string filterString, CancellationToken cancellationToken)
        {
            MetricDefinitionListResponse result;

            string invocationId = TracingAdapter.NextInvocationId.ToString(CultureInfo.InvariantCulture);

            this.LogStartGetMetricDefinitions(invocationId, resourceUri, filterString);

            // Remove any '/' characters from the start since these are handled by the hydra (thin) client
            // Encode segments here since they are not encoded by hydra client
            resourceUri = ShoeboxHelper.EncodeUriSegments(resourceUri.TrimStart('/'));
            IEnumerable <MetricDefinition> definitions = null;

            // If no filter string, must request all metric definitions since we don't know if we have them all
            if (string.IsNullOrWhiteSpace(filterString))
            {
                // request all definitions
                definitions = (await this.GetMetricDefinitionsInternalAsync(resourceUri, string.Empty, CancellationToken.None).ConfigureAwait(false))
                              .MetricDefinitionCollection.Value;

                // cache definitions
                if (this.Client.IsCacheEnabled)
                {
                    this.Client.Cache[resourceUri] = definitions;
                }

                // wrap and return definitions
                result = new MetricDefinitionListResponse()
                {
                    StatusCode = HttpStatusCode.OK,
                    MetricDefinitionCollection = new MetricDefinitionCollection()
                    {
                        Value = definitions.ToList()
                    }
                };

                this.LogEndGetMetricDefinitions(invocationId, result);

                return(result);
            }

            // Parse the filter and retrieve cached definitions
            IEnumerable <string> names = MetricDefinitionFilterParser.Parse(filterString);

            if (this.Client.IsCacheEnabled)
            {
                definitions = this.Client.Cache[resourceUri];
            }

            // Find the names in the filter that don't appear on any of the cached definitions
            IEnumerable <string> missing = definitions == null
                ? names
                : names.Where((n => !definitions.Any(d => string.Equals(d.Name.Value, n, StringComparison.OrdinalIgnoreCase))));

            // Request any missing definitions and update cache (if any)
            if (missing.Any())
            {
                string missingFilter = ShoeboxHelper.GenerateMetricDefinitionFilterString(missing);

                // Request missing definitions
                var missingDefinitions = (await this.GetMetricDefinitionsInternalAsync(resourceUri, missingFilter, cancellationToken).ConfigureAwait(false))
                                         .MetricDefinitionCollection.Value;

                // merge definitions
                definitions = (definitions ?? new MetricDefinition[0]).Union(missingDefinitions);

                // Store the new set of definitions
                if (this.Client.IsCacheEnabled)
                {
                    this.Client.Cache[resourceUri] = definitions;
                }
            }

            // Filter out the metrics that were cached but not requested and wrap
            result = new MetricDefinitionListResponse()
            {
                StatusCode = HttpStatusCode.OK,
                MetricDefinitionCollection = new MetricDefinitionCollection()
                {
                    Value = definitions.Where(d => names.Contains(d.Name.Value)).ToList()
                }
            };

            this.LogEndGetMetricDefinitions(invocationId, result);

            return(result);
        }