Added metrics to Webhook API (total events, errors)
This commit is contained in:
parent
a83fdbbe7a
commit
a64e16f681
|
@ -4,16 +4,19 @@
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Wave.Data;
|
using Wave.Data;
|
||||||
using Wave.Data.Api.Mailtrap;
|
using Wave.Data.Api.Mailtrap;
|
||||||
|
using Wave.Utilities.Metrics;
|
||||||
|
|
||||||
namespace Wave.Controllers;
|
namespace Wave.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("/api/[controller]")]
|
[Route("/api/[controller]")]
|
||||||
public class WebhookController(ILogger<WebhookController> logger, ApplicationDbContext context) : ControllerBase {
|
public class WebhookController(ILogger<WebhookController> logger, ApplicationDbContext context, ApiMetrics metrics)
|
||||||
|
: ControllerBase {
|
||||||
[HttpPost("mailtrap/{apiKey}")]
|
[HttpPost("mailtrap/{apiKey}")]
|
||||||
[Authorize("EmailApi", AuthenticationSchemes = "ApiKeyInRoute")]
|
[Authorize("EmailApi", AuthenticationSchemes = "ApiKeyInRoute")]
|
||||||
public async Task<IActionResult> Mailtrap(Webhook webhook, string apiKey) {
|
public async Task<IActionResult> Mailtrap(Webhook webhook, string apiKey) {
|
||||||
foreach (var webhookEvent in webhook.Events) {
|
foreach (var webhookEvent in webhook.Events) {
|
||||||
|
metrics.WebhookEventReceived("Mailtrap", webhookEvent.Type.ToString());
|
||||||
var subscriber = await context.Set<EmailSubscriber>().FirstOrDefaultAsync(s => s.Email == webhookEvent.Email);
|
var subscriber = await context.Set<EmailSubscriber>().FirstOrDefaultAsync(s => s.Email == webhookEvent.Email);
|
||||||
|
|
||||||
logger.LogDebug("Received Webhook event {EventType} for {email}",
|
logger.LogDebug("Received Webhook event {EventType} for {email}",
|
||||||
|
@ -24,6 +27,7 @@ public class WebhookController(ILogger<WebhookController> logger, ApplicationDbC
|
||||||
"Received webhook event from mailtrap of type {EventType}, " +
|
"Received webhook event from mailtrap of type {EventType}, " +
|
||||||
"but failed to find subscriber with E-Mail {email}.",
|
"but failed to find subscriber with E-Mail {email}.",
|
||||||
webhookEvent.Type, webhookEvent.Email);
|
webhookEvent.Type, webhookEvent.Email);
|
||||||
|
metrics.WebhookEventError("Mailtrap", webhookEvent.Type.ToString(), "unknown email");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +63,7 @@ public class WebhookController(ILogger<WebhookController> logger, ApplicationDbC
|
||||||
case WebhookEventType.Click:
|
case WebhookEventType.Click:
|
||||||
default:
|
default:
|
||||||
logger.LogInformation("Received unsupported event {EventType} for {email}. Skipping.", webhookEvent.Type, webhookEvent.Email);
|
logger.LogInformation("Received unsupported event {EventType} for {email}. Skipping.", webhookEvent.Type, webhookEvent.Email);
|
||||||
|
metrics.WebhookEventError("Mailtrap", webhookEvent.Type.ToString(), "unknown type");
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
using Serilog;
|
using Serilog;
|
||||||
using Serilog.Events;
|
using Serilog.Events;
|
||||||
using Serilog.Sinks.Grafana.Loki;
|
using Serilog.Sinks.Grafana.Loki;
|
||||||
|
using Wave.Utilities.Metrics;
|
||||||
|
|
||||||
#region Version Information
|
#region Version Information
|
||||||
|
|
||||||
|
@ -275,7 +276,7 @@
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Open Telemetry
|
#region Open Telemetry & Metrics
|
||||||
|
|
||||||
var features = builder.Configuration.GetSection(nameof(Features)).Get<Features>();
|
var features = builder.Configuration.GetSection(nameof(Features)).Get<Features>();
|
||||||
if (features?.Telemetry is true) {
|
if (features?.Telemetry is true) {
|
||||||
|
@ -292,7 +293,7 @@
|
||||||
.AddMeter("Microsoft.AspNetCore.Http.Connections")
|
.AddMeter("Microsoft.AspNetCore.Http.Connections")
|
||||||
.AddMeter("Microsoft.AspNetCore.Http.Routing")
|
.AddMeter("Microsoft.AspNetCore.Http.Routing")
|
||||||
.AddMeter("Microsoft.AspNetCore.Diagnostics")
|
.AddMeter("Microsoft.AspNetCore.Diagnostics")
|
||||||
|
.AddMeter("Wave.Api")
|
||||||
.AddPrometheusExporter());
|
.AddPrometheusExporter());
|
||||||
|
|
||||||
// Jaeger etc.
|
// Jaeger etc.
|
||||||
|
@ -303,6 +304,8 @@
|
||||||
tracing.AddOtlpExporter(options => options.Endpoint = new Uri(otlpUrl));
|
tracing.AddOtlpExporter(options => options.Endpoint = new Uri(otlpUrl));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
builder.Services.AddSingleton<ApiMetrics>();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
30
Wave/Utilities/Metrics/ApiMetrics.cs
Normal file
30
Wave/Utilities/Metrics/ApiMetrics.cs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
using System.Diagnostics.Metrics;
|
||||||
|
|
||||||
|
namespace Wave.Utilities.Metrics;
|
||||||
|
|
||||||
|
public class ApiMetrics {
|
||||||
|
private Counter<int> WebhookEventCounter { get; }
|
||||||
|
private Counter<int> WebhookErrorCounter { get; }
|
||||||
|
|
||||||
|
public ApiMetrics(IMeterFactory meterFactory) {
|
||||||
|
var meter = meterFactory.Create("Wave.Api");
|
||||||
|
|
||||||
|
WebhookEventCounter = meter.CreateCounter<int>("wave.webhook.events", "{events}",
|
||||||
|
description: "Counts the incoming webhook events");
|
||||||
|
WebhookErrorCounter = meter.CreateCounter<int>("wave.webhook.errors", "{events}",
|
||||||
|
description: "Counts errors in webhook events");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WebhookEventReceived(string api, string type) {
|
||||||
|
WebhookEventCounter.Add(1,
|
||||||
|
new KeyValuePair<string, object?>("wave.webhook.event_type", type),
|
||||||
|
new KeyValuePair<string, object?>("wave.webhook.api", api));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WebhookEventError(string api, string type, string reason) {
|
||||||
|
WebhookErrorCounter.Add(1,
|
||||||
|
new KeyValuePair<string, object?>("wave.webhook.event_type", type),
|
||||||
|
new KeyValuePair<string, object?>("wave.webhook.api", api),
|
||||||
|
new KeyValuePair<string, object?>("wave.error.reason", reason));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue