Telemetry and Observability

For: Platform operators and SREs monitoring Axemere Gateway in production.

Operations Overview | Approval Workflows | Quarantine | Risk Scoring | CP Connectivity | Telemetry

Axemere Gateway exposes four observability surfaces: a health endpoint, Prometheus metrics, a dashboard API, and SIEM event export. This guide covers all four, plus the anonymous usage telemetry that gateways send to Axemere.

Table of Contents


Gateway Health Endpoint

GET /healthz: no authentication required.

curl -s http://localhost:7080/healthz | jq .
{
  "status": "ok",
  "node_id": "gw-node-prod-01",
  "connectors": [
    {"id": "openai", "version": "1.0.0", "healthy": true},
    {"id": "anthropic", "version": "1.0.0", "healthy": true}
  ],
  "cp_status": "connected",
  "bundle_id": "01955f3e-0000-7abc-8def-000000000001",
  "bundle_version": "2.1.0",
  "last_hash_submit_at": "2026-03-12T14:30:00Z"
}
FieldValuesDescription
status"starting", "ok""starting" during MVGC_HEALTHZ_STARTUP_GRACE (default 10s); then "ok"
node_idstringThis gateway's node identifier
connectors[].healthyboolWhether the connector can reach its upstream (last health check result)
cp_status"connected", "offline", "unconfigured"Control plane connection state
bundle_idstringActive policy bundle ID
last_hash_submit_atRFC3339Last successful record hash submission to CP ledger

Use /healthz as the liveness and readiness probe target in Kubernetes:

livenessProbe:
  httpGet:
    path: /healthz
    port: 7080
  initialDelaySeconds: 15
readinessProbe:
  httpGet:
    path: /healthz
    port: 7080
  initialDelaySeconds: 5

Prometheus Metrics

Prometheus metrics are available at GET /metrics when MVGC_METRICS_ENABLED=true (the default).

curl -s http://localhost:7080/metrics | grep ^mvgc_
mvgc_requests_total{action_type="ai.infer",decision="allow",org_id="org-001"} 1842
mvgc_request_duration_ms_bucket{action_type="ai.infer",decision="allow",le="100"} 1651
mvgc_risk_score{org_id="org-001"} 0.15
mvgc_approvals_pending 0
mvgc_pending_hash_submissions 0
mvgc_auth_failures_total{reason="invalid_key",org_id=""} 3

Metrics Reference

MetricTypeLabelsDescription
mvgc_requests_totalCounteraction_type, decision, org_idTotal policy decisions
mvgc_request_duration_msHistogramaction_type, decisionEnd-to-end latency in ms (buckets: 5, 10, 25, 50, 100, 250, 500, 1000)
mvgc_upstream_latency_secondsHistogramproviderTime waiting for upstream AI provider response
mvgc_auth_failures_totalCounterreason, org_idAuth failures before policy evaluation
mvgc_auth_key_lookup_totalCounterresultAPI key cache lookup results (hit, miss, fallback)
mvgc_risk_scoreGaugeorg_idLast composite risk score per org (0.0–1.0)
mvgc_risk_signalsCountersignal_type, org_idRisk signal activations per type per org
mvgc_approvals_pendingGaugeOpen approval requests awaiting operator decision
mvgc_rate_limit_hitsCounterorg_idRequests rejected by rate limiter per org
mvgc_quarantine_totalCounterorg_idQuarantine decisions per org
mvgc_policy_deny_totalCounterorg_id, reason_codePolicy deny decisions per reason code
mvgc_org_overage_enforced_totalCounterorg_idRequests denied due to monthly spend overage
mvgc_pending_hash_submissionsGaugeRecord hashes queued for CP submission (non-zero means CP offline)
mvgc_config_sync_lag_secondsHistogramLag between config event and local processing (managed mode)

mvgc_auth_failures_total reasons:

ReasonDescription
missing_headerRequest has no Authorization header
invalid_keyKey not found or hash mismatch
revokedKey has been explicitly revoked
expiredKey TTL elapsed
suspendedOrg is suspended

Key Alerts to Configure

AlertConditionSeverityAction
High error raterate(mvgc_requests_total{decision="deny"}[5m]) / rate(mvgc_requests_total[5m]) > 0.1WarningInvestigate recent policy changes
Auth failures spikerate(mvgc_auth_failures_total[5m]) > 5WarningCheck for credential rotation or client misconfiguration
CP offlinemvgc_pending_hash_submissions > 0 for > 5mCriticalCheck CP connectivity: see CP Connectivity
Approvals backlogmvgc_approvals_pending > 10WarningOps team has pending approvals to review
Elevated risk scoremvgc_risk_score > 0.6 for > 2mWarningReview active risk signals
p99 latencyhistogram_quantile(0.99, rate(mvgc_request_duration_ms_bucket[5m])) > 1000WarningCheck upstream provider latency

