feat(batch4-task3): implement error and rate-limit logging helpers

This commit is contained in:
Joseph Doherty
2026-02-28 08:01:04 -05:00
parent b79e7aafe9
commit b79b5f6222
3 changed files with 147 additions and 0 deletions

View File

@@ -220,6 +220,76 @@ public class ServerLoggerTests
content.ShouldContain("message-after-reopen");
}
[Fact]
public void ErrorsVariants_ShouldUseExpectedFormatting()
{
var (server, err) = NatsServer.NewServer(new ServerOptions());
err.ShouldBeNull();
server.ShouldNotBeNull();
var setLogger = GetRequiredServerMethod("SetLogger", typeof(INatsLogger), typeof(bool), typeof(bool));
var errors = GetRequiredServerMethod("Errors", typeof(object), typeof(Exception));
var errorc = GetRequiredServerMethod("Errorc", typeof(string), typeof(Exception));
var errorsc = GetRequiredServerMethod("Errorsc", typeof(object), typeof(string), typeof(Exception));
var logger = new CapturingLogger();
setLogger.Invoke(server, [logger, false, false]);
var wrapped = ErrorContextHelper.NewErrorCtx(new Exception("connection reset"), "leaf reconnect");
errors.Invoke(server, ["client", wrapped]);
errorc.Invoke(server, ["tls", wrapped]);
errorsc.Invoke(server, ["route", "cluster", wrapped]);
logger.Messages.Count.ShouldBe(3);
logger.Messages[0].ShouldContain("client - connection reset: leaf reconnect");
logger.Messages[1].ShouldContain("tls: connection reset: leaf reconnect");
logger.Messages[2].ShouldContain("route - cluster: connection reset: leaf reconnect");
}
[Fact]
public void RateLimitHelpers_ShouldRespectDedupeSemanticsAndDebugFlag()
{
var (server, err) = NatsServer.NewServer(new ServerOptions());
err.ShouldBeNull();
server.ShouldNotBeNull();
var setLogger = GetRequiredServerMethod("SetLogger", typeof(INatsLogger), typeof(bool), typeof(bool));
var rateLimitFormatWarnf = GetRequiredServerMethod("RateLimitFormatWarnf", typeof(string), typeof(object[]));
var rateLimitWarnf = GetRequiredServerMethod("RateLimitWarnf", typeof(string), typeof(object[]));
var rateLimitDebugf = GetRequiredServerMethod("RateLimitDebugf", typeof(string), typeof(object[]));
var logger = new CapturingLogger();
setLogger.Invoke(server, [logger, false, false]);
// Dedupe by format string (same format, different args => single warning).
rateLimitFormatWarnf.Invoke(server, ["format {0}", new object[] { "one" }]);
rateLimitFormatWarnf.Invoke(server, ["format {0}", new object[] { "two" }]);
rateLimitFormatWarnf.Invoke(server, ["other {0}", new object[] { "three" }]);
logger.Messages.Count.ShouldBe(2);
logger.Messages.ShouldContain("format one");
logger.Messages.ShouldContain("other three");
// Dedupe by rendered statement.
logger.Messages.Clear();
rateLimitWarnf.Invoke(server, ["warn {0}", new object[] { "same" }]);
rateLimitWarnf.Invoke(server, ["warn {0}", new object[] { "same" }]);
rateLimitWarnf.Invoke(server, ["warn {0}", new object[] { "other" }]);
logger.Messages.Count.ShouldBe(2);
logger.Messages.ShouldContain("warn same");
logger.Messages.ShouldContain("warn other");
// Debug dedupe + debug-flag gating.
logger.Messages.Clear();
rateLimitDebugf.Invoke(server, ["debug {0}", new object[] { "suppressed" }]);
logger.Messages.ShouldBeEmpty();
setLogger.Invoke(server, [logger, true, false]);
rateLimitDebugf.Invoke(server, ["debug {0}", new object[] { "visible" }]);
rateLimitDebugf.Invoke(server, ["debug {0}", new object[] { "visible" }]);
logger.Messages.Count.ShouldBe(1);
logger.Messages[0].ShouldContain("debug visible");
}
private static int GetPrivateIntField(object target, string fieldName)
{
var field = target.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);