/// <summary>
        /// Execute a counter query against a single server.
        /// </summary>
        /// <param name="counterName">Name of the counter to query.</param>
        /// <param name="server">Server to query.</param>
        /// <param name="queryParameters">Optional query parameters for the counter.</param>
        /// <returns>single response aggregated from all servers</returns>
        public async Task <CounterQueryResponse> CounterQuery(string counterName, ServerInfo server,
                                                              IDictionary <string, string> queryParameters = null)
        {
            if (server == null)
            {
                throw new ArgumentNullException("server");
            }

            var request = new TieredRequest
            {
                Sources = new List <ServerInfo> {
                    server
                },
            };

            return(await this.CounterQuery(counterName, request, queryParameters,
                                           DimensionSet.FromQueryParameters(queryParameters)));
        }
        internal async Task <CounterQueryResponse> Query(string counterName, TieredRequest fanoutRequest,
                                                         DimensionSpecification queryParameters)
        {
            Task <CounterQueryResponse> distributedRequest;

            // if fanout is required, start it here (don't block)
            if (fanoutRequest != null && fanoutRequest.Sources != null && fanoutRequest.Sources.Count > 0)
            {
                distributedRequest = this.server.CreateQueryClient(fanoutRequest)
                                     .CounterQuery(counterName, fanoutRequest, queryParameters,
                                                   DimensionSet.FromQueryParameters(queryParameters));
            }
            else
            {
                distributedRequest = Task.FromResult <CounterQueryResponse>(null);
            }

            // get the local data (in parallel to the async distributed request running, if necessary)
            var localResponse = new CounterQueryResponse();

            try
            {
                var counter = this.server.DataManager.GetCounter <Counter>(counterName);
                if (counter == null)
                {
                    localResponse.HttpResponseCode = (int)HttpStatusCode.NotFound;
                    localResponse.ErrorMessage     = "Counter not found.";
                }
                else
                {
                    Events.Write.BeginProcessingQuery(RestCommands.CounterQueryCommand, counterName);
                    localResponse.Samples = counter.Query(queryParameters).ToList();

                    if (localResponse.Samples.Count > 0)
                    {
                        Events.Write.EndProcessingQuery("CounterQuery", counter.Name, 200);
                        localResponse.HttpResponseCode = (int)HttpStatusCode.OK;
                    }
                    else
                    {
                        Events.Write.EndProcessingQuery("CounterQuery", counter.Name, 404);
                        localResponse.HttpResponseCode = (int)HttpStatusCode.NotFound;
                        localResponse.ErrorMessage     = "No data matched query.";
                    }
                }
            }
            catch (Exception ex)
            {
                if (ex is FormatException || ex is ArgumentOutOfRangeException || ex is ArgumentException ||
                    ex is KeyNotFoundException || ex is NotSupportedException)
                {
                    localResponse.HttpResponseCode = (int)HttpStatusCode.BadRequest;
                    localResponse.ErrorMessage     = ex.Message;
                }
                else
                {
                    throw;
                }
            }

            // wait for the distributed request to finish
            var distributedResponse = await distributedRequest;

            if (fanoutRequest != null && fanoutRequest.IncludeRequestDiagnostics && localResponse.RequestDetails != null)
            {
                localResponse.RequestDetails.Add(new RequestDetails
                {
                    Server = new MetricSystem.ServerInfo
                    {
                        Hostname        = this.server.Hostname,
                        Port            = this.server.Port,
                        Datacenter      = this.server.Datacenter,
                        MachineFunction = this.server.MachineFunction,
                    },
                    HttpResponseCode  = localResponse.HttpResponseCode,
                    StatusDescription = localResponse.ErrorMessage ?? string.Empty,
                    Status            = localResponse.HttpResponseCode == (short)HttpStatusCode.OK ? RequestStatus.Success : RequestStatus.ServerFailureResponse,
                    IsAggregator      = distributedResponse != null
                });
            }

            var response = MergeResponses(queryParameters, localResponse,
                                          DistributedQueryClient.ShouldMergeTimeBuckets(queryParameters),
                                          distributedResponse);

            return(response);
        }
 /// <summary>
 /// Execute a distributed counter query based on the initial request
 /// </summary>
 /// <param name="counterName">Name of the counter to query.</param>
 /// <param name="request">Request with source list</param>
 /// <param name="queryParameters">Optional query parameters for the counter.</param>
 /// <returns>single response aggregated from all servers</returns>
 public async Task <CounterQueryResponse> CounterQuery(string counterName, TieredRequest request,
                                                       IDictionary <string, string> queryParameters = null)
 {
     return(await this.CounterQuery(counterName, request, queryParameters,
                                    DimensionSet.FromQueryParameters(queryParameters)));
 }
 public CounterAggregator(IDictionary <string, string> queryParameters)
     : this(DimensionSet.FromQueryParameters(queryParameters))
 {
 }