Metric Labels and Conventions⚓︎
Every metric xView stores carries labels, and they do two jobs. Some identify where a measurement came from — which site, which customer, which network function — and xView attaches those itself as metrics travel in from the sites. Others describe what was measured, and those come from the component that produced the metric.
This page specifies both: the identity labels the platform adds to every xCore metric, and the convention Expeto components follow when labelling protocol traffic. Read it before writing a PromQL query, an alert rule or a dashboard — nearly every useful query aggregates over one of these labels.
Identity labels⚓︎
These labels answer "where did this come from?". They are attached automatically; no component has to emit them.
| Label | Meaning | Attached by | Example |
|---|---|---|---|
site |
Human-readable Site name, as configured in xControl | xControl, at discovery | AcmeCorp-Plant-01 |
siteId |
Stable identifier for the Site, as a full API URI | xControl, at discovery | https://api.example.com/v1/sites/81251 |
customer |
Human-readable Customer name | xControl, at discovery | AcmeCorp |
customerId |
Stable identifier for the Customer, as a full API URI | xControl, at discovery | https://api.example.com/v1/customers/20806 |
site_state |
Operational state of the Site; suppresses alerts when set | Site extension in xControl | maintenance |
xName |
Name of the monitoring endpoint the metrics came from | The Expeto Agent | xAgent |
vmName |
Name of the xView deployment that collected the metric | xView | expeto-central |
cluster |
Name of the cluster xView is running in | xView | expeto-central |
nfnode, nfnodeip |
The individual network function instance a metric describes | The Expeto Agent | mme-a, 192.0.2.122 |
job |
The scrape job that collected the metric | The scrape configuration | xAgent |
instance |
The target address that was scraped | Prometheus convention | 192.0.2.10:9767 |
Important
siteId and customerId are full URIs, not numbers. Match them with =~".*/v1/sites/81251"
or compare them to the value exactly as it appears; a query written as siteId="81251" matches
nothing. The URI is stable across renames, which is why alert annotations quote it alongside the
human-readable name.
Where identity labels are attached⚓︎
Identity labels are added at xControl, when it publishes the list of sites for xView to scrape — not at the site and not by the network functions. This matters in two ways.
First, renaming a Site in xControl changes the site label on everything that site reports from the
next scrape onward, with no change at the site itself.
Second, the labels can be overridden. xControl applies them in a fixed order of precedence:
- Extensions on the site's monitoring feature (highest)
- Extensions on the Site
- The default labels above (lowest)
Any extension whose key begins with label. becomes a metric label, with the prefix stripped — so
an extension label.region with value west adds region="west" to everything that site reports.
Overriding customer or site is a supported way to keep human-readable customer names out of a
monitoring system that other parties can see.
Note
Scrapes are configured to honor labels already present in the scraped data. If a site's metrics already carry a label, that value wins over the one xView would attach. This is what lets each site's identity survive being collected through a single shared endpoint.
Suspending monitoring for a site⚓︎
Nearly every Expeto alert expression carries the guard
site_state!~"decommissioned|maintenance". Setting the Site's state is therefore how you suppress a
site's alerts for planned work — it is a property of the Site, not a silence that expires.
To suspend monitoring for a Site:
- Open xControl, navigate to Sites, and click the name of the Site.
- Click Edit.
- Create or edit the extension
label.site_state. - Set the value to
maintenance(planned work, expected to return) ordecommissioned(the site is being retired). - Click Save.
The extension appears with the Site's other key parameters. To resume monitoring, delete the
extension or set it to enabled.
Warning
A suspended Site raises no alerts at all — including alerts that would tell you the maintenance itself has gone wrong. Clear the state as soon as the work is finished.
Traffic-metric conventions⚓︎
Protocol counters are the metrics you reach for when answering "is this interface healthy?". They follow one pattern across the platform:
xcore_<nf>_<protocol>_total{direction, message, type, cause}
One metric per protocol, with the detail in labels rather than in the metric name. The four labels are:
| Label | Answers | Values |
|---|---|---|
direction |
Which way did it go? | inbound, outbound, and the drop/retry variants below |
message |
Which protocol message was it? | The message name, lowercased, e.g. session_establishment |
type |
Which part of the exchange? | request, response, and the protocol-specific variants below |
cause |
How did it end? | The protocol's own result code, by name, e.g. request_accepted |
This shape is what makes cross-protocol queries possible. To find every rejected request a site
handled, regardless of protocol, count the responses whose cause is neither success value:
sum by (site, job) (
rate({__name__=~"xcore_.+_total", type="response", cause!="", cause!~"success|request_accepted"}[5m])
)
Both extra matchers are load-bearing. type="response" keeps requests out: they carry no cause,
and a negative regex match against an absent label succeeds, so without it every request would be
counted as a rejection. cause!="" then drops responses that carry no cause at all — which is
the case for the MME's counters — since those would otherwise be counted as rejections too.
direction⚓︎
| Value | Meaning |
|---|---|
inbound |
Received by this network function |
outbound |
Sent by this network function |
inbound_drop |
Received and discarded without being processed |
outbound_retry |
Re-sent after no response arrived in time |
Counting drops and retries separately is deliberate: inbound_drop isolates overload and malformed
traffic from healthy receive volume, and outbound_retry exposes a peer that is failing to answer
before the retransmission shows up as a timeout elsewhere.
Note
A few of the smaller MME interfaces use the abbreviated forms in, out and in_drop rather
than the full words. When writing a query that must cover every interface, match with
direction=~"in.*" and direction=~"out.*" rather than listing exact values.
type⚓︎
request and response cover most traffic. Protocols with richer exchanges add their own values:
S1AP uses indication, command, complete, confirm, failure, notify, ack and others; NAS
uses accept, reject, complete, fail and command. Where a protocol has no request/response
structure for a message, type is msg.
cause⚓︎
cause carries the protocol's own result, converted to a lowercase name — request_accepted,
user_unknown, system_failure. It is present only on responses, so a query that groups by cause
should filter to type="response" to avoid counting requests into an empty bucket.
Note
On the service-based interface the cause label holds the HTTP status code as a string
("200", "404"), because that is the result the protocol defines. Treat it as a name, not a
number — PromQL will not order it numerically.
Per-protocol reference⚓︎
Labels carried by each protocol counter, as deployed:
| Protocol | Metric | direction |
message |
type |
cause |
|---|---|---|---|---|---|
| PFCP (N4) | xcore_smf_pfcp_total |
● | ● | ● | ● |
| GTP-C v2 (S5/S8, S11) | xcore_smf_gtp_2_total |
● | ● | ● | ● |
| GTP-C v1 (Gn/Gp) | xcore_smf_gtp_1_total |
● | ● | ● | ● |
| SBI (N11) | xcore_smf_n11_total |
● | ● | ● | ● |
| S1AP | xcore_mme_s1ap_total |
● | ● | ● | |
| NAS | xcore_mme_nas_total |
● | ● | ● | |
| GTP-C v2 (MME) | xcore_mme_gtpv2_total |
● | ● | ● | |
| GTP-C v1 (MME) | xcore_mme_gtpv1_total |
● | ● | ● | |
| Diameter (MME) | xcore_mme_diameter_total |
● | ● | ● | |
| S6a/S6d | xcore_hss_s6_messages_total |
● | ● | ● | |
| Other Diameter interfaces | xcore_hss_<interface>_messages_total |
● | ● | ● | |
| MAP | xcore_hss_map_messages_total |
● | ● | ● |
The HSS family covers every Diameter reference point the platform implements — s6, s6b, s6c,
s6t, s6mn, s13, sh, slh, swm, swx, staswa, cxdx and zh — plus map and sip.
They share one shape, so a query written for one works for all of them by changing the interface.
Where a cell is blank, that dimension is not currently reported for that protocol: the MME's
counters do not carry cause, and the HSS's do not carry direction (the message name and type
together imply it on those interfaces).
Message and cause vocabularies⚓︎
The values are the protocol's own message and result names, lowercased with words separated by underscores. Representative sets:
message: association_setup, heartbeat, session_establishment, session_modification,
session_deletion, session_report
cause: request_accepted, request_rejected, mandatory_ie_incorrect,
session_context_not_found, system_failure
message: create_session, modify_bearer, modify_bearer_cmd, delete_session,
create_bearer, update_bearer, delete_bearer, release_access_bearers,
downlink_data_notif, downlink_data_notif_ack, echo
cause: request_accepted, request_rejected_(reason_not_specified), context_not_found,
imsi/imei_not_known, invalid_message_format, no_resources_available,
unable_to_page_ue, system_failure
message: authentication_information, update_location, cancel_location,
insert_subscriber_data, delete_subscriber_data, purge_ue, notification, reset,
routing_info
cause: success, user_unknown, unknown_eps_subscription, rat_not_allowed,
roaming_not_allowed, authentication_data_unavailable, authentication_rejected,
authorization_rejected, diameter_too_busy, missing_avp, unable_to_comply,
system_error
message: s1_setup, initial_uemsg, initial_ctxt_setup, uectxt_mod, uectxt_rel,
e_rabsetup, e_rabmod, e_rabrel, handover, path_switch_req, paging,
uplink_nastrnspt, downlink_nastrnspt, reset, error
type: request, response, command, complete, confirm, failure, indication,
notify, ack, required, preparation_failure
message: att, det, tau, auth, auth_fail, ident, sec_mod, service,
pdn_conn, pdn_disconn, act_def_eps_brr_ctx, act_ded_eps_brr_ctx,
deact_eps_brr_ctx, mod_eps_brr_ctx, uplink_sms, downlink_sms
type: request, accept, reject, complete, fail, command, msg
message: smcontextcreate, smcontextupdate, smcontextrelease
cause: the HTTP status code as a string — 200, 201, 404, 500
Additional labels on protocol metrics⚓︎
smf_id appears on SMF counters, identifying which SMF instance within the site reported the
metric. Aggregate over it unless you are specifically comparing instances:
sum without (smf_id) (rate(xcore_smf_pfcp_total{type="request"}[5m]))
Peer identity is carried by nfnode and nfnodeip rather than by a dedicated peer label, and the
interface is part of the metric name rather than a label.
Writing queries against these labels⚓︎
A few patterns cover most needs.
Per-site message rate for one interface:
sum by (site) (rate(xcore_smf_pfcp_total{message="session_establishment", type="request"}[5m]))
Failure ratio on an interface, as a proportion of responses:
sum by (site) (rate(xcore_hss_s6_messages_total{type="response", cause!="success"}[5m]))
/
sum by (site) (rate(xcore_hss_s6_messages_total{type="response"}[5m]))
One customer's sites only, using the stable identifier:
sum by (site) (rate(xcore_mme_nas_total{customerId=~".*/v1/customers/20806", message="att"}[5m]))
Retransmissions, which usually indicate an unresponsive peer:
sum by (site, nfnode) (rate(xcore_mme_diameter_total{direction="outbound_retry"}[5m]))
Tip
Always aggregate away instance and nfnode unless you need them. A site with several
instances of a function reports one series per instance, and a query that keeps them produces a
graph per instance rather than the per-site figure you probably wanted.
Conventions for new instrumentation⚓︎
If you are adding a metric to an Expeto component, follow the pattern above rather than inventing a new one. In particular:
- Put the varying part in a label, not in the metric name. One
..._totalwith amessagelabel, not one metric per message. Metric names that encode the outcome cannot be aggregated, and every dashboard has to be rewritten when a new message type appears. - Use the vocabularies on this page.
directionisinbound/outbound, notrx/txorin/out;typeisrequest/response; success and failure belong incause, not in the metric name. - Name the protocol's own values, don't renumber them. A
causeis the protocol's result name, lowercased — not an internal enum ordinal. - Keep cardinality bounded. Labels take values from a fixed, protocol-defined set. An address, a session identifier or a subscriber identity must never become a label value.
- Let the platform add identity. Do not emit
site,customeror their identifiers yourself; they are attached centrally, and a locally-emitted copy will win over the correct value and be wrong the moment a Site is renamed.
Related pages⚓︎
- xView Architecture — where each label is attached along the collection path
- xCore Metrics — the metrics these labels appear on
- Custom Alerts and Rules — using these labels in your own alerts