How it works
Your service keeps the exporter it has today and adds one more. The second exporter sends the same spans tohttps://otlp.lumenstat.com with an x-scf-ingest-key header. Your APM stores full traces as before. Lumenstat aggregates its copy and discards it.
- Tenant stamping. The collector deletes any
scf.ingest_keyresource attribute the client sent, then copies thex-scf-ingest-keyrequest header onto the resource. This runs before aggregation, so spans from two projects are never merged into one series. - spanmetrics. The collector’s spanmetrics connector turns spans into a request count and a latency histogram per service, route attribute, method and status code, and flushes them every 15 seconds as deltas. The traces pipeline has no other exporter, so the spans go nowhere after that. Logs go to a no-op exporter.
- Writer. The writer keeps only the accepted HTTP latency histograms, and of the span-derived ones only those from server spans. It maps the ingest key to your project and ignores any tenant field inside the payload. It normalizes the route, caps each service at 500 routes, moves latency onto fixed millisecond buckets and adds the result to one row per minute.
- Dashboard. The API page shows requests, 5xx rate, p50 and p95 latency, and a table per route. Setup shows whether data is arriving.
apps/collector/config.yaml. The writer is in apps/writer. How tenants are kept apart is covered in Tenant isolation.
What Lumenstat stores
One row per project, service, route, method, status code, source and minute inscf_api.api_metric_minute. That row is everything Lumenstat keeps about your API.
What Lumenstat does not store
- Trace IDs, span IDs, span names, span events, exceptions and links.
- Span attributes other than the route, method and status fields above. That includes client IP addresses (
client.address,network.peer.address), user agents, query strings (url.query), headers, request and response bodies, and database statements. - Resource attributes other than
service.name, such as host names, process IDs and cloud metadata. - Logs, and metrics other than the three accepted HTTP latency series.
Issue an ingest key
Each project issues its own keys on the Setup page of the dashboard.1
Open Setup
Sign in at app.lumenstat.com, open your project and select Setup.
2
Issue a key
In the API (optional) card, select Issue an ingest key. The first key also creates your project’s API tenant. Only the project owner, a project manager or an SCF operator can issue keys.
3
Copy it now
The key starts with
scf_ingest_ and is shown once. Lumenstat stores only its SHA-256 hash and cannot show it again. Copy settings copies two environment variable lines with the key filled in.4
Store it as a secret
Keep the key in your secret store, not in source control. Anyone who holds it can send data that counts toward your project.
The dashboard cannot revoke an ingest key yet. If a key leaks, contact an SCF operator.
Node.js
Express or NestJS with the OpenTelemetry Node SDK and a second span exporter.
Collector and other languages
Go, Python, Rust, Java, or any service behind an OpenTelemetry Collector.
Limits
- Sampling lowers the counts. Lumenstat counts the spans it receives. If your SDK or Collector keeps 10% of traces, Lumenstat sees 10% of requests. Send Lumenstat an unsampled copy through a separate Collector pipeline, as shown in Send only what Lumenstat reads.
- Spans arrive in full. Lumenstat stores only the fields above, but the collector receives whole spans and holds them in memory until it aggregates them. In the current pilot
otlp.lumenstat.comis served through Cloudflare, which sees the requests in transit. To keep attributes inside your network, trim them in your own Collector before export. - Keys are checked after aggregation. The collector does not validate the ingest key. A missing or wrong key still gets a success response, and the writer then drops the data. Use Setup’s Is data arriving? check to confirm.
- Only HTTP server spans count. Client, internal, producer and consumer spans are dropped. A server span without HTTP attributes, such as a gRPC server span, is counted under route
{unknown}, method_OTHERand status0. - Latency has bucket resolution. Percentiles are interpolated inside fixed buckets. A request slower than 10 seconds lands in the overflow bucket, and a percentile that falls there reads 10,000 ms.
- No retention job yet. Per-minute rows are not deleted automatically today.
Planned for Milestone 2: an attribute allowlist at the collector, ingest keys checked at the edge instead of only in the writer, and hourly and daily rollups with retention jobs. The draft privacy statement sets per-minute rows to 30 days and rollups to 36 months. That statement is a draft for counsel review. See the roadmap.