Adds three new SD-WAN checks (wanAppRtpMos/Loss/Jitter) that measure
REAL voice-traffic quality on actual RTP frames via Prisma DPI, not
synthetic link probes. Graded against the WORST 5-minute window so
transient degradation the 24h link-probe averages smooth away
actually surfaces.
Voice-app selection is tenant-configurable via PRISMA_APP_ID_VOICE +
PRISMA_APP_NAME_VOICE (Webex_Calling_RTP recommended for Webex
Calling shops — the Webex-specific DPI signature excludes non-Webex
UDP noise). Legacy PRISMA_APP_ID_RTP_BASE still honored with a
one-time deprecation warning.
Widens the default WAN look-back from 24h to 7 days: per-app metrics
only get datapoints when calls actually happen, so sporadic Webex
Calling stores (3-4 calls/day) need a wider window for worst-window
statistics to be meaningful. Interval picker snaps 7d to 1hour
buckets (168 pts) to keep payloads bounded while preserving
worst-hour granularity. Hard-capped at 7d — beyond that Prisma
downsamples to 1-day buckets and the signal collapses.
Also:
- Client-side concurrency limiter (PRISMA_MAX_INFLIGHT, default 3)
to prevent 429 cascades when /voicediag fans out 10+ parallel
metric fetches
- "View in Prisma UI" deep links in both /phonestatus WAN follow-up
and /voicediag details, threading through a new
integrations/paloalto/urls.js builder
- humanizeMetricUnit maps raw API unit strings ("percentage",
"milliseconds") to display symbols ("%", "ms") to fix
"11.83percentage" leaking to the UI
- getAppAudio envelope distinguishes not-configured / fetch-failed /
no-traffic states so misleading "set env var" messages don't fire
when the real problem is a 429
Co-authored-by: Cursor <cursoragent@cursor.com>
57 lines
1.7 KiB
JavaScript
57 lines
1.7 KiB
JavaScript
// src/services/voiceDiag/checks/wan/wanAppRtpJitter.js
|
|
//
|
|
// Per-application audio jitter — measured on ACTUAL RTP voice
|
|
// traffic via Prisma DPI. Metric name on the v2.6 monitor/metrics
|
|
// endpoint is `AppPerfUDPAudioJitter` (unit: milliseconds), takes
|
|
// filter.direction="Ingress" AND filter.path_type=[all].
|
|
//
|
|
// See wanAppRtpMos.js for the app-selection contract — the check is
|
|
// app-agnostic; the tenant picks which voice app to grade via env.
|
|
//
|
|
// Grades against the WORST-window jitter — same reasoning as the
|
|
// MOS + loss checks: a brief burst that ruins in-flight calls is
|
|
// exactly what needs surfacing.
|
|
//
|
|
// Skipped when the voice-app env is not configured.
|
|
|
|
import {
|
|
maybeSkippedByKillSwitch,
|
|
getAppAudio,
|
|
evaluateAppAudioMetric,
|
|
getAppJitterWarnMs,
|
|
getAppJitterErrorMs,
|
|
} from './_helpers.js';
|
|
|
|
export const WAN_APP_RTP_JITTER_STANDARDS = Object.freeze({
|
|
maxWarnMs: 30,
|
|
maxErrorMs: 50,
|
|
unit: 'ms',
|
|
reference: 'RFC 3550 (jitter buffer tolerance)',
|
|
gradeAgainst: 'worst-window',
|
|
});
|
|
|
|
export const wanAppRtpJitterCheck = {
|
|
id: 'wanAppRtpJitter',
|
|
label: 'SD-WAN Voice Traffic Jitter (worst window)',
|
|
requires: ['sdwanSite'],
|
|
scope: null,
|
|
standards: WAN_APP_RTP_JITTER_STANDARDS,
|
|
|
|
async run(ctx) {
|
|
const skip = maybeSkippedByKillSwitch(wanAppRtpJitterCheck);
|
|
if (skip) return skip;
|
|
|
|
const audio = getAppAudio(ctx, 'jitter');
|
|
const warnThresh = getAppJitterWarnMs();
|
|
const errorThresh = getAppJitterErrorMs();
|
|
return evaluateAppAudioMetric({
|
|
audio,
|
|
label: 'jitter',
|
|
unit: 'ms',
|
|
warnThresh,
|
|
errorThresh,
|
|
lowIsBad: false,
|
|
standardLabel: `warn > ${warnThresh}ms, error > ${errorThresh}ms`,
|
|
});
|
|
},
|
|
};
|