Skip to content

Metrics export

Included free on every install, scheduled export included. A metrics destination of a tenant's own needs a license with the multitenant-customization feature. See pricing.

Metrics export sends your instance's request, database pool and runtime metrics to the monitoring backend you already run, every 30 seconds by default. It also serves a scrape route where a super admin reads every metric and a tenant admin reads only their own tenant's request metrics.

There are three ways to get the same metrics out.

WayWho reads itUse it when
Prometheus scrapes GET /api/admin/metricsPrometheus, with METRICS_TOKEN or a super admin tokenYou run Prometheus and it can reach the instance. METRICS_TOKEN is in the configuration reference.
Scrape GET /api/admin/telemetry/metricsA super admin sees everything, a tenant admin sees their tenantEach tenant needs its own view.
An exporter pushes on a scheduleYour backendThe backend cannot scrape the instance, or it is a hosted service.
A tenant destination pushes on the same scheduleThe tenant's own collectorA tenant wants its numbers in its own monitoring. Needs multitenant-customization.

Every export carries the same metrics:

  • Process and Go runtime metrics.
  • Database pool metrics, lyeve_db_pool_*.
  • Request metrics: lyeve_requests_total, lyeve_request_duration_seconds and lyeve_requests_in_flight. Each carries a tenant label with the tenant slug, or - when the request named no tenant.
  • Content cache counters, lyeve_content_list_cache_hits_total and lyeve_content_list_cache_misses_total.
  • lyeve_build_info, labeled with version and database dialect, lyeve_plugin_count and lyeve_runtime_seconds.

Traces are not part of this feature. To send traces, see tracing under load.

You need an admin token in TOKEN. The quickstart shows how to get one.

  1. Scrape the request metrics:

    Terminal window
    curl -s http://localhost:3001/api/admin/telemetry/metrics \
    -H "Authorization: Bearer $TOKEN" | grep '^lyeve_requests_total'
    lyeve_requests_total{code="2xx",method="GET",plugin="core",tenant="default"} 27
    lyeve_requests_total{code="4xx",method="GET",plugin="core",tenant="default"} 3
  2. List the exporters. On a fresh install none is configured:

    Terminal window
    curl http://localhost:3001/api/admin/telemetry/exporters \
    -H "Authorization: Bearer $TOKEN"
    { "data": [], "limit": 50, "offset": 0, "total_count": 0 }
  3. Configure a backend. Set METRICS_PUSHGATEWAY_URL to your Pushgateway, such as https://pushgateway.example.com, and restart the instance.

  4. Export once without waiting for the schedule:

    Terminal window
    curl -X POST http://localhost:3001/api/admin/telemetry/exporters/pushgateway/export \
    -H "Authorization: Bearer $TOKEN"
    { "status": "ok", "message": "export triggered for pushgateway" }

    Without a configured Pushgateway the answer is 404 with exporter not found.

  5. In the admin console, open Insight > Observability > Telemetry to see each exporter's health.

NameTransportWhat is sent
pushgatewayHTTP PUT /metrics/job/<job>, Prometheus text format, optional basic authEvery metric, labels intact. Each push replaces the job's group.
otlpOTLP over gRPCGauges as gauges, counters as cumulative sums, histograms as cumulative histograms, summaries as summaries. Labels become attributes.
newrelicOTLP over HTTP, api-key headerThe same as otlp, posted to the region's /v1/metrics.
statsdDogStatsD over UDPGauges as g. Counters as c, with the change since the last export. A histogram as .sum, .count and one .bucket gauge per bound tagged le:. A summary as .sum, .count and one gauge per quantile tagged quantile:. Labels become tags. Packets are at most 8 KiB.

A backend runs when its address or key is set. Each one runs on its own: one that fails is marked unhealthy and turns healthy again on its next successful export, without affecting the others.

Exporters refuse loopback, link-local and private addresses. A collector on your own network, such as 10.0.4.12:4317, needs its range in METRICS_ALLOWED_PRIVATE_NETWORKS, for example 10.0.4.0/24. Until then a manual export answers 422 and names the setting.

With multitenant-customization, a tenant admin saves one destination for the tenant, and every export also pushes it the series labeled with that tenant and nothing else, the same samples the tenant's scrape shows:

