fix(traffic): отличать измеренный ноль от отсутствия наблюдений
This commit is contained in:
1 parent
a28f871fd4
commit
9e0f695684
12 files changed
+111
-30
No files matched your search
@@ -20,7 +20,10 @@ export interface RatePoint {
|
||||
txMbps: number
|
||||
}
|
||||
|
||||
export interface TrafficObservations {rxNow:boolean;txNow:boolean;rxSeries:boolean[];txSeries:boolean[];sampledAt:string|null}
|
||||
|
||||
export interface BuiltTrafficSeries {
|
||||
observations?:TrafficObservations
|
||||
rxNow: number
|
||||
txNow: number
|
||||
rxPeak: number
|
||||
@@ -65,10 +68,12 @@ export function rateBpsFromDelta(
|
||||
prevAtMs: number,
|
||||
nextAtMs: number,
|
||||
): number | null {
|
||||
if(![prevBytes,nextBytes,prevAtMs,nextAtMs].every(Number.isFinite)||prevBytes<0||nextBytes<0)return null
|
||||
const dtSec = (nextAtMs - prevAtMs) / 1000
|
||||
if (!(dtSec > 0) || !Number.isFinite(dtSec)) return null
|
||||
if (nextBytes < prevBytes) return null
|
||||
return Math.round(((nextBytes - prevBytes) * 8) / dtSec)
|
||||
const rate=Math.round(((nextBytes - prevBytes) * 8) / dtSec)
|
||||
return Number.isFinite(rate)?rate:null
|
||||
}
|
||||
|
||||
export function bucketAvg(
|
||||
@@ -91,8 +96,7 @@ export function bucketAvg(
|
||||
}
|
||||
|
||||
function parseIsoMs(iso: string): number {
|
||||
const t = Date.parse(iso)
|
||||
return Number.isFinite(t) ? t : 0
|
||||
return Date.parse(iso)
|
||||
}
|
||||
|
||||
export function sampleSeriesKey(interfaceName: string, peerPublicKey = ""): string {
|
||||
@@ -105,6 +109,7 @@ export function buildTrafficFromSamples(
|
||||
rangeEndMs: number,
|
||||
onlyInterface?: string | readonly string[],
|
||||
peerPublicKey?: string,
|
||||
includeObservations=false,
|
||||
): BuiltTrafficSeries {
|
||||
const empty: BuiltTrafficSeries = {
|
||||
rxNow: 0,
|
||||
@@ -117,7 +122,8 @@ export function buildTrafficFromSamples(
|
||||
rxSeries: Array.from({ length: SERIES_POINTS }, () => 0),
|
||||
txSeries: Array.from({ length: SERIES_POINTS }, () => 0),
|
||||
}
|
||||
if (rows.length === 0) return empty
|
||||
const noObservations:TrafficObservations={rxNow:false,txNow:false,rxSeries:Array(SERIES_POINTS).fill(false),txSeries:Array(SERIES_POINTS).fill(false),sampledAt:null}
|
||||
if (rows.length === 0) return includeObservations?{...empty,observations:noObservations}:empty
|
||||
|
||||
const bySeries = new Map<string, TrafficSampleLike[]>()
|
||||
for (const r of rows) {
|
||||
@@ -133,7 +139,8 @@ export function buildTrafficFromSamples(
|
||||
|
||||
const rxPoints: Array<{ t: number; v: number }> = []
|
||||
const txPoints: Array<{ t: number; v: number }> = []
|
||||
const byTs = new Map<number, { rx: number; tx: number }>()
|
||||
const byTs = new Map<number, { rx: number; tx: number;rxObserved:boolean;txObserved:boolean;count:number }>()
|
||||
let includedSeries=0,lastAttemptAt:number|null=null
|
||||
|
||||
let rxBytesDelta = 0
|
||||
let txBytesDelta = 0
|
||||
@@ -159,6 +166,7 @@ export function buildTrafficFromSamples(
|
||||
if (!last) continue
|
||||
if (!allowList && (!last.running || last.disabled)) continue
|
||||
|
||||
includedSeries++
|
||||
if (last.running && !last.disabled) sessions += 1
|
||||
|
||||
const first = sorted[0]
|
||||
@@ -176,12 +184,14 @@ export function buildTrafficFromSamples(
|
||||
if (!allowList && (!cur.running || cur.disabled)) continue
|
||||
const t0 = parseIsoMs(prev.sampledAt)
|
||||
const t1 = parseIsoMs(cur.sampledAt)
|
||||
if(Number.isFinite(Date.parse(cur.sampledAt))&&t1>=rangeStartMs&&t1<=rangeEndMs)lastAttemptAt=Math.max(lastAttemptAt??t1,t1)
|
||||
const rxBps = rateBpsFromDelta(prev.rxBytes, cur.rxBytes, t0, t1)
|
||||
const txBps = rateBpsFromDelta(prev.txBytes, cur.txBytes, t0, t1)
|
||||
if (rxBps == null && txBps == null) continue
|
||||
const rxMbps = bpsToMbps(rxBps ?? 0)
|
||||
const txMbps = bpsToMbps(txBps ?? 0)
|
||||
const acc = byTs.get(t1) ?? { rx: 0, tx: 0 }
|
||||
const acc = byTs.get(t1) ?? { rx: 0, tx: 0,rxObserved:true,txObserved:true,count:0 }
|
||||
acc.count++;acc.rxObserved&&=rxBps!==null;acc.txObserved&&=txBps!==null
|
||||
acc.rx += rxMbps
|
||||
acc.tx += txMbps
|
||||
byTs.set(t1, acc)
|
||||
@@ -210,6 +220,13 @@ export function buildTrafficFromSamples(
|
||||
sessions,
|
||||
rxSeries,
|
||||
txSeries,
|
||||
...(includeObservations?{observations:{
|
||||
rxNow:lastAttemptAt!==null&&lastTs===lastAttemptAt&&!!last?.rxObserved&&last.count===includedSeries,
|
||||
txNow:lastAttemptAt!==null&&lastTs===lastAttemptAt&&!!last?.txObserved&&last.count===includedSeries,
|
||||
rxSeries:bucketAvg([...byTs].map(([t,v])=>({t,v:Number(v.rxObserved&&v.count===includedSeries&&t>=rangeStartMs&&t<=rangeEndMs)})),rangeStartMs,rangeEndMs).map(v=>v===1),
|
||||
txSeries:bucketAvg([...byTs].map(([t,v])=>({t,v:Number(v.txObserved&&v.count===includedSeries&&t>=rangeStartMs&&t<=rangeEndMs)})),rangeStartMs,rangeEndMs).map(v=>v===1),
|
||||
sampledAt:lastAttemptAt===null?null:new Date(lastAttemptAt).toISOString(),
|
||||
}}:{}),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user