Example Prometheus Scrape Config

scrape_configs:
  - job_name: mvgc-gateway
    static_configs:
      - targets: ['gateway-host:7080']
    metrics_path: /metrics
    scrape_interval: 15s

Dashboard API

The dashboard API provides aggregated summaries without a separate analytics stack. Both endpoints require the admin token.

Summary: total requests, allow/deny counts:

curl -s "http://localhost:7080/v1/dashboard/summary?org_id=org-001&from=2026-03-01T00:00:00Z&to=2026-03-12T00:00:00Z" \
  -H "MVGC-Admin-Token: $MVGC_ADMIN_TOKEN" | jq .
{
  "org_id": "org-001",
  "from": "2026-03-01T00:00:00Z",
  "to": "2026-03-12T00:00:00Z",
  "total_requests": 14203,
  "total_allowed": 13801,
  "total_denied": 402,
  "total_tokens_in": 8450000,
  "total_tokens_out": 3200000,
  "total_cost_usd": "1842.50"
}

Decision breakdown: counts grouped by decision type:

curl -s "http://localhost:7080/v1/dashboard/decisions?org_id=org-001" \
  -H "MVGC-Admin-Token: $MVGC_ADMIN_TOKEN" | jq .
[
  {"decision": "allow",            "count": 13801},
  {"decision": "deny",             "count": 387},
  {"decision": "rate_limit",       "count": 12},
  {"decision": "require_approval", "count": 3}
]

SIEM Event Export

The gateway streams events to external security systems via webhook and/or syslog. Configure one or both; events fan out to all configured exporters.

Event Types

Event typeWhen emittedKey fields
executionEvery action execution (allow, deny, rate_limit, etc.)Full ExecutionRecord including caller_ip, decision, attribution
approvalApproval request created, approved, or deniedapproval_id, decision, decided_by
quarantineQuarantine entry created or releasedquarantine_id, workload_id, reason
risk_alertComposite risk score ≥ 0.7risk_score, signals, org/workload context

risk_alert events are emitted before any policy decision; they fire purely on score threshold. This lets your SIEM react to elevated risk patterns even when no quarantine or require_approval rule has fired.

Webhook Export

Events are POST'd as JSON to your configured URL. Retried up to 3 times with exponential backoff on failure:

export MVGC_EXPORT_WEBHOOK_URL=https://siem.example.com/ingest
export MVGC_EXPORT_WEBHOOK_TOKEN=<bearer-token>   # optional

The gateway sends:

POST https://siem.example.com/ingest
Content-Type: application/json
Authorization: Bearer <MVGC_EXPORT_WEBHOOK_TOKEN>

{ ...event payload... }

Syslog Export

Events are sent as structured syslog messages. Supports TCP and UDP:

export MVGC_EXPORT_SYSLOG_ADDR=tcp://siem.example.com:514
# or
export MVGC_EXPORT_SYSLOG_ADDR=udp://siem.example.com:514

Event Payload Schema

All events share a common envelope:

{
  "event_type": "execution",
  "event_time": "2026-03-12T14:30:00Z",
  "org_id": "org-example-001",
  "workload_id": "wl-prod-app-1",
  "payload": { ... event-specific fields ... }
}

execution event payload:

The full ExecutionRecord document, including:

  • record_id, record_hash, decision, reason_codes
  • action_type, target, caller_id, caller_ip
  • Attribution: project_id, customer_id, account_id, labels
  • Metering: tokens_in, tokens_out, cost_usd

risk_alert event payload:

{
  "risk_score": 0.85,
  "signals": ["rate_spike", "cost_anomaly"],
  "request_rate": "45.2",
  "cost_rate": "0.82",
  "org_id": "org-example-001",
  "workload_id": "wl-prod-app-1",
  "caller_id": "service-abc"
}

Anonymous Usage Telemetry

Axemere Gateway sends anonymous aggregate usage data to Axemere. This data helps us understand how the gateway is used across deployments so we can prioritize improvements.

No request content, prompt text, API keys, or user-identifiable information is ever included. Each gateway generates a random instance ID at startup that is not persisted across restarts, so telemetry reports cannot be correlated across gateway restarts.

