mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-08 16:46:37 +08:00
feat(frontend): 观测网络字节字段与 UV 文案对齐
网络图仅使用 bytes_provided/received;看板与节点 UV 改为 24h/查询窗口 独立访客;清理 traffic_reports 与 openresty 吞吐兼容字段;运维清理目标 改为 node_edge_health。
This commit is contained in:
@@ -25,9 +25,9 @@ export type OpenFlareOpsFields = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const defaultOpenFlareOpsFields: OpenFlareOpsFields = {
|
export const defaultOpenFlareOpsFields: OpenFlareOpsFields = {
|
||||||
agent_heartbeat_interval: '10000',
|
agent_heartbeat_interval: '3000',
|
||||||
agent_websocket_upgrade_enabled: true,
|
agent_websocket_upgrade_enabled: true,
|
||||||
node_offline_threshold: '120000',
|
node_offline_threshold: '60000',
|
||||||
agent_update_repo: 'Rain-kl/OpenFlare',
|
agent_update_repo: 'Rain-kl/OpenFlare',
|
||||||
geoip_provider: 'ipinfo',
|
geoip_provider: 'ipinfo',
|
||||||
server_address: '',
|
server_address: '',
|
||||||
@@ -68,12 +68,12 @@ export function mapOptionsToOpsFields(
|
|||||||
serverAddress = '',
|
serverAddress = '',
|
||||||
): OpenFlareOpsFields {
|
): OpenFlareOpsFields {
|
||||||
return {
|
return {
|
||||||
agent_heartbeat_interval: optionMap.agent_heartbeat_interval ?? '10000',
|
agent_heartbeat_interval: optionMap.agent_heartbeat_interval ?? '3000',
|
||||||
agent_websocket_upgrade_enabled: toBoolean(
|
agent_websocket_upgrade_enabled: toBoolean(
|
||||||
optionMap.agent_websocket_upgrade_enabled,
|
optionMap.agent_websocket_upgrade_enabled,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
node_offline_threshold: optionMap.node_offline_threshold ?? '120000',
|
node_offline_threshold: optionMap.node_offline_threshold ?? '60000',
|
||||||
agent_update_repo: optionMap.agent_update_repo ?? 'Rain-kl/OpenFlare',
|
agent_update_repo: optionMap.agent_update_repo ?? 'Rain-kl/OpenFlare',
|
||||||
geoip_provider: optionMap.geoip_provider ?? 'ipinfo',
|
geoip_provider: optionMap.geoip_provider ?? 'ipinfo',
|
||||||
server_address: optionMap.server_address || serverAddress,
|
server_address: optionMap.server_address || serverAddress,
|
||||||
@@ -129,12 +129,15 @@ export function buildDiscoveryCommand(
|
|||||||
export function validateAgentFields(fields: OpenFlareOpsFields) {
|
export function validateAgentFields(fields: OpenFlareOpsFields) {
|
||||||
const heartbeat = Number.parseInt(fields.agent_heartbeat_interval, 10);
|
const heartbeat = Number.parseInt(fields.agent_heartbeat_interval, 10);
|
||||||
const offline = Number.parseInt(fields.node_offline_threshold, 10);
|
const offline = Number.parseInt(fields.node_offline_threshold, 10);
|
||||||
if (Number.isNaN(heartbeat) || heartbeat < 5000) {
|
if (Number.isNaN(heartbeat) || heartbeat < 1000) {
|
||||||
throw new Error('心跳间隔不能小于 5000 毫秒。');
|
throw new Error('心跳间隔不能小于 1000 毫秒。');
|
||||||
}
|
}
|
||||||
if (Number.isNaN(offline) || offline < 10000) {
|
if (Number.isNaN(offline) || offline < 10000) {
|
||||||
throw new Error('离线阈值不能小于 10000 毫秒。');
|
throw new Error('离线阈值不能小于 10000 毫秒。');
|
||||||
}
|
}
|
||||||
|
if (offline < heartbeat * 3) {
|
||||||
|
throw new Error('离线阈值建议至少为心跳间隔的 3 倍。');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function validateUptimeKumaFields(fields: OpenFlareOpsFields) {
|
export function validateUptimeKumaFields(fields: OpenFlareOpsFields) {
|
||||||
|
|||||||
@@ -90,10 +90,10 @@ const cleanupTargets: Array<{
|
|||||||
'清理 node_metric_snapshots,影响节点资源趋势;表 TTL 为 30 天。',
|
'清理 node_metric_snapshots,影响节点资源趋势;表 TTL 为 30 天。',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
target: 'node_request_reports',
|
target: 'node_edge_health',
|
||||||
label: '请求聚合',
|
label: 'OpenResty 健康',
|
||||||
description:
|
description:
|
||||||
'清理 node_request_reports,影响请求量与错误量统计;表 TTL 为 30 天。',
|
'清理 node_edge_health(OpenResty 连接/健康快照);表 TTL 为 30 天。业务流量请清理访问日志。',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export function NetworkDiskTrendChart({
|
|||||||
<Card className='border-dashed shadow-none'>
|
<Card className='border-dashed shadow-none'>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className='text-sm font-semibold'>
|
<CardTitle className='text-sm font-semibold'>
|
||||||
24 小时网络与磁盘趋势
|
24 小时业务流量与宿主机磁盘
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className='space-y-6'>
|
<CardContent className='space-y-6'>
|
||||||
@@ -30,21 +30,47 @@ export function NetworkDiskTrendChart({
|
|||||||
)}
|
)}
|
||||||
height={180}
|
height={180}
|
||||||
summaryScope='total'
|
summaryScope='total'
|
||||||
summaryHint='近 24 小时'
|
summaryHint='近 24 小时 · 来自访问日志'
|
||||||
yAxisValueFormatter={formatBytes}
|
yAxisValueFormatter={formatBytes}
|
||||||
series={[
|
series={[
|
||||||
{
|
{
|
||||||
label: 'OpenResty 入站',
|
label: '接收数据',
|
||||||
color: '#22c55e',
|
color: '#22c55e',
|
||||||
fillColor: 'rgba(34, 197, 94, 0.14)',
|
fillColor: 'rgba(34, 197, 94, 0.14)',
|
||||||
variant: 'area',
|
variant: 'area',
|
||||||
values: networkPoints.map((point) => point.openresty_rx_bytes),
|
values: networkPoints.map((point) => point.bytes_received),
|
||||||
valueFormatter: formatBytes,
|
valueFormatter: formatBytes,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'OpenResty 出站',
|
label: '已提供数据',
|
||||||
color: '#38bdf8',
|
color: '#38bdf8',
|
||||||
values: networkPoints.map((point) => point.openresty_tx_bytes),
|
values: networkPoints.map((point) => point.bytes_provided),
|
||||||
|
valueFormatter: formatBytes,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TrendChart
|
||||||
|
labels={networkPoints.map((point) =>
|
||||||
|
formatTrendHour(point.bucket_started_at),
|
||||||
|
)}
|
||||||
|
height={180}
|
||||||
|
summaryScope='total'
|
||||||
|
summaryHint='近 24 小时 · 宿主机网卡'
|
||||||
|
yAxisValueFormatter={formatBytes}
|
||||||
|
series={[
|
||||||
|
{
|
||||||
|
label: '宿主机网卡入站',
|
||||||
|
color: '#a3e635',
|
||||||
|
fillColor: 'rgba(163, 230, 53, 0.12)',
|
||||||
|
variant: 'area',
|
||||||
|
values: networkPoints.map((point) => point.network_rx_bytes),
|
||||||
|
valueFormatter: formatBytes,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '宿主机网卡出站',
|
||||||
|
color: '#f97316',
|
||||||
|
values: networkPoints.map((point) => point.network_tx_bytes),
|
||||||
valueFormatter: formatBytes,
|
valueFormatter: formatBytes,
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
@@ -56,7 +82,7 @@ export function NetworkDiskTrendChart({
|
|||||||
)}
|
)}
|
||||||
height={180}
|
height={180}
|
||||||
summaryScope='total'
|
summaryScope='total'
|
||||||
summaryHint='近 24 小时'
|
summaryHint='近 24 小时 · 宿主机磁盘'
|
||||||
yAxisValueFormatter={formatBytes}
|
yAxisValueFormatter={formatBytes}
|
||||||
series={[
|
series={[
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ export function DashboardStatCards({
|
|||||||
{formatCompactNumber(traffic.request_count)}
|
{formatCompactNumber(traffic.request_count)}
|
||||||
</div>
|
</div>
|
||||||
<p className='text-[10px] text-muted-foreground'>
|
<p className='text-[10px] text-muted-foreground'>
|
||||||
窗口UV(估) {formatCompactNumber(traffic.unique_visitors)} · 错误{' '}
|
24h 独立访客 {formatCompactNumber(traffic.unique_visitors)} · 错误{' '}
|
||||||
{formatCompactNumber(traffic.error_count)} · 估算 QPS{' '}
|
{formatCompactNumber(traffic.error_count)} · 估算 QPS{' '}
|
||||||
{traffic.estimated_qps.toFixed(2)}
|
{traffic.estimated_qps.toFixed(2)}
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
export function NetworkTrendChart({
|
export function NetworkTrendChart({
|
||||||
points,
|
points,
|
||||||
title = '24 小时网络趋势',
|
title = '24 小时网络趋势',
|
||||||
description = '按小时展示 OpenResty 入站/出站流量累计,摘要为近 24 小时总量。',
|
description = '按小时展示已提供/接收数据(访问日志)与宿主机网卡;摘要为近 24 小时总量。',
|
||||||
}: {
|
}: {
|
||||||
points: NetworkTrendPoint[];
|
points: NetworkTrendPoint[];
|
||||||
title?: string;
|
title?: string;
|
||||||
@@ -40,17 +40,29 @@ export function NetworkTrendChart({
|
|||||||
yAxisValueFormatter={formatBytes}
|
yAxisValueFormatter={formatBytes}
|
||||||
series={[
|
series={[
|
||||||
{
|
{
|
||||||
label: 'OpenResty 入站',
|
label: '接收数据',
|
||||||
color: '#22c55e',
|
color: '#22c55e',
|
||||||
fillColor: 'rgba(34, 197, 94, 0.14)',
|
fillColor: 'rgba(34, 197, 94, 0.14)',
|
||||||
variant: 'area',
|
variant: 'area',
|
||||||
values: points.map((point) => point.openresty_rx_bytes),
|
values: points.map((point) => point.bytes_received),
|
||||||
valueFormatter: formatBytes,
|
valueFormatter: formatBytes,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'OpenResty 出站',
|
label: '已提供数据',
|
||||||
color: '#38bdf8',
|
color: '#38bdf8',
|
||||||
values: points.map((point) => point.openresty_tx_bytes),
|
values: points.map((point) => point.bytes_provided),
|
||||||
|
valueFormatter: formatBytes,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '宿主机网卡入站',
|
||||||
|
color: '#a3e635',
|
||||||
|
values: points.map((point) => point.network_rx_bytes),
|
||||||
|
valueFormatter: formatBytes,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '宿主机网卡出站',
|
||||||
|
color: '#f97316',
|
||||||
|
values: points.map((point) => point.network_tx_bytes),
|
||||||
valueFormatter: formatBytes,
|
valueFormatter: formatBytes,
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
|
|||||||
@@ -38,9 +38,7 @@ import { DistributionList } from './distribution-list';
|
|||||||
import { NetworkTrendChart } from './network-trend-chart';
|
import { NetworkTrendChart } from './network-trend-chart';
|
||||||
import { NodeStatusBadge } from './node-status-badge';
|
import { NodeStatusBadge } from './node-status-badge';
|
||||||
import {
|
import {
|
||||||
aggregateTrafficBreakdown,
|
|
||||||
formatBytes,
|
formatBytes,
|
||||||
formatBytesPerSecond,
|
|
||||||
formatMetricCount,
|
formatMetricCount,
|
||||||
formatPercent,
|
formatPercent,
|
||||||
formatRelativeTime,
|
formatRelativeTime,
|
||||||
@@ -395,26 +393,26 @@ export function NodeObservability({
|
|||||||
resolvedHealthEvents,
|
resolvedHealthEvents,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const trafficSummary = observability?.analytics?.traffic ?? null;
|
||||||
|
const healthSummary = observability?.analytics?.health ?? null;
|
||||||
|
const distributions = observability?.analytics?.distributions;
|
||||||
const statusCodeDistribution = useMemo(
|
const statusCodeDistribution = useMemo(
|
||||||
() =>
|
() =>
|
||||||
aggregateTrafficBreakdown(
|
(distributions?.status_codes ?? []).map((item) => ({
|
||||||
observability?.traffic_reports,
|
label: item.key,
|
||||||
'status_codes_json',
|
value: item.value,
|
||||||
),
|
})),
|
||||||
[observability?.traffic_reports],
|
[distributions?.status_codes],
|
||||||
);
|
);
|
||||||
const topDomains = useMemo(
|
const topDomains = useMemo(
|
||||||
() =>
|
() =>
|
||||||
aggregateTrafficBreakdown(
|
(distributions?.top_domains ?? []).map((item) => ({
|
||||||
observability?.traffic_reports,
|
label: item.key,
|
||||||
'top_domains_json',
|
value: item.value,
|
||||||
),
|
})),
|
||||||
[observability?.traffic_reports],
|
[distributions?.top_domains],
|
||||||
);
|
);
|
||||||
const trafficSummary = observability?.analytics?.traffic ?? null;
|
const topSourceCountry = distributions?.source_countries?.[0] ?? null;
|
||||||
const healthSummary = observability?.analytics?.health ?? null;
|
|
||||||
const topSourceCountry =
|
|
||||||
observability?.analytics?.distributions?.source_countries?.[0] ?? null;
|
|
||||||
const latestHealthEvent = activeHealthEvents[0] ?? null;
|
const latestHealthEvent = activeHealthEvents[0] ?? null;
|
||||||
const dominantStatusCode = statusCodeDistribution[0] ?? null;
|
const dominantStatusCode = statusCodeDistribution[0] ?? null;
|
||||||
const dominantDomain = topDomains[0] ?? null;
|
const dominantDomain = topDomains[0] ?? null;
|
||||||
@@ -604,11 +602,11 @@ export function NodeObservability({
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<SummaryStat
|
<SummaryStat
|
||||||
label='请求/分钟'
|
label='查询窗口请求'
|
||||||
value={formatMetricCount(trafficSummary?.request_count)}
|
value={formatMetricCount(trafficSummary?.request_count)}
|
||||||
hint={
|
hint={
|
||||||
trafficSummary
|
trafficSummary
|
||||||
? `近 60 秒 · 错误率 ${trafficSummary.error_rate_percent.toFixed(1)}%`
|
? `查询窗口独立访客 ${formatMetricCount(trafficSummary.unique_visitor_count)} · 错误率 ${trafficSummary.error_rate_percent.toFixed(1)}%`
|
||||||
: '当前没有可展示的请求窗口摘要'
|
: '当前没有可展示的请求窗口摘要'
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@@ -721,22 +719,15 @@ export function NodeObservability({
|
|||||||
<div className='grid gap-3 sm:grid-cols-2'>
|
<div className='grid gap-3 sm:grid-cols-2'>
|
||||||
<div className='rounded-lg border px-3 py-3'>
|
<div className='rounded-lg border px-3 py-3'>
|
||||||
<p className='text-xs text-muted-foreground uppercase tracking-wide'>
|
<p className='text-xs text-muted-foreground uppercase tracking-wide'>
|
||||||
OpenResty 吞吐
|
OpenResty 连接
|
||||||
</p>
|
</p>
|
||||||
<div className='mt-3 space-y-2 text-sm text-muted-foreground'>
|
<div className='mt-3 space-y-2 text-sm text-muted-foreground'>
|
||||||
<p>
|
<p>
|
||||||
入站:
|
当前连接:
|
||||||
{formatBytesPerSecond(
|
{latestMetric.openresty_connections ?? 0}
|
||||||
latestMetric.openresty_rx_bytes,
|
|
||||||
60,
|
|
||||||
)}
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p className='text-xs'>
|
||||||
出站:
|
业务吞吐请看访问日志趋势(已提供/接收数据)
|
||||||
{formatBytesPerSecond(
|
|
||||||
latestMetric.openresty_tx_bytes,
|
|
||||||
60,
|
|
||||||
)}
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -754,20 +745,20 @@ export function NodeObservability({
|
|||||||
<div className='grid gap-3 sm:grid-cols-2'>
|
<div className='grid gap-3 sm:grid-cols-2'>
|
||||||
<div className='rounded-lg border px-3 py-3'>
|
<div className='rounded-lg border px-3 py-3'>
|
||||||
<p className='text-xs text-muted-foreground uppercase tracking-wide'>
|
<p className='text-xs text-muted-foreground uppercase tracking-wide'>
|
||||||
请求/分钟
|
查询窗口独立访客
|
||||||
</p>
|
</p>
|
||||||
<p className='mt-3 text-2xl font-semibold'>
|
<p className='mt-3 text-2xl font-semibold'>
|
||||||
{formatMetricCount(trafficSummary?.request_count)}
|
{formatMetricCount(trafficSummary?.unique_visitor_count)}
|
||||||
</p>
|
</p>
|
||||||
<p className='mt-2 text-sm text-muted-foreground'>
|
<p className='mt-2 text-sm text-muted-foreground'>
|
||||||
{trafficSummary
|
{trafficSummary
|
||||||
? `近 60 秒 · 窗口UV ${formatMetricCount(trafficSummary.unique_visitor_count)}`
|
? `请求 ${formatMetricCount(trafficSummary.request_count)} · 估算 QPS ${trafficSummary.estimated_qps.toFixed(2)}`
|
||||||
: '暂无窗口流量摘要'}
|
: '暂无窗口流量摘要'}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className='rounded-lg border px-3 py-3'>
|
<div className='rounded-lg border px-3 py-3'>
|
||||||
<p className='text-xs text-muted-foreground uppercase tracking-wide'>
|
<p className='text-xs text-muted-foreground uppercase tracking-wide'>
|
||||||
近 60 秒错误
|
查询窗口错误
|
||||||
</p>
|
</p>
|
||||||
<p className='mt-3 text-2xl font-semibold'>
|
<p className='mt-3 text-2xl font-semibold'>
|
||||||
{formatMetricCount(trafficSummary?.error_count)}
|
{formatMetricCount(trafficSummary?.error_count)}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import type {
|
|||||||
ApplyResult,
|
ApplyResult,
|
||||||
NodeItem,
|
NodeItem,
|
||||||
NodeStatus,
|
NodeStatus,
|
||||||
NodeTrafficReport,
|
|
||||||
OpenrestyStatus,
|
OpenrestyStatus,
|
||||||
} from '@/lib/services/openflare';
|
} from '@/lib/services/openflare';
|
||||||
|
|
||||||
@@ -238,48 +237,6 @@ export function formatBytesPerSecond(value?: number | null, windowSeconds = 1) {
|
|||||||
return `${formatBytes(value / windowSeconds)}/s`;
|
return `${formatBytes(value / windowSeconds)}/s`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseTrafficMap(value?: string | null) {
|
|
||||||
if (!value) {
|
|
||||||
return {} as Record<string, number>;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const parsed = JSON.parse(value) as Record<string, number>;
|
|
||||||
return Object.entries(parsed).reduce<Record<string, number>>(
|
|
||||||
(result, [key, count]) => {
|
|
||||||
if (typeof count === 'number' && Number.isFinite(count)) {
|
|
||||||
result[key] = count;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
);
|
|
||||||
} catch {
|
|
||||||
return {} as Record<string, number>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function aggregateTrafficBreakdown(
|
|
||||||
reports: NodeTrafficReport[] | undefined,
|
|
||||||
field: 'status_codes_json' | 'top_domains_json',
|
|
||||||
) {
|
|
||||||
const summary = new Map<string, number>();
|
|
||||||
for (const report of reports ?? []) {
|
|
||||||
const parsed = parseTrafficMap(report[field]);
|
|
||||||
for (const [key, value] of Object.entries(parsed)) {
|
|
||||||
summary.set(key, (summary.get(key) ?? 0) + value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Array.from(summary.entries())
|
|
||||||
.sort((left, right) => {
|
|
||||||
if (right[1] === left[1]) {
|
|
||||||
return left[0].localeCompare(right[0]);
|
|
||||||
}
|
|
||||||
return right[1] - left[1];
|
|
||||||
})
|
|
||||||
.slice(0, 6)
|
|
||||||
.map(([label, value]) => ({ label, value }));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function formatUsageRatio(used?: number | null, total?: number | null) {
|
export function formatUsageRatio(used?: number | null, total?: number | null) {
|
||||||
if (!used || !total || total <= 0) {
|
if (!used || !total || total <= 0) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -130,11 +130,19 @@ function normalizeNetworkTrendPoints(
|
|||||||
bucket_started_at: String(item[0] ?? ''),
|
bucket_started_at: String(item[0] ?? ''),
|
||||||
network_rx_bytes: Number(item[1] ?? 0),
|
network_rx_bytes: Number(item[1] ?? 0),
|
||||||
network_tx_bytes: Number(item[2] ?? 0),
|
network_tx_bytes: Number(item[2] ?? 0),
|
||||||
openresty_rx_bytes: Number(item[3] ?? 0),
|
bytes_received: Number(item[3] ?? 0),
|
||||||
openresty_tx_bytes: Number(item[4] ?? 0),
|
bytes_provided: Number(item[4] ?? 0),
|
||||||
reported_nodes: Number(item[5] ?? 0),
|
reported_nodes: Number(item[5] ?? 0),
|
||||||
}
|
}
|
||||||
: item,
|
: {
|
||||||
|
...item,
|
||||||
|
bytes_received: Number(
|
||||||
|
(item as { bytes_received?: number }).bytes_received ?? 0,
|
||||||
|
),
|
||||||
|
bytes_provided: Number(
|
||||||
|
(item as { bytes_provided?: number }).bytes_provided ?? 0,
|
||||||
|
),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ export type {
|
|||||||
NodeObservabilityAnalytics,
|
NodeObservabilityAnalytics,
|
||||||
NodeObservabilityTrends,
|
NodeObservabilityTrends,
|
||||||
NodeSystemProfile,
|
NodeSystemProfile,
|
||||||
NodeTrafficReport,
|
|
||||||
NodeStatus,
|
NodeStatus,
|
||||||
NodeType,
|
NodeType,
|
||||||
OpenrestyStatus,
|
OpenrestyStatus,
|
||||||
|
|||||||
@@ -122,8 +122,6 @@ export interface NodeMetricSnapshot {
|
|||||||
disk_write_bytes: number;
|
disk_write_bytes: number;
|
||||||
network_rx_bytes: number;
|
network_rx_bytes: number;
|
||||||
network_tx_bytes: number;
|
network_tx_bytes: number;
|
||||||
openresty_rx_bytes: number;
|
|
||||||
openresty_tx_bytes: number;
|
|
||||||
openresty_connections: number;
|
openresty_connections: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,17 +137,6 @@ export interface NodeHealthEvent {
|
|||||||
resolved_at?: string | null;
|
resolved_at?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NodeTrafficReport {
|
|
||||||
window_started_at: string;
|
|
||||||
window_ended_at: string;
|
|
||||||
request_count: number;
|
|
||||||
error_count: number;
|
|
||||||
unique_visitor_count: number;
|
|
||||||
status_codes_json: string;
|
|
||||||
top_domains_json: string;
|
|
||||||
source_countries_json: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface NodeTrafficSummary {
|
export interface NodeTrafficSummary {
|
||||||
window_started_at: string;
|
window_started_at: string;
|
||||||
window_ended_at: string;
|
window_ended_at: string;
|
||||||
@@ -194,7 +181,6 @@ export interface NodeObservability {
|
|||||||
node_id: string;
|
node_id: string;
|
||||||
profile: NodeSystemProfile | null;
|
profile: NodeSystemProfile | null;
|
||||||
metric_snapshots: NodeMetricSnapshot[];
|
metric_snapshots: NodeMetricSnapshot[];
|
||||||
traffic_reports?: NodeTrafficReport[];
|
|
||||||
health_events: NodeHealthEvent[];
|
health_events: NodeHealthEvent[];
|
||||||
analytics?: NodeObservabilityAnalytics;
|
analytics?: NodeObservabilityAnalytics;
|
||||||
trends?: NodeObservabilityTrends;
|
trends?: NodeObservabilityTrends;
|
||||||
@@ -665,7 +651,11 @@ export interface GeoIPLookupResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type DatabaseCleanupTarget =
|
export type DatabaseCleanupTarget =
|
||||||
'node_access_logs' | 'node_metric_snapshots' | 'node_request_reports';
|
| 'node_access_logs'
|
||||||
|
| 'node_metric_snapshots'
|
||||||
|
| 'node_edge_health'
|
||||||
|
| 'node_obs_frps'
|
||||||
|
| 'node_obs_frpc';
|
||||||
|
|
||||||
export interface DatabaseCleanupPayload {
|
export interface DatabaseCleanupPayload {
|
||||||
target: DatabaseCleanupTarget;
|
target: DatabaseCleanupTarget;
|
||||||
@@ -936,8 +926,10 @@ export interface NetworkTrendPoint {
|
|||||||
bucket_started_at: string;
|
bucket_started_at: string;
|
||||||
network_rx_bytes: number;
|
network_rx_bytes: number;
|
||||||
network_tx_bytes: number;
|
network_tx_bytes: number;
|
||||||
openresty_rx_bytes: number;
|
/** L1 接收数据 sum(request_length) */
|
||||||
openresty_tx_bytes: number;
|
bytes_received: number;
|
||||||
|
/** L1 已提供数据 sum(bytes_sent) */
|
||||||
|
bytes_provided: number;
|
||||||
reported_nodes: number;
|
reported_nodes: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user