XiHan.Framework.Observability.Host
运行信息的默认实现:单例 IHostMonitor 读进程与所在主机的 CPU、内存、磁盘、网卡、GPU、主板与运行时长,后台采样 CPU 使用率与网卡速率。提供 observability.host@1,供管理界面的服务监控使用。
| 项 | 内容 |
|---|---|
| 包 ID | XiHan.Framework.Observability.Host |
| 环层 | Ring 3(实现) |
| 能力 | 提供 observability.host@1(role: default);依赖 kernel.hosting@1 |
| 特性入口 | HostObservabilityFeature(清单 xihan.observability.host,IHostedFeature) |
| 配置节 | XiHan:Observability:Host |
| 依赖 | XiHan.Framework.Kernel、XiHan.Framework.Observability.Abstractions;Microsoft.Extensions.Logging.Abstractions;没有其他第三方包 |
| AOT | 兼容(系统调用经 LibraryImport 源生成) |
| 稳定性 | Preview |
概述
特性被选中时注册三个单例:按当前操作系统创建的平台读取器、后台采样器与 IHostMonitor。StartAsync 同步采第一次样再起采样循环,StopAsync 结束循环,最近算出的值保留(RFC-0023,ADR-0056)。
读取分两类。静态项(CPU 型号与核心、GPU、主板)首次读取后缓存;动态项(内存、磁盘、网卡、运行时)每次当场读。使用率与速率要两次采样求差,由采样器按间隔计算:
| 量 | 算法 |
|---|---|
| 系统 CPU 使用率 | 1 − 空闲增量 / 总增量 |
| 进程 CPU 使用率 | 进程处理器时间增量 /(经过时间 × 逻辑核心数) |
| 网卡收发速率 | 累计字节增量 / 经过时间 |
计数变小(回绕、网卡重建)或总增量为零时该项为空;百分比限制在 0 到 100,不取整。一次采样失败记一条警告,保留上一次的值,循环继续。
何时使用
管理界面要显示服务器状态、运维脚本要按阈值告警时。指标与链路的导出用 Observability.OpenTelemetry,两者互不依赖。Profiles.Full 已装配本包;不需要运行信息又想省下后台采样时,改用 Profiles.Standard 自行组合。
安装与启用
dotnet add package XiHan.Framework.Observability.Host --prerelease当前是预览版,安装要带 --prerelease;从源码或本地包源引用见快速上手。
using XiHan.Framework.Hosting.AspNetCore;
using XiHan.Framework.Observability.Host;
using XiHan.Framework.Profiles.Standard;
var builder = WebApplication.CreateBuilder(args);
builder.AddXiHan(xihan => xihan
.UseStandardProfile()
.UseFeature<HostObservabilityFeature>());
var app = builder.Build();
app.UseXiHan();
app.Run();配置
| 键 | 类型 | 缺省 | 说明 |
|---|---|---|---|
XiHan:Observability:Host:SampleIntervalSeconds | 数值,(0, 3600] | 5 | 采样间隔(秒),CPU 使用率与网卡速率是相邻两次采样之差 |
{ "XiHan": { "Observability": { "Host": { "SampleIntervalSeconds": 5 } } } }取值越界或不是数值时 HostObservabilityOptions.FromConfiguration 抛出 ArgumentException;上限是 HostObservabilityOptions.MaxSampleInterval(1 小时)。
主要类型
| 类型 | 说明 |
|---|---|
HostObservabilityFeature | 能力包入口;启动时采第一次样并起采样循环 |
HostObservabilityOptions | SampleInterval(缺省 5 秒);ConfigurationSection 为 XiHan:Observability:Host |
IHostMonitor(抽象包) | 七个读取方法,见 Observability.Abstractions |
使用示例
服务监控页的端点见可观测性。在测试里等第一次使用率出来再断言:
using Microsoft.Extensions.DependencyInjection;
using XiHan.Framework.Observability.Abstractions;
using XiHan.Framework.Observability.Host;
using XiHan.Framework.Testing;
public sealed class MonitorTests
{
[Fact]
public async Task CpuUsage_AppearsAfterOneInterval()
{
await using var host = await TestHost.StartAsync(
static b => b.UseFeature<HostObservabilityFeature>(),
[new("XiHan:Observability:Host:SampleIntervalSeconds", "0.1")]);
var monitor = host.Services.GetRequiredService<IHostMonitor>();
// 只有 Linux 与 Windows 读得到系统 CPU 时间
if (OperatingSystem.IsLinux() || OperatingSystem.IsWindows())
{
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10));
while (monitor.ReadProcessor().UsagePercent is null)
{
await Task.Delay(TimeSpan.FromMilliseconds(20), timeout.Token);
}
Assert.InRange(monitor.ReadProcessor().UsagePercent!.Value, 0d, 100d);
}
}
}行为与限制
- 不启动外部命令:只读 BCL、
/proc与/sys、pci.ids、注册表与 kernel32 的GetSystemTimes、GetLogicalProcessorInformation、K32GetPerformanceInfo;不用 WMI、PowerShell、dmidecode、lspci、nvidia-smi、top。 - 读不到的项为
null,列表读不到为空列表;字符串去掉首尾空白后为空也视为读不到。单项失败(权限不足、文件缺失、平台不支持)不影响其他项,读取不抛出、不睡眠、不等待采样。 - 不暴露命令行参数、环境变量与当前目录。
各平台的读取来源:
| 项 | Linux | Windows | 其他(macOS 等) |
|---|---|---|---|
| CPU 型号、厂商 | /proc/cpuinfo 的 model name(没有时取 Hardware)、vendor_id | 注册表 HKLM\HARDWARE\DESCRIPTION\System\CentralProcessor\0 的 ProcessorNameString、VendorIdentifier | 空 |
| 物理核心、最后一级缓存 | /sys/devices/system/cpu/cpu<N>/topology/ 与 cpu0/cache/index<N>/ | GetLogicalProcessorInformation | 空 |
| 标称频率 | cpu0/cpufreq/base_frequency,没有时取 cpuinfo_max_freq | 注册表 ~MHz | 空 |
| CPU 使用率 | /proc/stat 首行 | GetSystemTimes | 空 |
| 内存 | /proc/meminfo 的 MemTotal、MemAvailable、MemFree、Buffers + Cached | K32GetPerformanceInfo(空闲为空) | 空 |
| 系统运行时长 | /proc/uptime | Environment.TickCount64 | Environment.TickCount64 |
| 磁盘 | /proc/self/mounts 里以 /dev/ 开头、不是 /dev/loop 的设备,每个设备取第一个挂载点,容量取 DriveInfo | DriveInfo 里就绪的固定、可移动与网络盘 | 同 Windows |
| 网卡 | NetworkInterface,平台不支持的属性为空 | 同左 | 同左 |
| GPU | /sys/class/drm/card<N>/device,名称与厂商名查 pci.ids(/usr/share/hwdata、/usr/share/misc、/usr/share) | 注册表显示适配器类 {4d36e968-e325-11ce-bfc1-08002be10318} 下 MatchingDeviceId 以 pci 开头的子键 | 空列表 |
| 主板 | /sys/class/dmi/id/ 的 board_*、sys_vendor、product_name、bios_* | 注册表 HKLM\HARDWARE\DESCRIPTION\System\BIOS(没有序列号) | 空 |
已知的取舍:没有 NVIDIA 专有驱动的显存与温度、GPU 与显存使用率;Windows 没有 GPU 温度与主板序列号、没有空闲内存;Linux 的 board_serial 只有 root 读得到;容器里的内存与 CPU 使用率是宿主机的数值,不是 cgroup 限额,逻辑核心数是 .NET 看到的可用核心数。完整的取舍列在 RFC-0023。
相关
- 可观测性
- Observability.Abstractions
- Observability.OpenTelemetry
- Profiles.Full
- 规范:RFC-0023《可观测性:导出与运行信息》