What is collected

Reports use the schema mvgc.telemetry.v2 and contain aggregate counters for a time window (typically one hour). Each report covers:

Per-provider breakdown: for every AI provider the gateway routed traffic to during the window:

FieldDescription
requestsTotal requests routed to this provider
tokens_inTotal input tokens across all allowed requests
tokens_outTotal output tokens across all allowed requests
modelsPer-model breakdown of requests and token counts
domainsCount of requests per upstream hostname
connection_typesCount of requests per connection type (direct_api, sdk_redirect, connect_proxy)

Top-level aggregates:

FieldDescription
decisionsRequest counts grouped by policy decision (allow, deny, rate_limit, require_approval)
action_typesRequest counts grouped by action type (ai.infer, http.request)
risk_alertsCount of composite risk score threshold crossings (≥ 0.7) during the window

Example report shape:

{
  "schema": "mvgc.telemetry.v2",
  "instance_id": "3f2a1b4c-...",
  "version": "v0.53.0",
  "window_start": "2026-05-11T10:00:00Z",
  "window_end": "2026-05-11T11:00:00Z",
  "providers": {
    "anthropic": {
      "requests": 142,
      "tokens_in": 284000,
      "tokens_out": 71000,
      "models": {
        "claude-sonnet-4-6": { "requests": 142, "tokens_in": 284000, "tokens_out": 71000 }
      },
      "domains": { "api.anthropic.com": 142 },
      "connection_types": { "direct_api": 142 }
    }
  },
  "decisions": { "allow": 140, "deny": 2 },
  "action_types": { "ai.infer": 142 },
  "risk_alerts": 0
}

Token counts are only included for allowed requests; denied requests consume no tokens and are not included in provider token totals.

What is not collected

  • Request or response content
  • Prompt text or completions
  • API keys or credentials of any kind
  • Caller identity, user names, or email addresses
  • IP addresses
  • Individual request timing or latency data
  • Any field from your policy configuration

Frequency and delivery

Telemetry is flushed once per hour by default. The Axemere ingest service may hint a different interval in the response; the gateway will never flush more frequently than the configured minimum (it can only be slowed down by the server, not sped up).

Telemetry is sent over HTTPS to gcp.telemetry.axemere.ai. There is no retry on delivery failure: if a flush fails, the counters for that window are dropped and the next window starts fresh. Failed submissions are logged at debug level:

time=2026-05-11T10:00:01Z level=DEBUG msg="telemetry POST failed" error="..."

Successful flushes are also logged at debug level. To see them, set MVGC_LOG_LEVEL=debug.

Self-hosted gateways connected to the CP send telemetry via the encrypted, authenticated gRPC channel to the CP instead of HTTP. The CP then forwards to the ingest service on your behalf.

Disabling telemetry

Self-hosted gateways connected to the CP can disable telemetry:

export MVGC_TELEMETRY_ENABLED=false

Note: Free gateways (self-hosted without CP connectivity) cannot disable anonymous telemetry; it is the only signal we have about the health of the Free Gateway population and is required to continue offering the free tier.


Environment Variables

VariableDefaultDescription
MVGC_METRICS_ENABLEDtrueEnable Prometheus metrics at /metrics
MVGC_EXPORT_WEBHOOK_URLWebhook URL for SIEM event export
MVGC_EXPORT_WEBHOOK_TOKENOptional Bearer token for webhook authentication
MVGC_EXPORT_SYSLOG_ADDRSyslog address: tcp://host:port or udp://host:port
MVGC_HEALTHZ_STARTUP_GRACE10sDuration to report "starting" before "ok"
MVGC_TELEMETRY_ENABLEDtrueDisable anonymous usage telemetry (CP-connected self-hosted gateways only; not available for free gateways)

Troubleshooting

SymptomLikely causeFix
/metrics returns 404MVGC_METRICS_ENABLED=falseSet to true and restart
No events at SIEM webhookMVGC_EXPORT_WEBHOOK_URL not set or unreachableVerify URL; check gateway logs for export errors
Syslog messages not arrivingWrong address format or firewall blockingUse tcp:// for reliable delivery; check port access
mvgc_pending_hash_submissions non-zeroCP offlineSee CP Connectivity
healthz reports "starting" indefinitelyStartup grace period exceeded due to init errorCheck gateway startup logs for DB connection or config errors
Dashboard API returns empty resultsWrong org_id or from/to windowVerify org_id matches the requests being made; check time range

See Also