Skip to content
Aa

Origin performance

Origin metrics show the request path from the public network to the configured origin. Use the destination node’s upstream metrics for the service receiving requests. The edge’s data.metric.data describes the path from the selected source to that destination. Compare rates and errors with response latency, server round-trip time (RTT), and data transfer time. A high response latency alone does not identify an application bottleneck; server RTT and transfer time help explain where time was spent.

Use XCSH_NAMESPACE, the discovered XCSH_VIRTUAL_HOST, and the fixed two-hour XCSH_START_TIME–XCSH_END_TIME window with five-minute buckets. Use VHOST and SERVICE grouping to discover both ends of the request edge. The demo pool contains one public-IP origin. Match its configured address exactly; a service label or the load-balancer name alone is insufficient.

  1. Read the configured default pool and its unique public IP.

    Terminal window
    XCSH_ORIGIN_POOL="$(jq -er '
    [.spec.default_route_pools[]?.pool.name] | unique
    | if length == 1 then .[0] else error("Expected one origin pool") end
    ' <<<"$XCSH_LB_JSON")"
    XCSH_POOL_JSON="$(curl --silent --show-error --fail-with-body --max-time 60 \
    --header "Authorization: APIToken <XCSH_API_TOKEN>" \
    "<XCSH_API_URL>/api/config/namespaces/<XCSH_NAMESPACE>/origin_pools/${XCSH_ORIGIN_POOL}")"
    XCSH_ORIGIN_IP="$(jq -er '
    [.spec.origin_servers[]?.public_ip.ip // empty] | unique
    | if length == 1 then .[0] else error("Expected one public-IP origin") end
    ' <<<"$XCSH_POOL_JSON")"
  2. Discover the source and destination services.

    Terminal window
    XCSH_REQUEST="$(jq -nc --arg ns "<XCSH_NAMESPACE>" \
    --arg start "$XCSH_START_TIME" --arg end "$XCSH_END_TIME" \
    --arg vh "<XCSH_VIRTUAL_HOST>" '{
    namespace: $ns, start_time: $start, end_time: $end,
    step: "5m", range: "5m", group_by: ["VHOST", "SERVICE"],
    label_filter: [{label: "LABEL_VHOST", op: "EQ", value: $vh}],
    field_selector: {node: {metric: {upstream: ["HTTP_REQUEST_RATE"]}},
    edge: {metric: {types: ["HTTP_REQUEST_RATE"]}}}
    }')"
    XCSH_GRAPH_JSON="$(curl --silent --show-error --fail-with-body --max-time 60 \
    --request POST \
    --header "Authorization: APIToken <XCSH_API_TOKEN>" \
    --header 'Content-Type: application/json' \
    --data-binary "$XCSH_REQUEST" \
    "<XCSH_API_URL>/api/data/namespaces/<XCSH_NAMESPACE>/graph/service")"
    XCSH_GRAPH_DESTINATION="$(jq -er --arg vh "<XCSH_VIRTUAL_HOST>" \
    --arg ip "<XCSH_ORIGIN_IP>" '
    [.data.edges[]? | select(.dst_id.vhost == $vh)
    | .dst_id.service | select(. == ("S:" + $ip))] | unique
    | if length == 1 then .[0] else error("No unique configured origin edge") end
    ' <<<"$XCSH_GRAPH_JSON")"
    XCSH_GRAPH_SOURCE="$(jq -er --arg vh "<XCSH_VIRTUAL_HOST>" \
    --arg dst "$XCSH_GRAPH_DESTINATION" '
    [.data.edges[]? | select(.dst_id.vhost == $vh and .dst_id.service == $dst)
    | .src_id.service] | unique
    | if length == 1 then .[0] else error("Expected one source service") end
    ' <<<"$XCSH_GRAPH_JSON")"
    export XCSH_ORIGIN_POOL XCSH_ORIGIN_IP XCSH_GRAPH_SOURCE XCSH_GRAPH_DESTINATION
    jq -n --arg source "$XCSH_GRAPH_SOURCE" --arg destination "$XCSH_GRAPH_DESTINATION" \
    '{source: $source, destination: $destination, configured_origin_match: true}'

Captured 2026-10-06T03:13:41Z; HTTP 200.

