Register VARZ, HEALTHZ, SUBSZ, STATSZ, and IDZ request-reply handlers
on $SYS.REQ.SERVER.{id}.* subjects and $SYS.REQ.SERVER.PING.* wildcard
subjects via InitEventTracking. Also excludes the $SYS system account
from the /subz monitoring endpoint by default since its subscriptions
are internal infrastructure.
98 lines
3.2 KiB
C#
98 lines
3.2 KiB
C#
using Microsoft.AspNetCore.Http;
|
|
using NATS.Server.Subscriptions;
|
|
|
|
namespace NATS.Server.Monitoring;
|
|
|
|
/// <summary>
|
|
/// Handles /subz endpoint requests, returning subscription information.
|
|
/// Corresponds to Go server/monitor.go handleSubsz.
|
|
/// </summary>
|
|
public sealed class SubszHandler(NatsServer server)
|
|
{
|
|
public Subsz HandleSubsz(HttpContext ctx)
|
|
{
|
|
var opts = ParseQueryParams(ctx);
|
|
var now = DateTime.UtcNow;
|
|
|
|
// Collect subscriptions from all accounts (or filtered).
|
|
// Exclude the $SYS system account unless explicitly requested — its internal
|
|
// subscriptions are infrastructure and not user-facing.
|
|
var allSubs = new List<Subscription>();
|
|
foreach (var account in server.GetAccounts())
|
|
{
|
|
if (!string.IsNullOrEmpty(opts.Account) && account.Name != opts.Account)
|
|
continue;
|
|
if (string.IsNullOrEmpty(opts.Account) && account.Name == "$SYS")
|
|
continue;
|
|
allSubs.AddRange(account.SubList.GetAllSubscriptions());
|
|
}
|
|
|
|
// Filter by test subject if provided
|
|
if (!string.IsNullOrEmpty(opts.Test))
|
|
{
|
|
allSubs = allSubs.Where(s => SubjectMatch.MatchLiteral(opts.Test, s.Subject)).ToList();
|
|
}
|
|
|
|
var total = allSubs.Count;
|
|
var numSubs = server.GetAccounts()
|
|
.Where(a => (string.IsNullOrEmpty(opts.Account) && a.Name != "$SYS") || a.Name == opts.Account)
|
|
.Aggregate(0u, (sum, a) => sum + a.SubList.Count);
|
|
var numCache = server.GetAccounts()
|
|
.Where(a => (string.IsNullOrEmpty(opts.Account) && a.Name != "$SYS") || a.Name == opts.Account)
|
|
.Sum(a => a.SubList.CacheCount);
|
|
|
|
SubDetail[] details = [];
|
|
if (opts.Subscriptions)
|
|
{
|
|
details = allSubs
|
|
.Skip(opts.Offset)
|
|
.Take(opts.Limit)
|
|
.Select(s => new SubDetail
|
|
{
|
|
Subject = s.Subject,
|
|
Queue = s.Queue ?? "",
|
|
Sid = s.Sid,
|
|
Msgs = Interlocked.Read(ref s.MessageCount),
|
|
Max = s.MaxMessages,
|
|
Cid = s.Client?.Id ?? 0,
|
|
})
|
|
.ToArray();
|
|
}
|
|
|
|
return new Subsz
|
|
{
|
|
Id = server.ServerId,
|
|
Now = now,
|
|
NumSubs = numSubs,
|
|
NumCache = numCache,
|
|
Total = total,
|
|
Offset = opts.Offset,
|
|
Limit = opts.Limit,
|
|
Subs = details,
|
|
};
|
|
}
|
|
|
|
private static SubszOptions ParseQueryParams(HttpContext ctx)
|
|
{
|
|
var q = ctx.Request.Query;
|
|
var opts = new SubszOptions();
|
|
|
|
if (q.TryGetValue("subs", out var subs))
|
|
opts.Subscriptions = subs == "true" || subs == "1" || subs == "detail";
|
|
|
|
if (q.TryGetValue("offset", out var offset) && int.TryParse(offset, out var o))
|
|
opts.Offset = o;
|
|
|
|
if (q.TryGetValue("limit", out var limit) && int.TryParse(limit, out var l))
|
|
opts.Limit = l;
|
|
|
|
if (q.TryGetValue("acc", out var acc))
|
|
opts.Account = acc.ToString();
|
|
|
|
if (q.TryGetValue("test", out var test))
|
|
opts.Test = test.ToString();
|
|
|
|
return opts;
|
|
}
|
|
}
|