예제 #1
0
 private void SendMetrics()
 {
     if (Monitor.TryEnter(_syncObj))
     {
         try
         {
             using (var stream = new MemoryStream())
             {
                 ScrapeHandler.ProcessScrapeRequest(_registry.CollectAll(), ContentType, stream);
                 using (var client = new WebClient())
                 {
                     client.UploadData(_endpoint, "POST", stream.ToArray());
                 }
             }
         }
         catch (Exception e)
         {
             Trace.WriteLine(string.Format("Exception in send metrics: {0}", e));
         }
         finally
         {
             Monitor.Exit(_syncObj);
         }
     }
 }
예제 #2
0
        private void StartLoop(IScheduler scheduler)
        {
            //delegate allocations below - but that's fine as it's not really on the "critical path" (polled relatively infrequently) - and it's much more readable this way
            scheduler.Schedule(repeatAction => _httpListener.BeginGetContext(ar =>
            {
                try
                {
                    var httpListenerContext = _httpListener.EndGetContext(ar);
                    var request             = httpListenerContext.Request;
                    var response            = httpListenerContext.Response;

                    response.StatusCode = 200;

                    var acceptHeader     = request.Headers.Get("Accept");
                    var acceptHeaders    = acceptHeader == null ? null : acceptHeader.Split(',');
                    var contentType      = ScrapeHandler.GetContentType(acceptHeaders);
                    response.ContentType = contentType;

                    using (var outputStream = response.OutputStream)
                    {
                        var collected = _registry.CollectAll();
                        ScrapeHandler.ProcessScrapeRequest(collected, contentType, outputStream);
                    }

                    response.Close();
                }
                catch (Exception e)
                {
                    Trace.WriteLine(string.Format("Error in MetricsServer: {0}", e));
                }
                repeatAction.Invoke();
            }, null));
        }
예제 #3
0
        protected override Task StartServer(CancellationToken cancel)
        {
            // Kick off the actual processing to a new thread and return a Task for the processing thread.
            return(Task.Run(async delegate
            {
                while (true)
                {
                    // We schedule approximately at the configured interval. There may be some small accumulation for the
                    // part of the loop we do not measure but it is close enough to be acceptable for all practical scenarios.
                    var duration = Stopwatch.StartNew();

                    try
                    {
                        var metrics = _registry.CollectAll();

                        var stream = new MemoryStream();
                        ScrapeHandler.ProcessScrapeRequest(metrics, ContentType, stream);

                        stream.Position = 0;
                        // StreamContent takes ownership of the stream.
                        var response = await _httpClient.PostAsync(_targetUrl, new StreamContent(stream));

                        // If anything goes wrong, we want to get at least an entry in the trace log.
                        response.EnsureSuccessStatusCode();
                    }
                    catch (ScrapeFailedException ex)
                    {
                        Trace.WriteLine($"Skipping metrics push due to failed scrape: {ex.Message}");
                    }
                    catch (Exception ex) when(!(ex is OperationCanceledException))
                    {
                        Trace.WriteLine(string.Format("Error in MetricPusher: {0}", ex));
                    }

                    // We always stop after pushing metrics, to ensure that the latest state is flushed when told to stop.
                    if (cancel.IsCancellationRequested)
                    {
                        break;
                    }

                    var sleepTime = _pushInterval - duration.Elapsed;

                    // Sleep until the interval elapses or the pusher is asked to shut down.
                    if (sleepTime > TimeSpan.Zero)
                    {
                        try
                        {
                            await Task.Delay(sleepTime, cancel);
                        }
                        catch (OperationCanceledException)
                        {
                            // The task was cancelled.
                            // We continue the loop here to ensure final state gets pushed.
                            continue;
                        }
                    }
                }
            }));
        }
            public void Configure(IApplicationBuilder app)
            {
                app.Run(context => {
                    var response        = context.Response;
                    var request         = context.Request;
                    response.StatusCode = 200;

                    var acceptHeader     = request.Headers["Accept"];
                    var contentType      = ScrapeHandler.GetContentType(acceptHeader);
                    response.ContentType = contentType;

                    using (var outputStream = response.Body) {
                        var collected = _registry.CollectAll();
                        ScrapeHandler.ProcessScrapeRequest(collected, contentType, outputStream);
                    };
                    return(Task.FromResult(true));
                });
            }
