Documentation
¶
Overview ¶
Package metrics is the SIP-signaling-layer observability surface.
Scope: counters and histograms covering the protocol behaviour itself (INVITE rate, response classes, transaction timeouts, session-timer refresh outcomes, STIR/DTLS handshake results, RTCP per-call QoS roll-up). The package never holds per-call state and every call site is O(1).
Cardinality discipline:
- Label keys come from a small enum set (direction, scenario, code_class, method, result, reason_class). Per-call identifiers (Call-ID, phone, SSRC) are NEVER labelled — those belong in the CDR record, not the metrics registry.
- Each metric declares its allowed keys via RegisterLabels in init(); the underlying metrics package enforces this softly.
Hot-path discipline:
- All exported helpers take only enums/integers and look up the pre-allocated label map. Zero string formatting at the call site, zero allocation in the steady state.
Index ¶
- Constants
- func BYE(direction, by, reasonClass string)
- func Bye(by, reasonClass string)
- func DTLSHandshake(result string)
- func InviteResult(direction string, code int)
- func ObserveCallQoS(rttMs uint32, jitterMs float64, lossFraction float64, mosEstimate float64)
- func STIRVerify(result string)
- func SessionTimerRefresh(result string)
- func TransactionTimeout(method string)
- func VoiceAttach(mode string, ok bool)
- func VoiceAttachModeFallback(from, to string)
- func VoiceAttachNative(ok bool)
Constants ¶
const ( // INVITE responses, classified by direction and response class. // One series per (direction, class) — bounded to 2 × 6 = 12 series. MetricInviteResultTotal = "sip_invite_result_total" // BYE events, classified by who initiated and reason class. MetricByeTotal = "sip_bye_total" // Transaction-level timeouts (timer F / B fired, RFC 3261). MetricTransactionTimeoutTotal = "sip_transaction_timeout_total" // RFC 4028 session-timer refresher events. result = ok / 422 / // 481 / role-swap / gave-up. MetricSessionTimerRefreshTotal = "sip_session_timer_refresh_total" // DTLS-SRTP handshake outcomes. result = ok / fail / timeout / // fingerprint-mismatch. MetricDTLSHandshakeTotal = "sip_dtls_handshake_total" // RFC 8224 STIR verification outcomes. MetricSTIRVerifyTotal = "sip_stir_verify_total" // RTCP-derived per-call QoS roll-ups, recorded ONCE at call end. MetricCallRTTMs = "sip_call_rtt_ms" MetricCallJitterMs = "sip_call_jitter_ms" MetricCallLossFraction = "sip_call_loss_fraction" MetricCallMOSEstimate = "sip_call_mos_estimate" )
Metric names. Single source of truth so dashboards can grep.
const ( DirectionInbound = "inbound" DirectionOutbound = "outbound" )
Direction enum.
const ( ByeByLocal = "local" ByeByRemote = "remote" // Reason classes — bounded enum. ByeReasonNormal = "normal" // 200 OK BYE no special cause ByeReasonTimerExpired = "timer-expired" // RFC 4028 session-timer expired ByeReasonError = "error" // unexpected (pipeline failure, etc.) ByeReasonUserHangup = "user-hangup" // explicit hangup intent )
Bye classification.
const ( RefreshResultOK = "ok" // peer accepted with 200 Refresh422Bumped = "422-bumped" // got 422, retried with peer Min-SE Refresh422GaveUp = "422-gave-up" // second 422, stopped Refresh481DialogGone = "481" // dialog disappeared RefreshRoleSwappedToUAS = "role-swap" // peer flipped refresher to itself )
Refresher event classification.
const ( DTLSResultOK = "ok" DTLSResultFail = "fail" DTLSResultTimeout = "timeout" DTLSResultFingerprintMismatch = "fingerprint-mismatch" )
const ( STIRResultVerified = "verified" STIRResultFailed = "failed" STIRResultSoftFail = "soft-fail" // verifier rejected but call continued STIRResultNoIdent = "no-identity" )
const ( // MetricVoiceAttachTotal counts voice-attach attempts at the OnACK // seam, classified by resolved engine.Mode and final outcome. // // labels: // mode = "cascaded" | "realtime" // result = "ok" | "config_error" // // "config_error" is the umbrella for every failure path that // played scripts/config_error.wav (no tenant id, env load error, // missing/incomplete credentials). Granular reasons live in the // log lines emitted by AttachCascadedLegacy / AttachRealtimeLegacy; // they're not labels because the cardinality blows up fast. MetricVoiceAttachTotal = "sip_voice_attach_total" // MetricVoiceAttachModeFallbackTotal counts implicit mode // fallbacks made by ResolveAttachMode (today: tenant persisted // voice_mode="pipeline" but pipeline creds are unusable and // realtime is ready → we auto-select realtime). // // labels: // from = "pipeline" // to = "realtime" MetricVoiceAttachModeFallbackTotal = "sip_voice_attach_mode_fallback_total" // MetricVoiceAttachNativeTotal counts decisions made by the // PR-9d feature flag to route a cascaded call through the // native cascaded.Engine (engine.ModeCascadedNative) instead of // the legacy bridge. Independent from MetricVoiceAttachTotal so // dashboards can monitor opt-in rollout without churn-affecting // the existing per-mode chart. // // labels: // result = "ok" | "err" MetricVoiceAttachNativeTotal = "sip_voice_attach_native_total" )
const ( VoiceAttachModeCascaded = "cascaded" VoiceAttachModeRealtime = "realtime" )
Voice-attach mode enum. Mirrors engine.Mode but kept as plain strings here so this package doesn't import pkg/dialog/engine (which would create an import cycle once engines start emitting metrics directly). The constants MUST stay in sync with engine.Mode's string values.
const ( VoiceAttachResultOK = "ok" VoiceAttachResultConfigError = "config_error" )
Voice-attach result enum.
Variables ¶
This section is empty.
Functions ¶
func BYE ¶
func BYE(direction, by, reasonClass string)
BYE bumps the BYE counter for the given direction (inbound / outbound), initiator (local / remote), and reason class. Backwards- compat shim: a 2-arg call still works via the Bye() helper which defaults direction to outbound. Hot path; zero allocation for any known combination.
func Bye ¶
func Bye(by, reasonClass string)
Bye is the outbound-default shim. Kept for existing callers that don't yet care about direction. New callers should prefer BYE() with an explicit direction.
func DTLSHandshake ¶
func DTLSHandshake(result string)
DTLSHandshake reports the outcome of one DTLS-SRTP handshake.
func InviteResult ¶
InviteResult bumps the INVITE result counter. `code` is the SIP status code (100..699); it's classified to its hundreds class so the label cardinality stays bounded at 6 per direction.
func ObserveCallQoS ¶
ObserveCallQoS records the per-call RTCP-derived metrics. Call this ONCE per call at cleanup (after the last RTCPSnapshot). All inputs are optional; zero / negative values are skipped so "no data" doesn't pollute the distribution.
Hot path? No — this runs at most once per call (~0.02 Hz/leg). Cardinality? Zero labels — these are global distributions.
func STIRVerify ¶
func STIRVerify(result string)
STIRVerify reports one STIR (RFC 8224) verification outcome.
func SessionTimerRefresh ¶
func SessionTimerRefresh(result string)
SessionTimerRefresh logs one refresher state transition. Hot path — called from outbound refresher response handler.
func TransactionTimeout ¶
func TransactionTimeout(method string)
TransactionTimeout reports a transaction-layer timeout (timer B/F fired). Method is the SIP method name (UPPER); we collapse the long tail into "other" to keep cardinality bounded.
func VoiceAttach ¶
VoiceAttach bumps the voice-attach counter for one OnACK dispatch. Unknown mode / result strings are dropped silently — the goal is hot-path safety, not enforcement (dashboards alert on missing series, not on rejected inputs).
func VoiceAttachModeFallback ¶
func VoiceAttachModeFallback(from, to string)
VoiceAttachModeFallback bumps the mode-fallback counter. Today this is only called when ResolveAttachMode promotes "pipeline" to "realtime" because pipeline creds are unusable. Future fallbacks would add new pre-allocated label maps and a switch arm.
func VoiceAttachNative ¶
func VoiceAttachNative(ok bool)
VoiceAttachNative bumps the native-cascaded routing counter. ok reflects whether the native attach succeeded (engine.New + Attach both returned nil). Hot-path: same allocation profile as VoiceAttach.
Types ¶
This section is empty.