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
+16
View File
@@ -136,6 +136,22 @@ test('domain traffic accumulates connection deltas by device, service and source
downloadBytes: '70',
},
]);
assert.deepEqual(service.snapshot().routes, [
{
deviceId: id,
source: 'gateway',
outbound: 'vpn',
uploadBytes: '22',
downloadBytes: '200',
},
{
deviceId: id,
source: 'proxy',
outbound: 'vpn',
uploadBytes: '22',
downloadBytes: '260',
},
]);
assert.deepEqual(service.snapshot().attributionEvents, {
unresolved_host: '1',
unknown_device: '1',
+23
View File
@@ -27,6 +27,7 @@ const snapshot = {
proxyUploadBytes: '0',
proxyDownloadBytes: '0',
proxyTrafficObservedAt: null,
appliedPolicy: 'direct',
}],
directTraffic: {
observedAt,
@@ -80,6 +81,12 @@ const snapshot = {
outbound: 'vpn',
uploadBytes: '55',
downloadBytes: '666',
}, {
deviceId: 'dev_0011223344556677',
source: 'proxy',
outbound: 'vpn',
uploadBytes: '12',
downloadBytes: '345',
}],
series: [{
deviceId: 'dev_0011223344556677',
@@ -98,6 +105,8 @@ test('Prometheus exposition keeps exact counters, stable identity and escaped na
assert.match(output, /# TYPE harbor_traffic_bytes_total counter/);
assert.match(output, /harbor_traffic_bytes_total\{source="gateway"\} 9007199254740993/);
assert.match(output, /harbor_device_info\{device_id="dev_0011223344556677",name="ТВ \\"Зал\\"\\\\основной\\nэкран",ip="192\.168\.50\.7"\} 1/);
assert.match(output, /harbor_device_applied_policy\{device_id="dev_0011223344556677"\} 0/);
assert.doesNotMatch(output, /harbor_device_applied_policy\{[^\n]*(?:name|ip|mac|desired|status)=/);
assert.match(output, /harbor_device_traffic_bytes_total\{device_id="dev_0011223344556677",source="gateway",direction="upload"\} 9007199254740993/);
assert.doesNotMatch(output, /harbor_device_traffic_bytes_total\{[^\n]*name=/);
assert.doesNotMatch(output, /harbor_device_traffic_bytes_total\{[^\n]*source="proxy"/);
@@ -112,6 +121,7 @@ test('Prometheus exposition keeps exact counters, stable identity and escaped na
assert.match(output, /harbor_singbox_tracked_bytes_total\{source="gateway",outbound="vpn",direction="download"\} 777/);
assert.match(output, /# TYPE harbor_device_singbox_tracked_bytes_total counter/);
assert.match(output, /harbor_device_singbox_tracked_bytes_total\{device_id="dev_0011223344556677",source="gateway",outbound="vpn",direction="upload"\} 55/);
assert.match(output, /harbor_device_singbox_tracked_bytes_total\{device_id="dev_0011223344556677",source="proxy",outbound="vpn",direction="download"\} 345/);
assert.match(output, /harbor_device_domain_traffic_bytes_total\{device_id="dev_0011223344556677",domain="chatgpt\.com",service="OpenAI \/ ChatGPT",source="proxy",direction="download"\} 345/);
assert.match(output, /harbor_domain_traffic_last_observed_timestamp_seconds 1786183200/);
assert.match(output, /harbor_domain_traffic_overflow_connections_total 2/);
@@ -181,6 +191,19 @@ test('invalid canonical counters fail the scrape instead of publishing corrupt v
const invalidShadow = structuredClone(snapshot);
invalidShadow.domainTraffic.source.shadow.uploadDifferenceBytes = '1.5';
assert.throws(() => renderPrometheusMetrics(invalidShadow), /Invalid Prometheus gauge/);
const invalidPolicy = structuredClone(snapshot);
invalidPolicy.devices[0].appliedPolicy = 'future';
assert.throws(() => renderPrometheusMetrics(invalidPolicy), /Invalid applied device policy/);
});
test('Prometheus applied policy gauge reports VPN without changing series identity', () => {
const vpn = structuredClone(snapshot);
vpn.devices[0].appliedPolicy = 'vpn';
assert.match(
renderPrometheusMetrics(vpn),
/harbor_device_applied_policy\{device_id="dev_0011223344556677"\} 1/,
);
});
function routeResponse() {