예제 #5
0
        public async Task Invoke(HttpContext context)
        {
            // We just handle the root URL (/metrics or whatnot).
            if (!string.IsNullOrWhiteSpace(context.Request.Path.Value))
            {
                await _next(context);

                return;
            }

            var request  = context.Request;
            var response = context.Response;

            var acceptHeaders = request.Headers["Accept"];
            var contentType   = ScrapeHandler.GetContentType(acceptHeaders);

            response.ContentType = contentType;

            IEnumerable <MetricFamily> metrics;

            try
            {
                metrics = _registry.CollectAll();
            }
            catch (ScrapeFailedException ex)
            {
                response.StatusCode = 503;

                if (!string.IsNullOrWhiteSpace(ex.Message))
                {
                    using (var writer = new StreamWriter(response.Body))
                        await writer.WriteAsync(ex.Message);
                }

                return;
            }

            response.StatusCode = 200;

            using (var outputStream = response.Body)
                ScrapeHandler.ProcessScrapeRequest(metrics, contentType, outputStream);
        }
        protected override Task StartServer(CancellationToken cancel)
        {
            // This will ensure that any failures to start are nicely thrown from StartServerAsync.
            _httpListener.Start();

            // Kick off the actual processing to a new thread and return a Task for the processing thread.
            return(Task.Factory.StartNew(delegate
            {
                try
                {
                    while (!cancel.IsCancellationRequested)
                    {
                        // There is no way to give a CancellationToken to GCA() so, we need to hack around it a bit.
                        var getContext = _httpListener.GetContextAsync();
                        getContext.Wait(cancel);
                        var context = getContext.Result;
                        var request = context.Request;
                        var response = context.Response;

                        try
                        {
                            IEnumerable <MetricFamily> metrics;

                            try
                            {
                                metrics = _registry.CollectAll();
                            }
                            catch (ScrapeFailedException ex)
                            {
                                response.StatusCode = 503;

                                if (!string.IsNullOrWhiteSpace(ex.Message))
                                {
                                    using (var writer = new StreamWriter(response.OutputStream))
                                        writer.Write(ex.Message);
                                }

                                continue;
                            }

                            var acceptHeader = request.Headers.Get("Accept");
                            var acceptHeaders = acceptHeader?.Split(',');
                            var contentType = ScrapeHandler.GetContentType(acceptHeaders);
                            response.ContentType = contentType;

                            response.StatusCode = 200;

                            using (var outputStream = response.OutputStream)
                                ScrapeHandler.ProcessScrapeRequest(metrics, contentType, outputStream);
                        }
                        catch (Exception ex) when(!(ex is OperationCanceledException))
                        {
                            Trace.WriteLine(string.Format("Error in MetricsServer: {0}", ex));

                            try
                            {
                                response.StatusCode = 500;
                            }
                            catch
                            {
                                // Might be too late in request processing to set response code, so just ignore.
                            }
                        }
                        finally
                        {
                            response.Close();
                        }
                    }
                }
                finally
                {
                    _httpListener.Stop();
                    _httpListener.Close();
                }
            }, TaskCreationOptions.LongRunning));
        }
예제 #7
0
        /// <summary>
        /// Push metrics to single pushgateway endpoint
        /// </summary>
        /// <param name="metrics">Collection of metrics</param>
        /// <param name="endpoints">PushGateway endpoints - fault-tolerance</param>
        /// <param name="job">job name</param>
        /// <param name="instance">instance name</param>
        /// <param name="contentType">content-type</param>
        /// <param name="additionalLabels">additional labels</param>
        /// <returns></returns>
        public async Task PushAsync(IEnumerable <MetricFamily> metrics, string[] endpoints, string job, string instance, string contentType = ContentType, IEnumerable <Tuple <string, string> > additionalLabels = null)
        {
            if (endpoints == null || !endpoints.Any())
            {
                throw new ArgumentNullException(nameof(endpoints));
            }

            if (string.IsNullOrEmpty(job))
            {
                throw new ArgumentNullException(nameof(job));
            }

            var tasks            = new List <Task <HttpResponseMessage> >(endpoints.Length);
            var streamsToDispose = new List <Stream>();

            foreach (var endpoint in endpoints)
            {
                if (string.IsNullOrEmpty(endpoint))
                {
                    throw new ArgumentNullException(nameof(endpoint));
                }

                var url = $"{endpoint.TrimEnd('/')}/metrics/job/{job}";
                if (!string.IsNullOrEmpty(instance))
                {
                    url = $"{url}/instance/{instance}";
                }

                var sb = new StringBuilder();
                sb.Append(url);
                if (additionalLabels != null)
                {
                    foreach (var pair in additionalLabels)
                    {
                        if (pair == null || string.IsNullOrEmpty(pair.Item1) || string.IsNullOrEmpty(pair.Item2))
                        {
                            // TODO: Surely this should throw an exception?
                            Trace.WriteLine("Ignoring invalid label set");
                            continue;
                        }

                        sb.AppendFormat("/{0}/{1}", pair.Item1, pair.Item2);
                    }
                }

                if (!Uri.TryCreate(sb.ToString(), UriKind.Absolute, out var targetUrl))
                {
                    throw new ArgumentException("Endpoint must be a valid url", nameof(endpoint));
                }

                var memoryStream = new MemoryStream();
                streamsToDispose.Add(memoryStream);
                ScrapeHandler.ProcessScrapeRequest(metrics, contentType, memoryStream);
                memoryStream.Position = 0;
                var streamContent = new StreamContent(memoryStream);
                tasks.Add(_httpClient.PostAsync(targetUrl, streamContent));
            }

            await Task.WhenAll(tasks).ConfigureAwait(false);

            Exception exception = null;

            foreach (var task in tasks)
            {
                var response = await task.ConfigureAwait(false);

                try
                {
                    response.EnsureSuccessStatusCode();
                }
                catch (Exception ex)
                {
                    exception = ex;
                }
            }

            streamsToDispose.ForEach(s => s.Dispose());

            if (exception != null)
            {
                throw exception;
            }
        }