Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

public sealed class Exporter
{
public string Host { get; set; } = "localhost";
public int Port { get; set; } = 9002;
public string Host { get; set; } = "+";
public ushort Port { get; set; } = 33334;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
WORKDIR /app
EXPOSE 9002
EXPOSE 33334

FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
Expand Down
121 changes: 68 additions & 53 deletions src/ServiceControl_Exporter/ServiceControl_Exporter/Program.cs
Original file line number Diff line number Diff line change
@@ -1,62 +1,77 @@
namespace ServiceControl_Exporter;

using System.Net;
using Commands;
using Config;
using System.Net;
using Flurl.Http;
using Mediator;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Prometheus;
using ServiceControl_Exporter;
using ServiceControl_Exporter.Commands;
using ServiceControl_Exporter.Config;

var builder = Host.CreateApplicationBuilder(args);

builder.Services.AddSingleton(provider => provider.GetRequiredService<IConfiguration>().Get<AppSettings>());
builder.Services.AddSingleton<CollectorDictionary>();
builder.Services.AddHostedService<PrometheusExporter>();
builder.Services.AddMediator();
builder.Logging.AddConsole();

var appSettings = builder.Configuration.Get<AppSettings>();

var registry = Metrics.DefaultRegistry;

var serverOptions = new KestrelMetricServerOptions
{
Registry = registry,
Hostname = appSettings.Exporter.Host,
Port = appSettings.Exporter.Port
};
builder.Services.AddSingleton(serverOptions);

FlurlHttp.Clients.WithDefaults(settings =>
{
settings.ConfigureInnerHandler(handler =>
{
if (!string.IsNullOrWhiteSpace(appSettings.ProxyUrl))
{
handler.Proxy = new WebProxy(new Uri(appSettings.ProxyUrl));
handler.UseProxy = true;
}
});
});

internal class Program
{
public static async Task Main(string[] args)
{
using var host = CreateHostBuilder(args).Build();

var mediator = host.Services.GetRequiredService<IMediator>();

var appSettings = host.Services.GetRequiredService<AppSettings>();

FlurlHttp.Clients.WithDefaults(settings =>
{
settings.ConfigureInnerHandler(handler =>
{
if (!string.IsNullOrWhiteSpace(appSettings.ProxyUrl))
{
handler.Proxy = new WebProxy(new Uri(appSettings.ProxyUrl));
handler.UseProxy = true;
}
});
});

Metrics.DefaultRegistry.AddBeforeCollectCallback(async cancel =>
{
await mediator.Send(new UpdateEndpointStatsMetricsCommand(), cancel).ConfigureAwait(false);
await mediator.Send(new UpdateErrorMetricsCommand(), cancel).ConfigureAwait(false);
await mediator.Send(new UpdateCustomChecksMetricsCommand(), cancel).ConfigureAwait(false);
await mediator.Send(new UpdateHeartBeatStatsMetricsCommand(), cancel).ConfigureAwait(false);
await mediator.Send(new UpdateMonitoringMetricsCommand(), cancel).ConfigureAwait(false);
});

await host.RunAsync();
}

private static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.UseWindowsService()
.UseSystemd()
.ConfigureServices(c =>
var host = builder.Build();

var mediator = host.Services.GetRequiredService<IMediator>();

registry.AddBeforeCollectCallback(async cancel =>
{
try
{
var logger = host.Services.GetRequiredService<ILogger<PrometheusExporter>>();
// If you see this in your container logs, the network route is working
if (logger.IsEnabled(LogLevel.Debug))
logger.Log(LogLevel.Debug, "Kestrel handed execution to AddBeforeCollectCallback.");

await mediator.Send(new UpdateEndpointStatsMetricsCommand(), cancel).ConfigureAwait(false);
await mediator.Send(new UpdateErrorMetricsCommand(), cancel).ConfigureAwait(false);
await mediator.Send(new UpdateCustomChecksMetricsCommand(), cancel).ConfigureAwait(false);
await mediator.Send(new UpdateHeartBeatStatsMetricsCommand(), cancel).ConfigureAwait(false);
await mediator.Send(new UpdateMonitoringMetricsCommand(), cancel).ConfigureAwait(false);

if (logger.IsEnabled(LogLevel.Debug))
logger.Log(LogLevel.Debug, "Callback completed successfully.");
}
catch (Exception ex)
{
c.AddSingleton(provider => provider.GetRequiredService<IConfiguration>().Get<AppSettings>());
c.AddSingleton<CollectorDictionary>();
c.AddHostedService<PrometheusExporter>();
c.AddMediator();
})
.ConfigureLogging(c => c.AddConsole());
}
}
var logger = host.Services.GetRequiredService<ILogger<PrometheusExporter>>();
// Kestrel swallows pipeline faults; this forces it out to your container log stream
if (logger.IsEnabled(LogLevel.Error))
logger.Log(LogLevel.Error, ex, "An error occurred while collecting metrics.");
throw; // Allow prometheus-net to handle the 503 response
}
});

host.Run();
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
namespace ServiceControl_Exporter;

using Config;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Prometheus;

internal class PrometheusExporter(AppSettings configuration) : IHostedService
internal class PrometheusExporter(KestrelMetricServerOptions options, ILogger<PrometheusExporter> logger) : IHostedService
{
private readonly KestrelMetricServer _server = new KestrelMetricServer(configuration.Exporter.Host,
configuration.Exporter.Port);
private readonly KestrelMetricServer _server = new(options);

public Task StartAsync(CancellationToken cancellationToken)
{
logger.LogInformation("Starting Prometheus exporter for {0}:{1}", options.Hostname, options.Port);
_server.Start();
return Task.CompletedTask;
}

public async Task StopAsync(CancellationToken cancellationToken)
{
logger.LogInformation("Stopping Prometheus exporter for {0}:{1}", options.Hostname, options.Port);
await _server.StopAsync();
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"exporter": {
"host": "+",
"port": 9002
"port": 33334
},
"serviceControl": {
"url": "http://localhost:33333/api",
Expand Down