Loki does not index your logs. It indexes the labels you attach to them.
That one design decision explains everything people like about Loki and everything they trip over. Storage is cheap because only labels are indexed. Search is fast when you pick the right stream. And the day someone adds a label with ten thousand values, the whole thing gets slow and nobody knows why.
Loki is good software solving a real problem at real scale. If you already run Prometheus and Grafana, Loki slots in beside them and you get metrics and logs on one dashboard with the same label vocabulary. At Kubernetes scale, its object-storage economics beat anything a single server can do.
This page is for the other case: you are a small team, you picked Loki because it was the self-hosted option everyone recommends, and you now maintain a logging stack instead of using one.
A working Loki install is not one thing.
Each of those has a config file, an upgrade path, and a way to fail. None of them is hard on its own. Together they are a part-time job.
Central Logging is one executable:
./centrallogging
That starts an HTTPS server with an auto-issued certificate, a web UI, and an ingest API. No collector to deploy, no Grafana to stand up, no bucket to create. Deploy has the rest, and there is not much of it.
| Grafana Loki | Central Logging | |
|---|---|---|
| Components to run | Loki + collector + Grafana + object storage | One binary |
| Storage | Chunks in object storage | SQLite on local disk |
| Index | Labels only | Full-text index plus SQL over every column |
| Query language | LogQL | SQL and full-text search |
| UI | Grafana | Built in |
| Cardinality management | You own it | Not a concept |
| Cron monitoring | No | Yes |
| Uptime monitoring | No | Yes |
| Host monitoring | No | Yes |
| Clustering / HA | Yes | No |
| Multi-tenancy | Yes | No |
| Licensing | Open source, or Grafana Cloud pricing | $187 once |
| Scale ceiling | Very high | ~10GB/day |
Loki builds one stream per unique combination of label values. Streams are the unit of everything: storage, indexing, query planning.
So this is fine:
{app="api", env="prod"}
And this is a bad afternoon:
{app="api", env="prod", user_id="8814", request_id="a3f9..."}
Every distinct user_id creates a stream. Chunks fragment, the index grows, queries slow down, and ingestion starts rejecting writes. The fix is to move those fields out of labels and into the log line, where they are no longer indexed and you find them by grepping with |= instead.
That is a real skill, and it is a skill about Loki rather than about your logs. You are designing a schema for a database you did not want to think about.
Central Logging has no labels. Lines go into a table with a timestamp, and any field inside them is reachable with json_extract. High-cardinality fields cost nothing special because nothing is pre-indexed by them.
LogQL starts with a stream selector. You must name the stream before you can filter it:
{app="api"} |= "error" | json | status >= 500
That reads well and it is fast. What it does not do is answer analytical questions without turning into a metric query with its own syntax.
Central Logging gives you SQL over a logs table with timestamp and msg columns:
SELECT
json_extract(msg, '$.status') AS status,
json_extract(msg, '$.path') AS path,
COUNT(*) AS hits
FROM logs
WHERE json_valid(msg)
AND json_extract(msg, '$.status') >= 500
AND timestamp > strftime('%s', 'now', '-1 hour')
GROUP BY status, path
ORDER BY hits DESC
LIMIT 20;
Group by, join, window functions, subqueries. If you know SQL you already know the query language, and there is no stream to select first.
When SQL is more than the question deserves, full-text search is there too:
+timeout -healthcheck payment
One thing to know about timestamp: it is when the server received the line, not when your application emitted it. Under normal conditions they are close. If ordering by event time matters, parse your own timestamp field out of msg and sort on that.
Loki users ship with Promtail or Alloy. Neither speaks Central Logging’s API, so this is a swap rather than a redirect.
System and journald logs. Install the CL Agent. It reads the journal on Linux and posts to the server. This replaces the Promtail journal scrape.
Applications that already log JSON. POST the lines. Newline-separated, as many as you like per request:
curl -X POST https://logs.example.com/api/v1/ingest_logs/YOUR-SOURCE-TOKEN \
-d @mylogs.txt
The token can go in a header instead of the URL if you would rather not have it in a path:
curl -X POST https://logs.example.com/api/v1/ingest_logs \
-H "Authorization: Bearer YOUR-SOURCE-TOKEN" \
-d @mylogs.txt
gzip bodies work too.
Containers. The Docker guide covers getting container stdout off the host before docker rm takes it with them.
Existing syslog infrastructure. The rsyslog guide covers omhttp with a disk-backed queue, so a server restart loses nothing.
A fair comparison lists these, because they are the reasons to stay.
X-Scope-OrgID. Central Logging has one admin account and no per-user permissions.Stay with Loki if you run Kubernetes at scale, if your team already lives in Grafana, if you need years of retention on cheap storage, or if multi-tenancy is a requirement.
Switch if you chose Loki because it was the self-hosted default, if your log volume is comfortably under 10GB/day, if nobody on the team enjoys explaining cardinality, or if you want cron and uptime monitoring without adding two more services.
The free download is the complete product, not a trial.
Run it next to Loki for a week. Fork a copy of your log stream into it. Then ask which one you opened when something broke.
14-day refund if you buy and it does not fit. Deploy has the setup.
💌 Get notified on new features and updates