private async void RequestHandler(object sender, HttpListenerRequestEventArgs context) { try { if (context.Request.HttpMethod == HttpMethods.Get) { context.Response.StatusCode = 200; context.Response.Headers.Add("Content-Type", "text/plain; version=0.0.4"); await metrics.Expose(context.Response.OutputStream, ExposeOptions.Default); } else { context.Response.NotFound(); } context.Response.Close(); } catch (Exception ex) { try { errorHandler?.Invoke(new PrometheusServerException("Error while handling HTTP request", ex)); } catch (Exception) { // ignore exceptions thrown by user supplied callback } } }
private async void ListenerCallback(IAsyncResult result) { try { var context = _listener.EndGetContext(result); if (context.Request.HttpMethod == "GET") { context.Response.StatusCode = 200; context.Response.Headers.Add("Content-Type", "text/plain"); await _metrics.Expose(context.Response.OutputStream, ExposeOptions.Default); } else { context.Response.StatusCode = 405; // Method not allowed } context.Response.Close(); } catch (ObjectDisposedException) { // Do not throw exception on shutdown } catch (HttpListenerException ex) { _logger.LogWarning(ex, "HTTP problem error while providing metric"); } catch (Exception ex) { _logger.LogError(ex, "Unexpected error while providing metric"); } finally { BeginContext(); } }
/// <summary> /// Starts exposing metrics. /// </summary> public PrometheusServer(IOptions <PrometheusServerOptions> options, ILogger <PrometheusServer> logger, IExposable metrics) { string prefix = $"http://*:{options.Value.Port}/"; try { _listener = new HttpListener { Prefixes = { prefix } }; _listener.Start(); _listener.BeginGetContext(ListenerCallback, _listener); } catch (ObjectDisposedException) { // Do not throw exception on shutdown } catch (Exception ex) when(Environment.OSVersion.Platform == PlatformID.Win32NT) { logger.LogCritical(ex, "Please run the following as admin and then retry:\nnetsh http add urlacl {0} user={1}\\{2}", prefix, Environment.GetEnvironmentVariable("USERDOMAIN"), Environment.GetEnvironmentVariable("USERNAME")); throw; } async void ListenerCallback(IAsyncResult result) { try { var context = _listener.EndGetContext(result); if (context.Request.HttpMethod == "GET") { context.Response.StatusCode = 200; context.Response.Headers.Add("Content-Type", "text/plain"); await metrics.Expose(context.Response.OutputStream, ExposeOptions.Default); } else { context.Response.StatusCode = 405; // Method not allowed } context.Response.Close(); } catch (ObjectDisposedException) { // Do not throw exception on shutdown } catch (HttpListenerException ex) { logger.LogWarning(ex, "HTTP problem error while providing metric"); } catch (Exception ex) { logger.LogError(ex, "Unexpected error while providing metric"); } finally { _listener.BeginGetContext(ListenerCallback, _listener); } } }
/// <summary> /// Pushes a metric to the push gateway. /// </summary> /// <param name="metrics">The metric to push.</param> /// <param name="job">The job name used by prometheus, this should be a unique name for the type of service. Must be a valid Prometheus label.</param> public void Push(IExposable metrics, string job) { Validate(metrics, job); // It would be better to have a buffered stream using (var ms = new MemoryStream()) { metrics.Expose(ms, ExposeOptions.NoTimestamp).ConfigureAwait(false).GetAwaiter().GetResult(); ms.Position = 0; var response = client.SendAsync(CreateRequestMessage(metrics, job, ms)).ConfigureAwait(false).GetAwaiter().GetResult(); if (!response.IsSuccessStatusCode) { throw new PushGatewayException($"Error pushing to gateway: {response.StatusCode}: {response.ReasonPhrase}"); } } }
public async Task Invoke(HttpContext context) { var sw = Stopwatch.StartNew(); context.Response.StatusCode = 200; context.Response.Headers["Content-Type"] = "text/plain; version=0.0.4; charset=utf-8"; using (var writer = new StreamWriter(context.Response.Body, PrometheusConventions.PrometheusEncoding, 128, true)) { writer.NewLine = "\n"; await writer.WriteLineAsync("# Exposing Nexogen.Libraries.Metrics.Prometheus\n"); await writer.FlushAsync(); await exposable.Expose(context.Response.Body, ExposeOptions.Default); await writer.WriteLineAsync($"# Elapsed: {sw.ElapsedMilliseconds}ms"); } }
/// <summary> /// Pushes a metric to the push gateway asynchronously . /// </summary> /// <param name="metrics">The metric to push.</param> /// <param name="job">The job name used by prometheus, this should be a unique name for the type of service. Must be a valid Prometheus label.</param> /// <returns>An awaitable Task</returns> public async Task PushAsync(IExposable metrics, string job) { Validate(metrics, job); // It would be better to have a buffered stream using (var ms = new MemoryStream()) { await metrics.Expose(ms, ExposeOptions.NoTimestamp); ms.Position = 0; var response = await client.SendAsync(CreateRequestMessage(metrics, job, ms)); if (!response.IsSuccessStatusCode) { var message = await response.Content.ReadAsStringAsync(); throw new PushGatewayException($"Error pushing to gateway: {response.StatusCode}: {message}"); } } }