feat(lmxproxy): add delivered/dropped message counts to subscription stats

Subscription metrics (totalDelivered, totalDropped) now visible in
/api/status JSON and HTML dashboard. Card turns yellow if drops > 0.
Aggregated from per-client counters in SubscriptionManager.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-03-23 00:07:58 -04:00
parent 59d143e4c8
commit 7f74b660b3
4 changed files with 29 additions and 4 deletions

View File

@@ -3,15 +3,20 @@ namespace ZB.MOM.WW.LmxProxy.Host.Domain
/// <summary>Subscription statistics for monitoring.</summary> /// <summary>Subscription statistics for monitoring.</summary>
public class SubscriptionStats public class SubscriptionStats
{ {
public SubscriptionStats(int totalClients, int totalTags, int activeSubscriptions) public SubscriptionStats(int totalClients, int totalTags, int activeSubscriptions,
long totalDelivered = 0, long totalDropped = 0)
{ {
TotalClients = totalClients; TotalClients = totalClients;
TotalTags = totalTags; TotalTags = totalTags;
ActiveSubscriptions = activeSubscriptions; ActiveSubscriptions = activeSubscriptions;
TotalDelivered = totalDelivered;
TotalDropped = totalDropped;
} }
public int TotalClients { get; } public int TotalClients { get; }
public int TotalTags { get; } public int TotalTags { get; }
public int ActiveSubscriptions { get; } public int ActiveSubscriptions { get; }
public long TotalDelivered { get; }
public long TotalDropped { get; }
} }
} }

View File

@@ -28,6 +28,8 @@ namespace ZB.MOM.WW.LmxProxy.Host.Status
public int TotalClients { get; set; } public int TotalClients { get; set; }
public int TotalTags { get; set; } public int TotalTags { get; set; }
public int ActiveSubscriptions { get; set; } public int ActiveSubscriptions { get; set; }
public long TotalDelivered { get; set; }
public long TotalDropped { get; set; }
} }
public class PerformanceStatus public class PerformanceStatus

View File

@@ -96,7 +96,9 @@ namespace ZB.MOM.WW.LmxProxy.Host.Status
{ {
TotalClients = subStats.TotalClients, TotalClients = subStats.TotalClients,
TotalTags = subStats.TotalTags, TotalTags = subStats.TotalTags,
ActiveSubscriptions = subStats.ActiveSubscriptions ActiveSubscriptions = subStats.ActiveSubscriptions,
TotalDelivered = subStats.TotalDelivered,
TotalDropped = subStats.TotalDropped
}; };
// Performance stats // Performance stats
@@ -216,11 +218,17 @@ namespace ZB.MOM.WW.LmxProxy.Host.Status
sb.AppendLine(" </div></div>"); sb.AppendLine(" </div></div>");
// Subscriptions card // Subscriptions card
sb.AppendLine(" <div class=\"grid-item\"><div class=\"card card-green\">"); var subCardCss = statusData.Subscriptions.TotalDropped > 0 ? "card-yellow" : "card-green";
sb.AppendLine($" <div class=\"grid-item\"><div class=\"card {subCardCss}\">");
sb.AppendLine(" <h3>Subscriptions</h3>"); sb.AppendLine(" <h3>Subscriptions</h3>");
sb.AppendLine($" <p><strong>Clients:</strong> {statusData.Subscriptions.TotalClients}</p>"); sb.AppendLine($" <p><strong>Clients:</strong> {statusData.Subscriptions.TotalClients}</p>");
sb.AppendLine($" <p><strong>Tags:</strong> {statusData.Subscriptions.TotalTags}</p>"); sb.AppendLine($" <p><strong>Tags:</strong> {statusData.Subscriptions.TotalTags}</p>");
sb.AppendLine($" <p><strong>Active:</strong> {statusData.Subscriptions.ActiveSubscriptions}</p>"); sb.AppendLine($" <p><strong>Active:</strong> {statusData.Subscriptions.ActiveSubscriptions}</p>");
sb.AppendLine($" <p><strong>Delivered:</strong> {statusData.Subscriptions.TotalDelivered:N0}</p>");
if (statusData.Subscriptions.TotalDropped > 0)
{
sb.AppendLine($" <p style=\"color:red\"><strong>Dropped:</strong> {statusData.Subscriptions.TotalDropped:N0}</p>");
}
sb.AppendLine(" </div></div>"); sb.AppendLine(" </div></div>");
sb.AppendLine(" </div>"); sb.AppendLine(" </div>");

View File

@@ -242,10 +242,20 @@ namespace ZB.MOM.WW.LmxProxy.Host.Subscriptions
/// <summary>Returns subscription statistics.</summary> /// <summary>Returns subscription statistics.</summary>
public SubscriptionStats GetStats() public SubscriptionStats GetStats()
{ {
long totalDelivered = 0;
long totalDropped = 0;
foreach (var kvp in _clientSubscriptions)
{
totalDelivered += kvp.Value.DeliveredCount;
totalDropped += kvp.Value.DroppedCount;
}
return new SubscriptionStats( return new SubscriptionStats(
_clientSubscriptions.Count, _clientSubscriptions.Count,
_tagSubscriptions.Count, _tagSubscriptions.Count,
_clientSubscriptions.Values.Sum(c => c.Addresses.Count)); _clientSubscriptions.Values.Sum(c => c.Addresses.Count),
totalDelivered,
totalDropped);
} }
public void Dispose() public void Dispose()