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.
This commit is contained in:
1 parent
4c31a4a79e
commit
fb3a9c260f
17 files changed
+482
-110
No files matched your search
@@ -19,6 +19,7 @@ public static class MoShiroMethodTable
|
||||
MethodSpec.Request(MoShiroMethods.TestRun, RpcSide.Server),
|
||||
MethodSpec.Request(MoShiroMethods.TestCancel, RpcSide.Server),
|
||||
MethodSpec.Request(MoShiroMethods.DialerDisconnect, RpcSide.Server),
|
||||
MethodSpec.Request(MoShiroMethods.LogsFetch, RpcSide.Server),
|
||||
MethodSpec.Notification(MoShiroMethods.LinkRetry, RpcSide.Server),
|
||||
MethodSpec.Notification(MoShiroMethods.UpdateOffer, RpcSide.Server),
|
||||
MethodSpec.Notification(MoShiroMethods.UpdateApply, RpcSide.Server),
|
||||
|
||||
@@ -17,6 +17,7 @@ public static class MoShiroMethods
|
||||
public const string UpdateOffer = "moshiro.update.offer";
|
||||
public const string UpdateApply = "moshiro.update.apply";
|
||||
public const string Schedule = "moshiro.schedule";
|
||||
public const string LogsFetch = "moshiro.logs.fetch";
|
||||
|
||||
// 拨号方 ↔ 监听方(点对点会话)
|
||||
public const string Clock = "moshiro.clock";
|
||||
@@ -338,11 +339,84 @@ public sealed class NodeHeartbeatExtra
|
||||
[JsonPropertyName("update")]
|
||||
public UpdateStatus? Update { get; set; }
|
||||
|
||||
[JsonPropertyName("runtime_logs")]
|
||||
public List<NodeLogRecord>? RuntimeLogs { get; set; }
|
||||
/// <summary>日志只报计数(不带文本):自上次心跳以来各级别的条数、最多几个出现最多的类型,以及最新一条的编号;文本由 Backend 用 <c>moshiro.logs.fetch</c> 按需拉取。</summary>
|
||||
[JsonPropertyName("log_summary")]
|
||||
public LogSummaryDto? LogSummary { get; set; }
|
||||
}
|
||||
|
||||
[JsonPropertyName("dropped_runtime_logs")]
|
||||
public long? DroppedRuntimeLogs { get; set; }
|
||||
/// <summary>某一类日志(消息文本的稳定哈希)在一个级别上出现了多少次。</summary>
|
||||
public sealed class LogTypeCountDto
|
||||
{
|
||||
[JsonPropertyName("type")]
|
||||
public uint Type { get; set; }
|
||||
|
||||
[JsonPropertyName("level")]
|
||||
public string Level { get; set; } = "info";
|
||||
|
||||
[JsonPropertyName("count")]
|
||||
public long Count { get; set; }
|
||||
}
|
||||
|
||||
public sealed class LogSummaryDto
|
||||
{
|
||||
[JsonPropertyName("last_id")]
|
||||
public long LastId { get; set; }
|
||||
|
||||
[JsonPropertyName("info")]
|
||||
public long Info { get; set; }
|
||||
|
||||
[JsonPropertyName("warn")]
|
||||
public long Warn { get; set; }
|
||||
|
||||
[JsonPropertyName("error")]
|
||||
public long Error { get; set; }
|
||||
|
||||
[JsonPropertyName("types")]
|
||||
public List<LogTypeCountDto> Types { get; set; } = [];
|
||||
}
|
||||
|
||||
/// <summary>Backend → 节点:拉取编号大于 <c>after_id</c> 的日志(最旧的在前),级别不低于 <c>min_level</c>。</summary>
|
||||
public sealed class LogsFetchParams
|
||||
{
|
||||
[JsonPropertyName("after_id")]
|
||||
public long AfterId { get; set; }
|
||||
|
||||
[JsonPropertyName("limit")]
|
||||
public int Limit { get; set; } = 100;
|
||||
|
||||
[JsonPropertyName("min_level")]
|
||||
public string? MinLevel { get; set; }
|
||||
}
|
||||
|
||||
public sealed class LogEntryDto
|
||||
{
|
||||
[JsonPropertyName("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonPropertyName("type")]
|
||||
public uint Type { get; set; }
|
||||
|
||||
[JsonPropertyName("at_utc_ms")]
|
||||
public long AtUtcMs { get; set; }
|
||||
|
||||
[JsonPropertyName("level")]
|
||||
public string Level { get; set; } = "info";
|
||||
|
||||
[JsonPropertyName("message")]
|
||||
public string Message { get; set; } = "";
|
||||
|
||||
[JsonPropertyName("fields")]
|
||||
public Dictionary<string, string> Fields { get; set; } = [];
|
||||
}
|
||||
|
||||
public sealed class LogsFetchResult
|
||||
{
|
||||
[JsonPropertyName("items")]
|
||||
public List<LogEntryDto> Items { get; set; } = [];
|
||||
|
||||
/// <summary>节点上最新一条的编号:比 <c>after_id</c> 小说明节点重启过,编号从头开始。</summary>
|
||||
[JsonPropertyName("last_id")]
|
||||
public long LastId { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -749,6 +823,9 @@ public static class FragmentKeys
|
||||
[JsonSerializable(typeof(DialTargets))]
|
||||
[JsonSerializable(typeof(UpdateOfferParams))]
|
||||
[JsonSerializable(typeof(ScheduleParams))]
|
||||
[JsonSerializable(typeof(LogsFetchParams))]
|
||||
[JsonSerializable(typeof(LogsFetchResult))]
|
||||
[JsonSerializable(typeof(LogSummaryDto))]
|
||||
[JsonSerializable(typeof(UpdateStatus))]
|
||||
[JsonSerializable(typeof(NodeHeartbeatExtra))]
|
||||
[JsonSerializable(typeof(NodeHelloMeta))]
|
||||
|
||||
Reference in new issue
Block a user