Terminal window
curl -X PUT http://localhost:3001/api/admin/telemetry/destination \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"kind": "otlp", "url": "https://otlp.example.com/v1/metrics", "headers": {"Authorization": "Bearer <collector key>"}}'
FieldMeaning
kindotlp, sent as OTLP over HTTP to the URL exactly as saved, or pushgateway, sent to <url>/metrics/job/lyeve-core/tenant/<slug>.
urlAn http or https URL of at most 2,048 characters, with no credentials in it. Send those as a header.
headersUp to 16 headers, 8 KiB in all. Left out, the stored headers stay while the URL keeps its scheme and host. {} sends none.
  • The URL and the headers are encrypted at rest. The answer, like GET on the same path, shows the kind, the url, the header_names alone and the health of the last push, beside licensed.
  • A destination on a private or internal network is refused, and METRICS_ALLOWED_PRIVATE_NETWORKS never opens one for a tenant.
  • A destination moved to another host must send its headers again, so a stored key never follows a URL somebody else chose.
  • DELETE removes the destination and stays free. If the license lapses, the stored destination keeps receiving, and a new or changed one answers 402.

GET /api/admin/telemetry/exporters lists each configured backend:

{
"data": [
{ "name": "pushgateway", "healthy": true, "last_export": "2026-10-01T09:40:00Z", "exports": 120, "failures": 0 }
],
"limit": 50,
"offset": 0,
"total_count": 1
}

A backend that has failed also shows last_failure, last_error and last_error_class. Addresses and URLs in the error text are redacted.

Set these as environment variables or in the admin console. They are read when the instance starts, so restart it after a change.

VariableWhat it doesDefault
METRICS_EXPORT_INTERVALHow often to export, such as 30s or 1m. 0 turns the schedule off and leaves manual export.30s
METRICS_ENABLED_EXPORTERSComma-separated backends to run. Empty or all runs every backend that is configured.all
METRICS_PUSHGATEWAY_URLPushgateway base URL.unset
METRICS_PUSHGATEWAY_JOBPushgateway job name. Slashes and .. are refused.lyeve-core
METRICS_PUSHGATEWAY_USERNAME, METRICS_PUSHGATEWAY_PASSWORDPushgateway basic auth.unset
METRICS_OTLP_ENDPOINTOTLP gRPC endpoint as host:port.unset
METRICS_OTLP_INSECUREConnect to the OTLP endpoint without TLS.false
METRICS_OTLP_HEADERSComma-separated key=value headers for OTLP.unset
METRICS_STATSD_ADDRESSDogStatsD address as host:port.unset
METRICS_STATSD_PREFIXPrefix for every StatsD metric name.lyeve
METRICS_STATSD_TAGSComma-separated tags sent with every StatsD metric.unset
METRICS_NEWRELIC_API_KEYNew Relic license key.unset
METRICS_NEWRELIC_ENDPOINTNew Relic OTLP URL for your region. For the EU use https://otlp.eu01.nr-data.net:4318.https://otlp.nr-data.net:4318
METRICS_ALLOWED_PRIVATE_NETWORKSComma-separated CIDR ranges or addresses an exporter may reach.unset

Metrics export runs on every install. If you set LYEVE_PLUGINS to choose which features start, include telemetry in it. See licensing and tiers.

MethodPathWhoPurpose
GET/api/admin/telemetry/metricsAdminPrometheus text format. A super admin gets every metric, a tenant admin only the samples labeled with their tenant.
GET/api/admin/telemetry/exportersSuper adminHealth of each backend, with limit (default 50, at most 500) and offset.
POST/api/admin/telemetry/exporters/{name}/exportSuper adminExport to one backend now.
GET/api/admin/telemetry/destinationAdminThe tenant's own destination, or null, and licensed.
PUT/api/admin/telemetry/destinationAdminSave it: kind, url, headers. Needs multitenant-customization.
DELETE/api/admin/telemetry/destinationAdminRemove it. 204.
StatusMessageCause
402payment_required, naming feature:multitenant_customizationA new or changed tenant destination without the license.
422kind must be otlp or pushgateway, url must be an absolute http or https URL, url must not carry credentials, send them as a header, at most 16 headersThe destination is not valid.
422the destination moved to another host, send its headers again, code telemetry.headers_requiredA new host with the headers left out.
422the destination is on a network this instance does not send toA private or internal address.
422the instance has no encryption key to seal the destination withSet ENCRYPTION_KEY.
403instance-wide metrics need super_adminThe caller is not a super admin and the request named no tenant.
404exporter not foundNo backend by that name is configured.
422export target is on a private network the guard refuses; list it under metrics_allowed_private_networksAdd the range to METRICS_ALLOWED_PRIVATE_NETWORKS.
429export cooldown active; minimum 5 seconds between manual exportsWait five seconds between manual exports to one backend.
502export target did not accept the push; see the exporter's health rowThe backend could not be reached or refused the data.
503metrics not initializedThe instance is still starting.