Production,
in plain sight.

Iknos reads the logs and metrics of every app on your servers: one search over every line, errors grouped into issues, alert rules, and the trace of each request. Your apps keep writing the standard formats they already write.

filtersservice:beacon-apiLIVE
time · CESTlvlservicestmessage
16:42:28.064INFObeacon-api200GET /api/forecast/:city 200 in 321 ms
16:42:21.436INFObeacon-api200GET /api/ranking 200 in 114 ms
16:42:19.388INFObeacon-api200GET /api/forecast/:city 200 in 197 ms
16:42:10.055INFObeacon-api–declaration window rolled over
16:41:48.388INFObeacon-api200GET /api/declarations 200 in 55 ms
16:41:25.653DEBUGbeacon-api–forecast sync finished: 3398 cities
16:43:33.441ERRORbeacon-api–FetchError: forecast upstream request timed out after 8000 ms
6ca3eb80FetchErrorbeacon-api
count49
first seen9d ago
last seenjust now
occurrences · 48h
latest stack

FetchError: forecast upstream request timed out after 8000 ms

at ForecastClient.fetchCity (forecast/forecast-client.js:61)

at async ForecastService.refresh (forecast/forecast.service.js:118)

at async CityController.forecast (city/city.controller.js:42)

Alertsevaluated by the collector
PENDINGfor 00:01:12

rate(http_5xx[10m]) > 5%

beacon-api · 7.8%

beacon-apiECS · pino + @elastic/ecs-pino-format
pm2 id 1release 2026.09.01up 2h 24mdb 5msredis 2ms/health 200
throughput0.4req/s
error rate0.3%
p95 latency453ms
node runtime168MB heap
event loopdb pool
traceefbf68478.2 s total
The console

One rail. Every signal.

Pick a service and every view follows it. Each card plays a real piece of the console, with a demo fleet.

filtersservice:beacon-apiLIVE
16:41:25.653DEBUGbeacon-api–forecast sync finished: 3398 cities
16:43:31.902ERRORbeacon-api–FetchError: forecast upstream request timed out after 8000 ms
16:43:24.624INFObeacon-api201POST /api/declarations 201 in 28 ms
16:42:44.031INFObeacon-api200GET /api/declarations 200 in 88 ms
16:42:28.064INFObeacon-api200GET /api/forecast/:city 200 in 321 ms
filtersservice:beacon-apiLIVE
16:41:25.653DEBUGforecast sync finished: 3398 cities
16:43:31.902ERRORFetchError: forecast upstream request timed out after 8000 ms
16:43:24.624INFOPOST /api/declarations 201 in 28 ms
16:42:44.031INFOGET /api/declarations 200 in 88 ms
16:42:28.064INFOGET /api/forecast/:city 200 in 321 ms
LogsOne search over every line, a histogram above it, a live tail over SSE.
beacon-api
db 5msredis 2ms/health 200
throughput0.4req/s
p95 latency406ms
error rate0.3%
beacon-api
db 5msredis 2ms/health 200
throughput0.4req/s
p95 latency406ms
ServiceThroughput, error rate, p95 and the runtime, beside the facts true now.
6ca3eb80FetchErrorforecast upstream request timed out after 8000 ms · ForecastClient.fetchCity51
f630b723Errorconnect ECONNREFUSED 127.0.0.1:63797
2281b3bbTypeErrorHydration failed: cannot read 'amount' of undefined12
IssuesErrors grouped by fingerprint, counted over 48 hours.
PENDINGfor 00:01:12

rate(http_5xx[10m]) > 5%

beacon-api · 7.8%

RESOLVEDfor 03:31:20

probe_failures[90s] ≥ 2

beacon-api · 0

AlertsRules the collector evaluates: firing, acknowledged, resolved.
routep50p95p99
/api/forecast/:city1884537920
/api/ranking61132410
/api/declarations2894210
/api/cities92148
RoutesEach route's p50, p95 and p99, from the app's own /metrics.
traceefbf68478.2 s total
+0 msbeacon-frontGET /city/lyon8212 ms
+4 msbeacon-apiGET /api/forecast/:city8012 ms
+8008 msbeacon-apiFetchError: upstream timed out–
+8210 msbeacon-frontrendered error boundary2 ms
traceefbf68478.2 s total
+0 msbeacon-frontGET /city/lyon8212 ms
+4 msbeacon-apiGET /api/forecast/:city8012 ms
+8008 msbeacon-apiFetchError: upstream timed out–
+8210 msbeacon-frontrendered error boundary2 ms
TraceEvery line that carried one trace id, on one timeline.
paletteGo to
service, issue, route, trace id, view…
paletteGo to
service, issue, route, trace id, view…
Command palette⌘K to a service, an issue, a route or a trace id.
01 — Search

