诊断组件(Aegis.Diagnostics)
Aegis.Diagnostics 给每个应用实例装一个自查页面:浏览器打开 /diag,这个进程连了哪些依赖、健不健康、加载了哪些组件、配置实际生效值是什么,一个页面看全。同一个端点带 ?probe=live / ?probe=ready 两个 Kubernetes 探针。分工上,指标趋势归 Prometheus 指标监控,跨服务调用链归 OpenTelemetry 链路追踪,诊断组件回答的是"这个实例此刻的自查",排查通常从它开始。快照只有当前态,不落库,历史回看不归它管。
组件概览
| 字段 | 说明 |
|---|---|
| 组件名称 | 诊断组件 |
| 真实类库 | Aegis.Diagnostics |
| 最新版本 | 3.1.4-preview4 |
| 组件定位 | 实例自查页面 + 周期健康巡检 + k8s 探针端点 |
| 引入方式 | 安装 NuGet,在 Component.deps.json 的 Load 清单中声明 Diagnostics |
| 主要配置 | Aegis:Diagnostics |
| 核心能力 | /diag 自查页面、健康矩阵、组件台账、配置脱敏分块、live / ready 探针、信息段 / 表格 / 健康检查 / 健康探针 / 网络诊断五接口 |
| 典型配套 | Prometheus 指标监控、OpenTelemetry 链路追踪 |
添加诊断组件
第一步:安装 NuGet 包
dotnet add package Aegis.Diagnostics
第二步:在 Component.deps.json 中声明
Diagnostics 既要注册服务也要挂载页面端点,写进 Load 清单一份即可;服务、中间件两个阶段漏掉哪个,页面都是 404:
{
"Components": {
"Load": [
"Diagnostics"
]
}
}
诊断组件的装配位置由框架排定:默认沉底带,在认证、授权之后(顺序规则见Component.deps.json 组件清单),/diag 的登录保护在认证之后的管线上生效。
第三步:启动后打开 /diag
浏览器访问 http://localhost:5000/diag,配置全部可省,页面能打开就是生效了。第一屏的样子见图 1。
图 1:/diag 第一屏。从上到下:顶部单实例提示横幅、实例摘要条(pod 名、uptime、运行模式、GC 模式,配置日志平台后多一个跳转入口)、健康矩阵(一行一个检查项)、Tab 栏(诊断 / 文件 / 有表格数据的分组各占一个)。
看图 1 时注意两点:顶部横幅提醒你看到的是单个实例的数据,经负载均衡访问会随机命中副本,精确排查用 kubectl port-forward 直连目标 pod;页脚有 trace id(点击复制),拿它去日志或链路系统对齐这一次请求。诊断 Tab 之外还有文件 Tab(工作目录层级),激活时自动暂停诊断轮询,切回即恢复。
添加完成的验收清单:
- 摘要条的 pod 名、uptime、运行模式正确
- 装配了 Redis / 数据库 / 认证组件的项目,健康矩阵自动出现对应检查项
- 引用了 Broker 包的项目,Tab 栏自动出现"契约"Tab
- 组件台账里
Diagnostics一行的 Service / Middleware 两列都是成功 - 配置块里有
appsettings.json的 JSON 视图,密码类字段是指纹形态 curl http://localhost:5000/diag?probe=live返回alive
给 Kubernetes 配探针
| 端点 | 返回 | 用途 |
|---|---|---|
/diag?probe=live | 恒 200,正文 alive | liveness:进程能响应即活,不触碰任何依赖 |
/diag?probe=ready | 200 或 503 | readiness:聚合影响流量的检查项与组件加载结果 |
livenessProbe:
httpGet: { path: /diag?probe=live, port: 5000 }
readinessProbe:
httpGet: { path: /diag?probe=ready, port: 5000 }
ready 只读巡检快照和注册台账,不做现场探测,响应 O(1),探针打多少次都不会压到依赖。返回 503 时正文只有两种:not-ready: 存在影响流量的检查项不健康,或 not-ready: 存在组件加载失败,先看正文再上页面。
配置项说明(Aegis:Diagnostics)
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Path | string | /diag | 诊断端点路径 |
Enabled | bool | true | 总开关,关闭后组件整体跳过 |
RequireAuthorization | bool | false | 要求请求已认证,未认证返回 401 |
ConfigSectionEnabled | bool | true | 配置生效值段独立开关,谨慎环境可整段关 |
FileTreeEnabled | bool | true | 文件树开关,关闭后 ?format=files 返回 404 |
EnvVarWhitelistPrefixes | string[] | ASPNETCORE_、DOTNET_ | 环境变量段白名单前缀,只展示命中的变量 |
ProbeCacheSeconds | int | 10 | 一键诊断结果缓存窗(秒):诊断完成后这段时间内的重复请求直接回缓存结果,防 F5 连点放大探测。0 = 不缓存(同目标并发仍只有第一个真正执行)。周期巡检走快照,与此值无关 |
LogPlatform | 配置节 | 无 | 日志平台跳转配置,见下表 |
LogPlatform 子节点:
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Type | string | VictoriaLogs | 平台类型,当前仅支持 VictoriaLogs,其他值预留扩展 |
BaseUrl | string | 空 | vmui 基础地址(多租户 /select/ 租户 ID /vmui/ 路径同样适用),为空时不显示入口 |
DefaultQuery | string | * | 跳转时预填并自动执行的 LogsQL 查询 |
RelativeTime | string | last_24_hours | 跳转时间范围,取 vmui 相对时间格式 |
Enabled 默认 true,按内网最小公分母可用的口径设计。对外网暴露的服务要么显式关掉,要么配 RequireAuthorization=true(要求已装配认证组件,否则一开就全 401)。页面是零外链单文件 HTML,CSP 收死外联出口,内网直接打开不会请求任何外部资源。
用 /diag 排查问题
先明确数据口径:健康矩阵是 15 秒周期巡检的快照,打开页面不触发探测,看到的是最近一轮巡检结果;要做现场探测,用信息段卡片上的"一键诊断"(见下)。
依赖挂没挂:健康矩阵
一行一个检查项:状态、严重度、最近成功时间、连续失败次数、失败原因、健康详情。失败的样子见图 2。
图 2:健康矩阵。红框行是失败项——失败原因(这里是超时)和连续失败次数直接写在行内,不用翻日志。
排查时看四个东西:
- 失败原因:行内直接给出异常消息(如
The operation has timed out.),通常一句话就能定位是网络不通、认证失败还是超时 - 连续失败次数 / 最近成功:区分"刚断"和"断了很久";最近成功为"从未"说明启动起就没通过,多半是配置错
- 严重度:影响流量的项不健康 → ready 探针 503 → 摘流量;提示级(如 SSO 端点)只标红不影响流量
- 健康详情:部分检查项附带关键事实,如 Redis 哨兵行会给出当前推举的 master
矩阵里检查项的名字与信息段同名对齐(如 Redis · 缓存集群):矩阵行标红后,到页面下方同名信息段卡片看连接详情——IP、端口、库名、连接池状态。
现场探测:一键诊断
巡检只告诉你是红是绿,"一键诊断"做分层现场探测。哪些段有这个入口由后端给的目标清单决定:/diag 的数据里带一份可诊断目标名单(组件注册的 INetworkDiagnosticsProvider 的目标名,加上 Broker 契约这类运行时增删的动态目标),段名命中名单就在段头右端渲染"一键诊断 ›"。数据库、Redis、文件存储(Local / NAS / S3 / WebDav 四个后端)的段都有;以后任何组件注册了 INetworkDiagnosticsProvider,按钮自动出现,不用改前端。步骤链按目标类型组:数据库是 连接串 → DNS → ICMP → TCP → SELECT 1,Redis 走到 PING,S3 是 Endpoint 解析 → … → 应用层 HeadBucket。结果以步骤条展开在卡片内(图 3),卡在哪一步一目了然——DNS 解析失败和 TCP 不通是两种完全不同的修法。
图 3:一键诊断。点击段头"一键诊断 ›"后,卡片内步骤条逐层给出每步结果与耗时,绿点为通过;结果持久到页面生命周期,自动刷新不丢。
分层探测遇慢故障时前端 120 秒超时并提示结合后端日志定位。
同一目标只执行一次:单飞与短缓存
同一个目标连点几次、多个人同时点、F5 刷新后再点,都只执行一次。后端对每个诊断目标做并发协调,这个机制叫单飞(single-flight):同一目标同时来多个请求,只有第一个真正执行,其余请求不重复跑。对全部诊断目标生效,包括数据库、Redis、文件存储四后端,以及 Broker 契约这类运行时登记的动态目标。
?diagnose= 端点的响应因此分三种状态,HTTP 一律 200,永远不会 429:
status | 什么时候返回 | 响应内容 |
|---|---|---|
completed | 本次请求自己发起并执行了诊断 | steps 步骤列表 |
processing | 另一个请求正在执行同一目标,本请求不等待不排队 | elapsedMs(对方已执行毫秒数) |
cached | 上一次诊断完成后还没超过缓存窗 | completedAt(完成时刻)+ steps |
缓存窗(上一次诊断完成后结果保留的时长)由 Aegis:Diagnostics:ProbeCacheSeconds 控制,默认 10 秒,设 0 关闭缓存。关了缓存单飞仍在:同目标并发还是只有第一个执行。这样执行频率有硬上界:1 / max(单次执行耗时, 缓存窗)。执行失败的请求返回 500(error 字段),失败结果不进缓存,下一个请求重新执行。脚本化调用要按 status 分支,不能假设响应里直接就是步骤列表。
服务端对单次诊断另有 15 秒超时。到点返回 504,但诊断任务不被取消,交给后台收尾:成功照样写进缓存,失败清掉执行占位(占位是协调器里"该目标正有人在执行"的记录)。所以遇到挂死的目标(比如 TCP 一直不通),15 秒后端点回 504,再点会看到"正在处理中"。这不是页面卡住,是那一次诊断确实还没跑完。完成或失败后占位即清,不会永久停在"处理中"。
页面对这两种状态的展示:processing 时结果区显示一条"正在处理中"步骤,附说明"另一请求正在执行本目标的诊断(已 X.X 秒)",页面 5 秒自动刷新会带出结果;cached 时正常渲染步骤条,上方标注"诊断于 HH:mm:ss",这个时间是后端完成时刻,不是本次点击的时刻。
配置生效没生效:配置分块
页面下方每个配置来源一块(appsettings.json、appsettings.Development.json、Component.deps.json、配置中心……)。两个排查用法:
- 查覆盖:文件视图语义——被覆盖的键仍出现在所属文件块里,对照相邻块就能看出"谁覆盖了谁",配置中心的值有没有压过本地文件一眼可辨
- 查内容:JSON 来源渲染为高亮 JSON 视图(容忍 .NET 配置的注释/尾逗号形态),支持全屏;密码类字段是指纹形态(只留尾 4 位和长度,见图 4 红底行),结构信息 host / database / port 都在,不影响判断连的哪儿
图 4:配置卡的 JSON 视图。红底行是脱敏指纹——看不出原值,但键名、结构和尾 4 位足够对比排错。
组件加载到哪一步:组件台账
一个组件一行,Service / Middleware 两个阶段列各自的装配结果、耗时和消息(图 5)。"服务起不来""某组件功能没生效"时先来这里:哪一行红了,失败消息就在行内;版本号也在表里,多实例版本不一致时用于核对。
图 5:组件台账。Service / Middleware 两列各自的成败与耗时,失败消息直接在行内。
下游契约连通吗:契约 Tab
引用 Broker 包的项目自动出现"契约"Tab,契约连通性总表一行一个契约(图 6)。注意连通状态是被动口径:不主动探测,只记录真实调用留下的结果。"未请求"表示契约已创建但还没有流量,不是故障。
图 6:契约连通性总表。连通状态、最近调用、熔断状态、连续失败并排看;行尾"诊断"按钮对单个契约做现场探测。
契约行尾有"诊断 ›"按钮,对单个契约发起现场探测(只对配了基地址的契约提供);契约列可展开方法明细。SOAP 契约只登记通道创建,不参与连通统计。代码里按需探测用 BrokerEndpointRegistry.ProbeAsync。
表格的两条通用渲染规则:判定徽标与导出 JSON
有两条渲染规则对所有表格 provider 通用,不绑定某个组件:
- "判定"列彩色徽标:任何表格的"判定"列,值命中词表就渲染成彩色徽标:
不一致/列名不符红、提示/表不存在/列不存在黄、匹配绿、未验证/未比对灰。词表外的值按普通文本显示。目前的主要使用方是库表校验比对表(见下),其他表格组件输出同名同值的判定列同样享受着色。3.1.4-preview5 起库表校验的组级徽标分层:红(不一致/列名不符)> 黄(提示)> 绿,灰级不拖累组色——绿+灰的组仍亮绿并计数,只有红灯才让组变红;组序同层 - "库表校验"Tab 卡头的导出 JSON:「库表校验」Tab 里每张比对表卡的卡头有"导出 JSON ›"动作(与"校验 ›"并排)。点击走
?schemacompare=库表校验结构化导出端点(聚合IDiagnosticsExportProvider的自报载荷,按 ExportKind 去重),下载aegis-库表校验-日期时间.json——结构化字段(按表分组的比对列、缺表实体带全列声明、给 AI 的语义说明),可直接交给 AI 生成建表/迁移脚本或喂给迁移工具;不是页面表格的字符串形态
库表校验的数据来自 FreeSql 数据访问的实体结构校验(用法与判定语义见库表校验手册):在"库表校验"Tab 点某张比对表卡头的"校验",比对表随之更新(实体分组左右对照布局),导出的就是这次校验的全量比对行(含全部数据源的表)。"诊断"Tab 的对应段只留跳转链接。
实例被摘流量了:先看 503 正文
/diag?probe=ready 返回 503 只有两种来源,正文会指明:影响流量的检查项不健康(去健康矩阵找红行),或组件加载失败(去组件台账找红行)。定位路径就这两条。
没有浏览器:curl
服务器上没有浏览器时,同一端点的纯文本与 JSON 输出与页面同源:
# 健康检查段(CJK 对齐的定宽文本表,grep 友好)
curl -s "http://localhost:5000/diag?format=text" | grep -A 3 "健康检查"
# 探针状态一行确认
curl -s "http://localhost:5000/diag?probe=ready"; echo
# 机器可读全量(camelCase,sections 与 tables 两个数据节,脚本消费)
curl -s "http://localhost:5000/diag?format=json" | jq '.health'
# 现场网络诊断(与页面"一键诊断"同一入口,目标名要与可诊断名单一致;
# 响应带 status 三态:completed 本次执行 / processing 另一请求在执行 / cached 缓存窗内)
curl -s -G "http://localhost:5000/diag" --data-urlencode "diagnose=文件存储 · S3" | jq
继续深挖:trace id 与日志平台
页脚 trace id 点击复制,拿去 UMeta 结构化日志或链路系统对齐请求。配置 Aegis:Diagnostics:LogPlatform 后摘要条出现"日志平台"入口,点击新窗口打开 VictoriaLogs 的 vmui,查询语句和时间范围已预填并自动执行——从"这个实例有问题"到"看它的日志"一次点击。
装配组件后页面上会多什么
内置检查项与信息段,装配即出现,无需配置:
| 组件 | 健康矩阵检查项 | 信息段 / 表格 |
|---|---|---|
| FreeSql 数据访问 | 数据库 · 数据源名(SELECT 1 探测,5 秒超时,影响流量) | IP、数据库类型、库名、连接池统计;3.1.4-preview3 起另有「库表校验 · 数据源名」段(入口在「库表校验」Tab,见库表校验手册) |
| Redis 缓存 | Redis · 数据源名(standalone 或 哨兵)(PING 探测;哨兵附带当前 master) | 模式、端点、master 名、RunId、连接状态 |
| SSO 认证 | SSO 认证端点(提示级:SSO 不通影响新登录,不影响存量流量) | 无 |
| ESS 认证鉴权 | ESS 认证服务(在线实时校验开启时影响流量,本地验签仅提示) | 无 |
| 远程调用客户端 | 无(被动口径,不做周期探测) | "契约"Tab 总表 + Broker · 资源与开关 段 |
| 文件管理器后端(Local / NAS / S3 / WebDav) | 文件存储 · X(5 秒超时,影响流量:存储不可用即摘流量) | 类型、Endpoint / 根路径、认证账号(SecretKey 与密码不入段),段头带一键诊断入口 |
对照这张表可以反向排查:装配了某组件但矩阵里没有对应检查项,说明该组件压根没加载成功,回到组件台账看。
业务组件往页面上加内容:五个接口
业务组件可以把自己的健康项和信息搬上这个页面,实现五个接口之一即可,都定义在 Aegis.Component 包的 Aegis.Component.Diagnostics 命名空间(引用任意 Aegis 组件都会传递带入)。示例省略 using,需要引入的只有 Aegis.Component.Diagnostics。
| 接口 | 用途 | 发现方式 |
|---|---|---|
IDiagnosticsSectionProvider | 信息段("是什么":连接信息、计数、开关状态) | 中间件装配期反射扫描,构造支持注入 |
IDiagnosticsTableProvider | 表格("横向对比":N 行固定列,列级 Sensitive 标记,按 Group 生成独立 Tab) | 同上 |
IHealthProbe | 探针(简单连通性,HealthProbeResult 带失败原因 / 健康详情) | 由提供依赖的注册处登记 DI(Redis / FreeSql / SSO / ESS 已内置) |
IHealthChecker | 检查器(失败计数 + Unhealth / Fatal 回调,可接告警) | 无参构造自动扫描;带参构造由所在组件显式注册 |
INetworkDiagnosticsProvider | 网络诊断("通不通":分层现场探测,挂成信息段段头的一键诊断入口) | 由提供依赖的注册处登记 DI(数据库 / Redis / 文件存储四后端已内置) |
信息段 IDiagnosticsSectionProvider
public class OrderDiagnosticsProvider : IDiagnosticsSectionProvider
{
public int Order => 100; // 展示顺序小的在前:内置段占 0-99,业务组件默认 100
public IEnumerable<DiagnosticsSection> BuildSections()
{
yield return new DiagnosticsSection
{
Name = "订单 · 主数据源",
Group = "Order",
Provider = "Aegis.Webapi.Demo",
Entries = new List<DiagnosticsEntry>
{
new() { Key = "最近同步", Value = "2026-09-15 08:00:03", Source = "内存计数" },
// 声明敏感即强制指纹化,页面显示尾 4 位加长度
new() { Key = "对接密钥", Value = "9f3e2a1b-secure-partner-key", Sensitive = true }
}
};
}
}
一个 provider 可以返回多段。BuildSections 必须廉价:只读现成状态,不做探测和重 IO——探测归健康检查接口或一键诊断。
表格 IDiagnosticsTableProvider
public class QuotaDiagnosticsProvider : IDiagnosticsTableProvider
{
public int Order => 100;
public IEnumerable<DiagnosticsTable> BuildTables()
{
yield return new DiagnosticsTable
{
Name = "租户配额",
Group = "Quota",
Columns = new List<DiagnosticsColumn>
{
new("租户"),
new("配额"),
new("对接密钥", sensitive: true) // 声明敏感的列整列强制指纹化
},
Rows = new List<IReadOnlyList<string>>
{
new[] { "华东", "1000", "9f3e2a1b-secure-partner-key" },
new[] { "华南", "800", "7c2b9d0e-another-key" }
}
};
}
}
页面按 Group 自动生成独立 Tab(内置中文映射目前只有 Broker → "契约",未声明 Group 归"其他"Tab);provider 构建抛异常时跳过该表不拖垮端点,异常消息脱敏后记 Trace 日志;?format=json 的 tables 节、?format=text 的 [表格] 节与页面同源。
健康探针 IHealthProbe
public class HisGatewayProbe : IHealthProbe
{
public string ProbeName => "HIS · 网关";
public bool BlocksReady => false; // 外部弱依赖:标红提示,不参与摘流量
public async Task<HealthProbeResult> ProbeAsync()
{
try
{
using var client = new HttpClient();
var resp = await client.GetAsync("http://his-gateway/ping");
return HealthProbeResult.Ok($"端点: his-gateway(HTTP {(int)resp.StatusCode})");
}
catch (Exception ex)
{
return HealthProbeResult.Fail(ex.InnerException?.Message ?? ex.Message);
}
}
}
在 DI 里登记一行:services.AddSingleton<Aegis.Component.Diagnostics.IHealthProbe, HisGatewayProbe>();(Startup 的 ConfigureServices 或组件注册代码里)。
健康检查器 IHealthChecker
public class DemoDiskHealthChecker : IHealthChecker
{
public string HealthCheckerName => "磁盘可写(应用基目录)";
// 影响流量:不健康时 ready 探针 503;外部弱依赖改声明 HealthSeverity.Info
public HealthSeverity Severity => HealthSeverity.ReadyBlocking;
public uint MaxUnhealthCount => 3;
public TimeSpan CheckDuration => TimeSpan.FromSeconds(30);
public ValueTask<bool> CheckAsync()
{
try
{
var probe = Path.Combine(AppContext.BaseDirectory, $"healthprobe-{Guid.NewGuid():N}.tmp");
File.WriteAllText(probe, "ok");
File.Delete(probe);
return ValueTask.FromResult(true);
}
catch { return ValueTask.FromResult(false); }
}
public Task<bool> UnhealthCallBackAsync() => Task.FromResult(true);
public Task<bool> FatalCallbackAsync() => Task.FromResult(true);
}
连续失败超过 MaxUnhealthCount 触发 FatalCallbackAsync(可接告警、熔断联动),健康恢复后计数清零;巡检周期 15 秒。
网络诊断 INetworkDiagnosticsProvider
对单个目标做分层现场探测,探测在后端执行(后端有网络权限,浏览器不一定能直达内网)。页面把段名与目标名对上的信息段挂上"一键诊断 ›"入口,匹配口径:全名精确相等,或截断"(…)"后缀后相等,与 ?diagnose= 端点同一套。通用层(DNS / ICMP / TCP / TLS)直接用 NetworkDiagSteps 的现成步骤,应用层一步自己写,探什么、怎么算通过由目标类型决定:
public class HisGatewayNetworkDiagnostics : INetworkDiagnosticsProvider
{
public string TargetName => "HIS · 网关"; // 与信息段段名对齐,段头才会出现按钮
public async Task<IReadOnlyList<DiagStep>> DiagnoseAsync()
{
var steps = new List<DiagStep>
{
await NetworkDiagSteps.DnsAsync("his-gateway"),
await NetworkDiagSteps.PingAsync("his-gateway"),
await NetworkDiagSteps.TcpAsync("his-gateway", 8080)
};
var sw = System.Diagnostics.Stopwatch.StartNew();
try
{
using var client = new HttpClient();
var resp = await client.GetAsync("http://his-gateway/ping");
steps.Add(new DiagStep("应用层 HTTP",
resp.IsSuccessStatusCode ? "passed" : "failed",
$"HTTP {(int)resp.StatusCode}", sw.Elapsed.TotalMilliseconds));
}
catch (Exception ex)
{
steps.Add(new DiagStep("应用层 HTTP", "failed",
ex.InnerException?.Message ?? ex.Message, sw.Elapsed.TotalMilliseconds));
}
return steps;
}
}
在 DI 里登记一行:services.AddSingleton<Aegis.Component.Diagnostics.INetworkDiagnosticsProvider, HisGatewayNetworkDiagnostics>();。
三个实现要点:
- 步骤状态四种:
passed/failed/skipped(前序失败短路)/unavailable(环境不支持,如容器禁 ICMP) - 每步自己带超时(
NetworkDiagSteps各步 3 秒);端点对整次诊断另有 15 秒兜底超时,到点返回 504 但不取消任务,任务由后台收尾后释放该目标的执行占位。实现不要发无超时的请求:挂住的请求在 504 之后仍占着执行位,后续请求会一直拿到"正在处理中",直到它真正完成或失败 - 目标运行时增删的场景(如 Broker 契约,端点随业务调用动态登记)不适合这个接口,实现
IDynamicNetworkDiagnosticsSource注册进NetworkDiagnosticsRegistry,匹配链会在静态目标未命中后接着查它
接口选型
| 需求 | 用哪个 |
|---|---|
| 只想展示信息(连接信息、计数) | IDiagnosticsSectionProvider |
| 清单类数据横向对比(多端点、多条目) | IDiagnosticsTableProvider |
| 第三方依赖连通性,红一下就行 | IHealthProbe |
| 失败要计数、要回调、要联动告警 | IHealthChecker |
| 现场分层探测连通性(页面上的一键诊断) | INetworkDiagnosticsProvider |
脱敏管线(provider 不用自己打码)
三种输出格式共用一份管线,表格单元格以列名为键同一条管线,原始值直接交给渲染层:
| 层 | 规则 | 效果 |
|---|---|---|
| 声明敏感 | entry 标 Sensitive = true | 强制指纹 |
| 键名黑名单 | 键名含 password / pwd / secret / token / credential / apikey / access_key / private_key | 指纹。true、数字这类平凡字面量豁免,开关配置不会被误伤 |
| 连接串遮蔽 | 值形如 ; 或 , 分隔的键值结构时,敏感段遮为 **** | 保留 host / database 等结构与分隔符原位置 |
| 指纹形态 | 尾 4 位 + 长度 + 结构特征(空格 / 非 ASCII / 首尾空白) | 保留对比排错能力;长度不足 8 位不保留尾缀 |
探针失败原因、组件 Fail 消息这类自由文本同样过脱敏出口,异常消息里常内嵌完整连接串。
常见问题
访问 /diag 是 404
三处排查:Component.deps.json 的 Load 清单是否包含了 Diagnostics;Aegis:Diagnostics:Enabled 是否被配成了 false;Path 是否改过路径。
健康矩阵一直是空的
说明没有任何 IHealthChecker / IHealthProbe 被发现。装配 Redis、数据库组件后会自动出现。自定义时确认:IHealthChecker 实现有无参构造,IHealthProbe 已注册到 DI。
段头没有"一键诊断"入口
按钮的渲染依据是后端给的可诊断目标名单,段名不在名单里就不出按钮。先确认该组件注册了 INetworkDiagnosticsProvider(名单只收网络诊断目标,信息段和健康探针不进这份名单);再核对目标名与段名是否对得上——比对时截断"(…)"后缀(如"(standalone)"不影响),除此之外要全名精确相等。不想点按钮也能直接调 ?diagnose=目标名 触发同一次诊断。
probe=ready 返回 503,但业务看着是好的
两种来源:健康矩阵有影响流量的红项,或组件台账有组件加载失败。503 正文会指明是哪一种,红项的失败原因直接显示在矩阵行里。
一键诊断一直显示"正在处理中",多久出结果
两种情况。一种是另一个请求正在执行同一目标(可能是同页面早先的一次点击、另一位访问者、或一次超时后还在后台收尾的诊断),等它完成即可,页面 5 秒自动刷新会带出结果。另一种是目标挂死(如 TCP 一直不通),那次诊断确实没跑完,会持续显示"正在处理中"直到后台收尾,这是如实反映,不是页面故障。另外,刚出结果后的缓存窗(ProbeCacheSeconds,默认 10 秒)内再点,直接显示带"诊断于 HH:mm:ss"标注的缓存结果,属正常行为。
生产环境能不能开这个页面
内网环境默认开没有问题(页面展示的是已脱敏的配置、端点和组件清单);对外网服务的处置见"配置项说明"的警告块。
pod 名显示成了机器名
实例名取 POD_NAME 环境变量,缺省回落机器名。hostNetwork 或自定义 hostname 的部署,用 Downward API 注入:
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
页面没有"日志平台"入口
Aegis:Diagnostics:LogPlatform:BaseUrl 未配置。目前只支持 VictoriaLogs(vmui),其他平台类型预留扩展。
页面多出来的"契约"Tab 是什么,能关掉吗
Broker 的表格数据自动生成的 Tab,生成规则见"表格 IDiagnosticsTableProvider"。数据源消失(比如不再引用 Broker 包)Tab 就不出现;展示本身没有 per-app 开关。
和 Prometheus、OpenTelemetry 什么关系
互补,不互相替代:Prometheus 看指标趋势,OpenTelemetry 看调用链,诊断组件看"这个实例此刻的自查"。排查通常先开 /diag 确认实例级事实,再下钻指标或链路。
配套阅读
- Redis 缓存
- FreeSql 数据访问
- 库表校验(Aegis.Core.FreeSql.SchemaValidation) — FreeSql 数据源在 /diag 的实体-库表类型比对
- Prometheus 指标监控
- OpenTelemetry 链路追踪
- UMeta 结构化日志