Files
MoShiro/backend/fleet/tests/Fleet.Tests/BufferedNodeLogTests.cs
T
justme fb3a9c260f fleet: send log counters in heartbeats and pull the text on demand
Heartbeats carry per-level counts, the most frequent log types (a stable hash of the message) and the newest id, no text. The node keeps its last 2048 lines; moshiro.logs.fetch lets the backend pull them. The log page pulls when it is open, and the backend pulls warnings and errors once a minute after a node reports an error.
2026-10-22 05:28:29 +08:00

66 lines
2.3 KiB
C#

using Fleet.Core;
using Fleet.Hosting;
namespace Fleet.Tests;
public sealed class BufferedNodeLogTests
{
[Fact]
public void Summary_CountsByLevelAndTypeWithoutText_AndResetsAfterEachTake()
{
var log = new BufferedNodeLog(NullNodeLog.Instance, TimeProvider.System);
for (int i = 0; i < 5; i++)
{
log.Warn("peer control handshake failed", ("attempt", i));
}
log.Info("link up");
log.Error("MsQuic QUIC transport shutdown");
NodeLogSummary first = log.TakeSummary();
Assert.Equal((1L, 5L, 1L), (first.Info, first.Warn, first.Error));
Assert.Equal(7, first.LastId);
NodeLogTypeCount top = first.Types[0];
Assert.Equal((BufferedNodeLog.TypeOf("peer control handshake failed"), "warn", 5L), (top.Type, top.Level, top.Count));
NodeLogSummary second = log.TakeSummary();
Assert.Equal((0L, 0L, 0L), (second.Info, second.Warn, second.Error));
Assert.Empty(second.Types);
Assert.Equal(7, second.LastId);
}
[Fact]
public void Read_ReturnsLinesAfterAnIdAtOrAboveALevel_OldestFirst_AndTheRingKeepsTheNewest()
{
var log = new BufferedNodeLog(NullNodeLog.Instance, TimeProvider.System);
log.Info("one");
log.Warn("two");
log.Error("three");
log.Info("four");
Assert.Equal(["two", "three"], log.Read(1, 2, null).Items.Select(e => e.Record.Message));
Assert.Equal(["three"], log.Read(0, 10, "error").Items.Select(e => e.Record.Message));
Assert.Equal(["two", "three"], log.Read(0, 10, "warn").Items.Select(e => e.Record.Message));
for (int i = 0; i < 3000; i++)
{
log.Info("filler", ("n", i));
}
NodeLogPage page = log.Read(0, 200, null);
Assert.Equal(200, page.Items.Count);
Assert.True(page.Items[0].Id > 4); // 最早的几条已经被环挤掉
Assert.Equal(3004, page.LastId);
}
[Fact]
public void SensitiveFieldsAreRedacted()
{
var log = new BufferedNodeLog(NullNodeLog.Instance, TimeProvider.System);
log.Info("auth", ("token", "abc"), ("agent", "agt_x"));
NodeLogEntry entry = Assert.Single(log.Read(0, 10, null).Items);
Assert.Equal("[redacted]", entry.Record.Fields["token"]);
Assert.Equal("agt_x", entry.Record.Fields["agent"]);
}
}