Find the line in milliseconds

Every line lands in a daily partition, so a search over one service and one day answers in about two milliseconds, even on ten million rows. A bar of the histogram jumps the table to its time.

  • Filters on service, level, route and status
  • A live tail over SSE
  • The query time on every answer
filtersservice:beacon-apiq 4msLIVE
time · CESTlvlservicestmessage
16:43:24.624INFObeacon-api201POST /api/declarations 201 in 28 ms
16:42:44.031INFObeacon-api200GET /api/declarations 200 in 88 ms
16:42:28.064INFObeacon-api200GET /api/forecast/:city 200 in 321 ms
16:42:21.436INFObeacon-api200GET /api/ranking 200 in 114 ms
16:42:19.388INFObeacon-api200GET /api/forecast/:city 200 in 197 ms
16:42:10.055INFObeacon-api–declaration window rolled over
16:41:48.388INFObeacon-api200GET /api/declarations 200 in 55 ms
02 — Group

Group every error by its cause

Errors that share a fingerprint become one issue: its count, first and last seen, its last 48 hours and its latest stack. From there, one click opens the logs of the request that raised it.

  • Server and browser errors, one schema
  • Resolve, ignore, or reopen
  • A regression flagged when it comes back
logsLIVE
16:43:31.902ERRORbeacon-api–FetchError: forecast upstream request timed out after 8000 ms
Issuesgrouped errors
6ca3eb80FetchErrorforecast upstream request timed out after 8000 ms · ForecastClient.fetchCitybeacon-api46just now
f630b723Errorconnect ECONNREFUSED 127.0.0.1:6379beacon-api729m ago
2281b3bbTypeErrorHydration failed: cannot read 'amount' of undefinedatlas-front121h ago
6ca3eb80FetchErrorbeacon-api
count51
last seenjust now
first seen9d ago
occurrences · 48h
latest stack

FetchError: forecast upstream request timed out after 8000 ms

at ForecastClient.fetchCity (forecast/forecast-client.js:61)

at async ForecastService.refresh (forecast/forecast.service.js:118)

at async CityController.forecast (city/city.controller.js:42)

open the logs of this requestignoreresolve
03 — Alert

Watch every rule, evaluated for you

The collector evaluates each rule every minute: an error rate, failed probes, a restart. A rule is pending until it has held, then firing, and each change lands in its history with the reading behind it.

  • Pending, firing, resolved
  • Acknowledge, or silence for an hour
  • Six hours of state per rule
RESOLVEDrate(http_5xx[10m]) > 5%beacon-api
stateRESOLVED
current1.4%
threshold5%
reading
state, last 6h
evaluated every 60sacknowledgesilence 1h
Preview

The whole fleet, one rail away.

Four views of the console, playing with a demo fleet: every log line, one service, the grouped errors and the alerts.

Demo fleet · sample data
And the rest

Every line, wherever it starts.

A page has no stdout, so the browser posts its errors to one route, in the same ECS JSON a server prints. Once stored, a browser error reads like any other line.

The same tailer follows each vhost's access log, so what nginx answered on its own, and a static site with no process, sit beside everything else.

Each day is its own partition. Retention drops the oldest in one statement and hands the disk back, with three days of partitions ready ahead.

The addresses behind a route, grouped, and one click to see who an address belongs to and where it is — asked once, then cached.

The contract

Standard formats in.
Free to move on.

Your apps write ECS JSON to stdout and expose /metrics, and that is the whole contract. Moving to Loki or Grafana later takes zero lines in your server apps.

ECS JSON on stdoutWhat pino already prints, read from the files PM2 writes.
Prometheus /metricsScraped as text from each app; routes come from its histograms.
Zero lines to moveVector, Fluent Bit or an OTel filelog read the same files.
Deny by defaultEvery route behind the session; one ingest route, allowlisted and rate-limited.

Production,
in plain sight.

Every app's logs, errors and alerts, on your own infrastructure.