{
"source": "<XCSH_GRAPH_SOURCE>",
"destination": "<XCSH_GRAPH_DESTINATION>",
"configured_origin_match": true
}

The origin address is returned as a service identity prefixed with S:. The source is the public network identity. These commands deliberately stop if the configured origin cannot be matched uniquely. Other pool types or multiple origins need their own matching procedure.

  1. Request node and edge metrics with service identities retained.

    Terminal window
    XCSH_REQUEST="$(jq -nc --arg ns "<XCSH_NAMESPACE>" --arg start "$XCSH_START_TIME" \
    --arg end "$XCSH_END_TIME" --arg vh "<XCSH_VIRTUAL_HOST>" '{
    namespace: $ns, start_time: $start, end_time: $end,
    step: "5m", range: "5m", group_by: ["VHOST", "SERVICE"],
    label_filter: [{label: "LABEL_VHOST", op: "EQ", value: $vh}],
    field_selector: {
    node: {metric: {upstream: [
    "HTTP_REQUEST_RATE", "HTTP_ERROR_RATE", "HTTP_ERROR_RATE_4XX",
    "HTTP_ERROR_RATE_5XX", "HTTP_RESPONSE_LATENCY",
    "REQUEST_THROUGHPUT", "RESPONSE_THROUGHPUT", "REQUEST_TO_ORIGIN_RATE",
    "CLIENT_RTT", "SERVER_RTT", "HTTP_SERVER_DATA_TRANSFER_TIME"
    ]}},
    edge: {metric: {types: [
    "HTTP_REQUEST_RATE", "HTTP_ERROR_RATE", "HTTP_ERROR_RATE_4XX",
    "HTTP_ERROR_RATE_5XX", "HTTP_RESPONSE_LATENCY",
    "REQUEST_THROUGHPUT", "RESPONSE_THROUGHPUT", "REQUEST_TO_ORIGIN_RATE",
    "CLIENT_RTT", "SERVER_RTT", "HTTP_SERVER_DATA_TRANSFER_TIME"
    ]}}
    }
    }')"
  2. Query the matched node and edge.

    Terminal window
    XCSH_ORIGIN_JSON="$(curl --silent --show-error --fail-with-body --max-time 60 \
    --request POST \
    --header "Authorization: APIToken <XCSH_API_TOKEN>" \
    --header 'Content-Type: application/json' \
    --data-binary "$XCSH_REQUEST" \
    "<XCSH_API_URL>/api/data/namespaces/<XCSH_NAMESPACE>/graph/service")"
    jq -er --arg vh "<XCSH_VIRTUAL_HOST>" --arg src "<XCSH_GRAPH_SOURCE>" \
    --arg dst "<XCSH_GRAPH_DESTINATION>" '
    def summary: {type, unit, points: (.value.raw | length),
    latest: (.value.raw[-1] // null)};
    {step, source: $src, destination: $dst,
    node: ([.data.nodes[]? | select(.id.vhost == $vh and .id.service == $dst)
    | .data.metric.upstream[]? | summary] | sort_by(.type)),
    edge: ([.data.edges[]? | select(.dst_id.vhost == $vh and
    .src_id.service == $src and .dst_id.service == $dst)
    | .data.metric.data[]? | summary] | sort_by(.type))}
    ' <<<"$XCSH_ORIGIN_JSON"

Captured 2026-10-06T03:13:42Z; HTTP 200.

{
"step": "5m",
"source": "<XCSH_GRAPH_SOURCE>",
"destination": "<XCSH_GRAPH_DESTINATION>",
"node": [
{
"type": "CLIENT_RTT",
"unit": "UNIT_SECONDS",
"points": 12,
"latest": {
"timestamp": 1791255900,
"value": "0.0010500000000000002",
"trend_value": null
}
},
{
"type": "HTTP_ERROR_RATE",
"unit": "UNIT_ERRORS_PER_SECOND",
"points": 5,
"latest": {
"timestamp": 1791253200,
"value": "0",
"trend_value": null
}
},
{
"type": "HTTP_ERROR_RATE_4XX",
"unit": "UNIT_ERRORS_PER_SECOND",
"points": 5,
"latest": {
"timestamp": 1791253200,
"value": "0",
"trend_value": null
}
},
{
"type": "HTTP_REQUEST_RATE",
"unit": "UNIT_REQUESTS_PER_SECOND",
"points": 25,
"latest": {
"timestamp": 1791256200,
"value": "0.02860921837322622",
"trend_value": null
}
},
{
"type": "HTTP_RESPONSE_LATENCY",
"unit": "UNIT_SECONDS",
"points": 12,
"latest": {
"timestamp": 1791255900,
"value": "0.8850000000000001",
"trend_value": null
}
},
{
"type": "HTTP_SERVER_DATA_TRANSFER_TIME",
"unit": "UNIT_SECONDS",
"points": 12,
"latest": {
"timestamp": 1791255900,
"value": "0",
"trend_value": null
}
},
{
"type": "REQUEST_THROUGHPUT",
"unit": "UNIT_BITS_PER_SECOND",
"points": 25,
"latest": {
"timestamp": 1791256200,
"value": "82.46763041554156",
"trend_value": null
}
},
{
"type": "REQUEST_TO_ORIGIN_RATE",
"unit": "UNIT_REQUESTS_PER_SECOND",
"points": 25,
"latest": {
"timestamp": 1791256200,
"value": "0.02860921837322622",
"trend_value": null
}
},
{
"type": "RESPONSE_THROUGHPUT",
"unit": "UNIT_BITS_PER_SECOND",
"points": 25,
"latest": {
"timestamp": 1791256200,
"value": "153.03037615105956",
"trend_value": null
}
},
{
"type": "SERVER_RTT",
"unit": "UNIT_SECONDS",
"points": 12,
"latest": {
"timestamp": 1791255900,
"value": "0.43500000000000005",
"trend_value": null
}
}
],
"edge": [
{
"type": "CLIENT_RTT",
"unit": "UNIT_SECONDS",
"points": 12,
"latest": {
"timestamp": 1791255900,
"value": "0.0010500000000000002",
"trend_value": null
}
},
{
"type": "HTTP_ERROR_RATE",
"unit": "UNIT_ERRORS_PER_SECOND",
"points": 5,
"latest": {
"timestamp": 1791253200,
"value": "0",
"trend_value": null
}
},
{
"type": "HTTP_ERROR_RATE_4XX",
"unit": "UNIT_ERRORS_PER_SECOND",
"points": 5,
"latest": {
"timestamp": 1791253200,
"value": "0",
"trend_value": null
}
},
{
"type": "HTTP_REQUEST_RATE",
"unit": "UNIT_REQUESTS_PER_SECOND",
"points": 25,
"latest": {
"timestamp": 1791256200,
"value": "0.02860921837322622",
"trend_value": null
}
},
{
"type": "HTTP_RESPONSE_LATENCY",
"unit": "UNIT_SECONDS",
"points": 12,
"latest": {
"timestamp": 1791255900,
"value": "0.8850000000000001",
"trend_value": null
}
},
{
"type": "HTTP_SERVER_DATA_TRANSFER_TIME",
"unit": "UNIT_SECONDS",
"points": 12,
"latest": {
"timestamp": 1791255900,
"value": "0",
"trend_value": null
}
},
{
"type": "REQUEST_THROUGHPUT",
"unit": "UNIT_BITS_PER_SECOND",
"points": 25,
"latest": {
"timestamp": 1791256200,
"value": "82.46763041554156",
"trend_value": null
}
},
{
"type": "REQUEST_TO_ORIGIN_RATE",
"unit": "UNIT_REQUESTS_PER_SECOND",
"points": 25,
"latest": {
"timestamp": 1791256200,
"value": "0.02860921837322622",
"trend_value": null
}
},
{
"type": "RESPONSE_THROUGHPUT",
"unit": "UNIT_BITS_PER_SECOND",
"points": 25,
"latest": {
"timestamp": 1791256200,
"value": "153.03037615105956",
"trend_value": null
}
},
{
"type": "SERVER_RTT",
"unit": "UNIT_SECONDS",
"points": 12,
"latest": {
"timestamp": 1791255900,
"value": "0.43500000000000005",
"trend_value": null
}
}
]
}

Both arrays must contain metric points before interpreting origin performance. An absent error series is unavailable telemetry, not proof of zero errors. Rate units are per second, throughput is bits per second, and returned latency, RTT, and transfer-time units are preserved. A measured transfer time of "0" is a returned value; it does not mean the field was absent.