Example #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);

                            // Do not pass CT because we only want to cancel after pushing, so a flush is always performed.
                            await _registry.CollectAndSerializeAsync(serializer, default);

                            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)
                    {
                        LogProxy.WriteLine($"Skipping metrics push due to failed scrape: {ex.Message}");
                    }
                    catch (Exception ex) when(!(ex is OperationCanceledException))
                    {
                        LogProxy.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;
                        }
                    }
                }
            }));
        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(async 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
                            {
                                // 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))
                        {
                            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));
        }