chore: initial project import
This commit is contained in:
commit
3fc4e5ca53
347 files changed
+56172
No files matched your search
@@ -0,0 +1,90 @@
|
||||
using System.Text.Json;
|
||||
using Fleet.Core;
|
||||
using Monitor.Protocol;
|
||||
|
||||
namespace Monitor.Measurement;
|
||||
|
||||
/// <summary>Agent 单调时钟(微秒)与 UTC(毫秒)的对应关系:块头里的时钟锚点。</summary>
|
||||
public readonly record struct ClockAnchor(long AgentMonoUs, long UtcMs);
|
||||
|
||||
/// <summary>
|
||||
/// 给合并好的流盖章:生成完整的块头(任务/测试、参数快照、端口、时钟锚点、起止时间)。
|
||||
/// 起止时间由数据本身的时间戳换算得出,而不是取收到列块的时刻,所以不受 Probe 交付延迟的影响。
|
||||
/// </summary>
|
||||
public static class ChunkFinalizer
|
||||
{
|
||||
public const int MaxDurationMs = 600_000;
|
||||
|
||||
public static RawChunk Finalize(
|
||||
KindSpec spec,
|
||||
RawChunk fragment,
|
||||
IReadOnlyList<RawStream> streams,
|
||||
NodeId agent,
|
||||
ClockAnchor anchor,
|
||||
IReadOnlyDictionary<string, JsonElement> resolvedParams,
|
||||
int port,
|
||||
ChunkId id)
|
||||
{
|
||||
RawChunkHeader source = fragment.Header;
|
||||
long offsetUs = source.Clock.ProbeOffsetUs;
|
||||
long min = long.MaxValue;
|
||||
long max = long.MinValue;
|
||||
foreach (RawStream stream in streams)
|
||||
{
|
||||
if (stream.Name == "tcp_info")
|
||||
{
|
||||
continue; // 这个流的时钟取决于 side 列,不参与起止时间的计算
|
||||
}
|
||||
|
||||
foreach (RawColumn column in stream.Columns)
|
||||
{
|
||||
if (column.Role == ColumnRole.None)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < stream.Count; i++)
|
||||
{
|
||||
if (!column.IsValid(i))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
long utc = ToUtcMs(column.Values[i], column.Role, anchor, offsetUs);
|
||||
min = Math.Min(min, utc);
|
||||
max = Math.Max(max, utc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
long start = min == long.MaxValue ? anchor.UtcMs - source.DurationMs : min;
|
||||
int duration = (int)Math.Clamp(Math.Max(source.DurationMs, min == long.MaxValue ? 0 : max - start), 1, MaxDurationMs);
|
||||
|
||||
var header = new RawChunkHeader
|
||||
{
|
||||
ChunkId = id,
|
||||
Kind = spec.Id,
|
||||
TaskId = source.TaskId,
|
||||
TestId = source.TestId,
|
||||
Phase = source.Phase,
|
||||
AgentId = agent,
|
||||
ProbeId = source.ProbeId,
|
||||
Target = null,
|
||||
Params = new Dictionary<string, JsonElement>(resolvedParams),
|
||||
Port = port,
|
||||
Direction = source.Direction,
|
||||
StartUtcMs = start,
|
||||
DurationMs = duration,
|
||||
Partial = false,
|
||||
Clock = new ChunkClock { AgentMonoUs = anchor.AgentMonoUs, UtcMs = anchor.UtcMs, ProbeOffsetUs = offsetUs },
|
||||
};
|
||||
return new RawChunk(header, streams);
|
||||
}
|
||||
|
||||
public static long ToUtcMs(long value, ColumnRole role, ClockAnchor anchor, long probeOffsetUs)
|
||||
{
|
||||
long agentUs = role == ColumnRole.TsProbe ? value + probeOffsetUs : value;
|
||||
long delta = agentUs - anchor.AgentMonoUs;
|
||||
return anchor.UtcMs + (delta >= 0 ? delta / 1000 : -((-delta + 999) / 1000));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user