예제 #1
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
                    {
                        using (var stream = new MemoryStream())
                        {
                            var serializer = new TextSerializer(stream);
                            await _registry.CollectAndSerializeAsync(serializer, cancel);

                            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 stop only 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;
                        }
                    }
                }
            }));
        }
예제 #2
0
        public async Task Invoke(HttpContext context)
        {
            var response = context.Response;

            try
            {
                // We first touch the response.Body only in the callback because touching
                // it means we can no longer send headers (the status code).
                var serializer = new TextSerializer(delegate
                {
                    response.ContentType = PrometheusConstants.ExporterContentType;
                    response.StatusCode  = StatusCodes.Status200OK;
                    return(response.Body);
                });

                await _registry.CollectAndSerializeAsync(serializer, context.RequestAborted);
            }
            catch (OperationCanceledException) when(context.RequestAborted.IsCancellationRequested)
            {
                // The scrape was cancalled by the client. This is fine. Just swallow the exception to not generate pointless spam.
            }
            catch (ScrapeFailedException ex)
            {
                // This can only happen before any serialization occurs, in the pre-collect callbacks.
                // So it should still be safe to update the status code and write an error message.
                response.StatusCode = StatusCodes.Status503ServiceUnavailable;

                if (!string.IsNullOrWhiteSpace(ex.Message))
                {
                    using (var writer = new StreamWriter(response.Body, PrometheusConstants.ExportEncoding,
                                                         bufferSize: -1, leaveOpen: true))
                        await writer.WriteAsync(ex.Message);
                }
            }
        }
        /// <summary>
        /// Collects all metrics and exports them in text document format to the provided stream.
        ///
        /// This method is designed to be used with custom output mechanisms that do not use an IMetricServer.
        /// </summary>
        public void CollectAndExportAsText(Stream to)
        {
            if (to == null)
            {
                throw new ArgumentNullException(nameof(to));
            }

            using (var serializer = new TextSerializer(to, leaveOpen: true))
                CollectAndSerialize(serializer);
        }
        public async Task Invoke(HttpContext context)
        {
            // We just handle the root URL (/metrics or whatnot).
            if (!string.IsNullOrWhiteSpace(context.Request.Path.Value.Trim('/')))
            {
                await _next(context);

                return;
            }

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

            try
            {
                // We first touch the response.Body only in the callback because touching
                // it means we can no longer send headers (the status code).
                var serializer = new TextSerializer(delegate
                {
                    response.ContentType = PrometheusConstants.ExporterContentType;
                    response.StatusCode  = StatusCodes.Status200OK;
                    return(response.Body);
                });

                await _registry.CollectAndSerializeAsync(serializer, default);

                response.Body.Dispose();
            }
            catch (ScrapeFailedException ex)
            {
                // This can only happen before any serialization occurs, in the pre-collect callbacks.
                // So it should still be safe to update the status code and write an error message.
                response.StatusCode = StatusCodes.Status503ServiceUnavailable;

                if (!string.IsNullOrWhiteSpace(ex.Message))
                {
                    using (var writer = new StreamWriter(response.Body))
                        await writer.WriteAsync(ex.Message);
                }
            }
        }
예제 #5
0
        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
                        {
                            try
                            {
                                using (var serializer = new TextSerializer(delegate
                                {
                                    response.ContentType = PrometheusConstants.ExporterContentType;
                                    response.StatusCode = 200;
                                    return response.OutputStream;
                                }))
                                {
                                    _registry.CollectAndSerialize(serializer);
                                }
                            }
                            catch (ScrapeFailedException ex)
                            {
                                // This can only happen before anything is written to the stream, so it
                                // should still be safe to update the status code and report an error.
                                response.StatusCode = 503;

                                if (!string.IsNullOrWhiteSpace(ex.Message))
                                {
                                    using (var writer = new StreamWriter(response.OutputStream))
                                        writer.Write(ex.Message);
                                }
                            }
                        }
                        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));
        }
예제 #6
0
        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
                {
                    Thread.CurrentThread.Name = "Metric Server";     //Max length 16 chars (Linux limitation)
                    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;

                        // Kick the request off to a background thread for processing.
                        _ = Task.Factory.StartNew(async delegate
                        {
                            var request = context.Request;
                            var response = context.Response;

                            try
                            {
                                Thread.CurrentThread.Name = "Metric Process";
                                try
                                {
                                    // We first touch the response.OutputStream only in the callback because touching
                                    // it means we can no longer send headers (the status code).
                                    var serializer = new TextSerializer(delegate
                                    {
                                        response.ContentType = PrometheusConstants.ExporterContentType;
                                        response.StatusCode = 200;
                                        return response.OutputStream;
                                    });

                                    await _registry.CollectAndSerializeAsync(serializer, cancel);
                                    response.OutputStream.Dispose();
                                }
                                catch (ScrapeFailedException ex)
                                {
                                    // This can only happen before anything is written to the stream, so it
                                    // should still be safe to update the status code and report an error.
                                    response.StatusCode = 503;

                                    if (!string.IsNullOrWhiteSpace(ex.Message))
                                    {
                                        using (var writer = new StreamWriter(response.OutputStream))
                                            writer.Write(ex.Message);
                                    }
                                }
                            }
                            catch (Exception ex) when(!(ex is OperationCanceledException))
                            {
                                if (!_httpListener.IsListening)
                                {
                                    return;   // We were shut down.
                                }
                                Trace.WriteLine(string.Format("Error in {0}: {1}", nameof(MetricServer), ex));

                                try
                                {
                                    response.StatusCode = 500;
                                }
                                catch
                                {
                                    // Might be too late in request processing to set response code, so just ignore.
                                }
                            }
                            finally
                            {
                                response.Close();
                            }
                        }, TaskCreationOptions.LongRunning);
                    }
                }
                finally
                {
                    _httpListener.Stop();
                    // This should prevent any currently processed requests from finishing.
                    _httpListener.Close();
                }
            }, TaskCreationOptions.LongRunning));
        }