Improve VPN client connection management
This commit is contained in:
@@ -114,7 +114,88 @@ export function renderPrometheusMetrics(value: unknown) {
|
||||
}
|
||||
}
|
||||
|
||||
const directTraffic = record(snapshot.directTraffic);
|
||||
const directSeries = Array.isArray(directTraffic.series) ? directTraffic.series.map(record) : [];
|
||||
const directObservedAt = timestamp(directTraffic.observedAt);
|
||||
if (directObservedAt) {
|
||||
lines.push(
|
||||
'# HELP harbor_direct_ipv4_packet_bytes_total IPv4 L3 packet bytes forwarded directly instead of entering sing-box; includes IP headers and retransmissions.',
|
||||
'# TYPE harbor_direct_ipv4_packet_bytes_total counter',
|
||||
);
|
||||
metric(lines, 'harbor_direct_ipv4_packet_bytes_total', { direction: 'download' }, counter(directTraffic.downloadBytes));
|
||||
metric(lines, 'harbor_direct_ipv4_packet_bytes_total', { direction: 'upload' }, counter(directTraffic.uploadBytes));
|
||||
}
|
||||
if (directSeries.length) {
|
||||
lines.push(
|
||||
'# HELP harbor_device_direct_ipv4_packet_bytes_total Attributed IPv4 L3 packet bytes forwarded directly instead of entering sing-box.',
|
||||
'# TYPE harbor_device_direct_ipv4_packet_bytes_total counter',
|
||||
);
|
||||
for (const series of directSeries) {
|
||||
for (const [direction, amount] of [
|
||||
['download', series.downloadBytes],
|
||||
['upload', series.uploadBytes],
|
||||
]) {
|
||||
metric(lines, 'harbor_device_direct_ipv4_packet_bytes_total', {
|
||||
device_id: series.deviceId,
|
||||
direction,
|
||||
}, counter(amount));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (directObservedAt) {
|
||||
lines.push(
|
||||
'# HELP harbor_direct_ipv4_packet_last_observed_timestamp_seconds Unix timestamp of the last successful direct IPv4 packet observation.',
|
||||
'# TYPE harbor_direct_ipv4_packet_last_observed_timestamp_seconds gauge',
|
||||
);
|
||||
lines.push(`harbor_direct_ipv4_packet_last_observed_timestamp_seconds ${directObservedAt}`);
|
||||
}
|
||||
|
||||
const domainTraffic = record(snapshot.domainTraffic);
|
||||
const trackedSeries = Array.isArray(domainTraffic.tracked) ? domainTraffic.tracked.map(record) : [];
|
||||
if (trackedSeries.length) {
|
||||
lines.push(
|
||||
'# HELP harbor_singbox_tracked_bytes_total Bytes observed by the sing-box TCP/UDP tracker; excludes IP and tunnel overhead and may miss short connections.',
|
||||
'# TYPE harbor_singbox_tracked_bytes_total counter',
|
||||
);
|
||||
for (const series of trackedSeries) {
|
||||
const source = String(series.source || '');
|
||||
const outbound = String(series.outbound || '');
|
||||
if (!['gateway', 'proxy'].includes(source) || !['vpn', 'direct', 'unknown'].includes(outbound)) {
|
||||
throw new Error('Invalid sing-box outbound labels');
|
||||
}
|
||||
for (const [direction, amount] of [
|
||||
['download', series.downloadBytes],
|
||||
['upload', series.uploadBytes],
|
||||
]) {
|
||||
metric(lines, 'harbor_singbox_tracked_bytes_total', { source, outbound, direction }, counter(amount));
|
||||
}
|
||||
}
|
||||
}
|
||||
const routeSeries = Array.isArray(domainTraffic.routes) ? domainTraffic.routes.map(record) : [];
|
||||
if (routeSeries.length) {
|
||||
lines.push(
|
||||
'# HELP harbor_device_singbox_tracked_bytes_total Attributed bytes observed by the sing-box TCP/UDP tracker for a selected outbound.',
|
||||
'# TYPE harbor_device_singbox_tracked_bytes_total counter',
|
||||
);
|
||||
for (const series of routeSeries) {
|
||||
const source = String(series.source || '');
|
||||
const outbound = String(series.outbound || '');
|
||||
if (!['gateway', 'proxy'].includes(source) || !['vpn', 'direct', 'unknown'].includes(outbound)) {
|
||||
throw new Error('Invalid sing-box outbound labels');
|
||||
}
|
||||
for (const [direction, amount] of [
|
||||
['download', series.downloadBytes],
|
||||
['upload', series.uploadBytes],
|
||||
]) {
|
||||
metric(lines, 'harbor_device_singbox_tracked_bytes_total', {
|
||||
device_id: series.deviceId,
|
||||
source,
|
||||
outbound,
|
||||
direction,
|
||||
}, counter(amount));
|
||||
}
|
||||
}
|
||||
}
|
||||
const domainSeries = Array.isArray(domainTraffic.series) ? domainTraffic.series.map(record) : [];
|
||||
if (domainSeries.length) {
|
||||
lines.push(
|
||||
@@ -143,6 +224,11 @@ export function renderPrometheusMetrics(value: unknown) {
|
||||
'# TYPE harbor_domain_traffic_last_observed_timestamp_seconds gauge',
|
||||
);
|
||||
lines.push(`harbor_domain_traffic_last_observed_timestamp_seconds ${domainObservedAt}`);
|
||||
lines.push(
|
||||
'# HELP harbor_singbox_traffic_last_observed_timestamp_seconds Unix timestamp of the last successful sing-box traffic observation.',
|
||||
'# TYPE harbor_singbox_traffic_last_observed_timestamp_seconds gauge',
|
||||
`harbor_singbox_traffic_last_observed_timestamp_seconds ${domainObservedAt}`,
|
||||
);
|
||||
}
|
||||
if (domainTraffic.overflowConnections != null) {
|
||||
lines.push(
|
||||
|
||||
Reference in New Issue
Block a user