Clarify VPN and Direct traffic metrics in Grafana dashboard
Build and Deploy Gateway / build-and-push (push) Successful in 31s
Build and Deploy Gateway / deploy (push) Successful in 7s

This commit is contained in:
2026-09-01 07:01:26 +03:00
parent 76a99f098a
commit ab14fc979e
8 changed files with 316 additions and 91 deletions
+15
View File
@@ -4,6 +4,7 @@ const COUNTER_PATTERN = /^\d+$/;
const SIGNED_DECIMAL_PATTERN = /^-?\d+$/;
const COLLECTOR_MODES = new Set(['snapshot', 'shadow', 'native']);
const COLLECTOR_WRITERS = new Set(['snapshot', 'native']);
const APPLIED_POLICY_VALUES: Readonly<Record<string, string>> = Object.freeze({ direct: '0', vpn: '1' });
const COLLECTOR_STATES = new Set([
'connecting', 'live', 'degraded', 'stale', 'stopped', 'incompatible', 'disabled',
]);
@@ -93,6 +94,20 @@ export function renderPrometheusMetrics(value: unknown) {
ip: device.ip || '',
}, '1');
}
lines.push(
'# HELP harbor_device_applied_policy Current applied device policy: 0 Direct, 1 VPN.',
'# TYPE harbor_device_applied_policy gauge',
);
for (const device of devices) {
const appliedPolicy = String(device.appliedPolicy || '');
if (!Object.hasOwn(APPLIED_POLICY_VALUES, appliedPolicy)) {
throw new Error('Invalid applied device policy');
}
metric(lines, 'harbor_device_applied_policy', {
device_id: device.id,
}, APPLIED_POLICY_VALUES[appliedPolicy]);
}
}
const deviceTraffic = devices.flatMap((device) => [
+3 -3
View File
@@ -1,7 +1,7 @@
export const HARBOR_VERSIONS = Object.freeze({
macClient: '0.36.0',
gatewayClient: '0.38.0',
gatewayBackend: '0.38.0',
macClient: '0.36.1',
gatewayClient: '0.38.1',
gatewayBackend: '0.38.1',
});
export interface ParsedVersion {
@@ -97,7 +97,7 @@ export function instructionBlocks({ isGateway, host, port, controlHost }: {
paragraphs: [
`Prometheus забирает накопленные Harbor counters с http://${controlHost}/metrics. Ручка читает готовый snapshot и не запускает новый сбор трафика.`,
'Harbor обновляет traffic snapshot раз в 15 секунд, поэтому начальный scrape interval и refresh dashboard в 30 секунд не создают лишних одинаковых выборок.',
'Единый фильтр «Устройства» управляет скоростью, накопленным трафиком, сервисами и доменами для всех или одного устройства. Отдельный график показывает текущую скорость каждого активного устройства; нулевые series скрыты.',
'Единый фильтр «Устройства» управляет applied policy, фактическим VPN/Direct, общим трафиком, сервисами и доменами. Policy Direct не запрещает VPN через явно настроенный Harbor Proxy: режим останется Direct, а proxy-байты появятся в VPN.',
],
steps: [
'Добавьте блок ниже в prometheus.yml и перезагрузите Prometheus.',
@@ -110,7 +110,7 @@ export function instructionBlocks({ isGateway, host, port, controlHost }: {
{ id: 'prometheus-config', label: 'prometheus.yml', text: prometheusScrapeConfig(controlHost) },
{ id: 'grafana-dashboard', label: 'Grafana dashboard', text: grafanaDashboardJson },
],
note: 'Domain counters снимаются с активных соединений sing-box раз в 2 секунды. Историю хранит Prometheus; соединения между снимками могут быть пропущены, неизвестный домен записывается как _unknown, а policy Direct виден только в отдельной Direct IPv4 metric.',
note: 'Историю хранит Prometheus. Основной Direct приблизительно объединяет sing-box и Linux IPv4 bytes с разной семантикой; точные значения остаются раздельными в технической секции. До первого scrape история applied policy отсутствует.',
}] : []),
];
}