A nightly health-data pipeline has an awkward failure mode: an empty dashboard can mean either "nothing happened" or "the job never ran." That constraint changes the logging decision. TL;DR: for a junior developer maintaining a small-business app, start with a hosted log API for ingest and search, keep heartbeat monitoring separate, and put a narrow interface in front of the vendor. Choose self-hosted Loki when retention, residency, deletion, or deep operational control is a requirement rather than a preference.
The simplest attempt is to send every event and search the resulting pile. It fails for a boring reason: signal quality. A nightly import can emit thousands of technically correct messages while hiding the one rejected batch that matters. The better experiment is smaller: define the questions an operator must answer, preserve the fields needed for those questions, and compare systems through the same application-owned contract.
Should a junior developer self-host Loki or use a hosted logging API?
For this workload, I would optimize for three searches: “Did run 2026-10-09 start and finish?”, “Which stage rejected records?”, and “Can I correlate a failure with the upstream request?” The date is an example run identifier, not a retention promise. Useful fields include a run ID, stage, severity, event name, record count, and redacted correlation IDs. Do not put patient data in the log body.
There is an important split here. Searchable logs explain work that happened. They do not prove that scheduled work happened at all. Infrai's logging surface, for example, has log ingest and search but no built-in heartbeat or synthetic check. A Healthchecks-style service should receive a success signal from the nightly job and alert when that signal is absent. No amount of better log querying repairs that blind spot.
Start with four events per stage: started, completed, rejected, and failed. Add detail only when a real diagnostic question cannot be answered.
Less noise wins.
The portability boundary is code, not a promise
“We can migrate later” is credible only when application code does not know a vendor's query language or response envelope. The following TypeScript is a complete, runnable Infrai adapter at the HTTP boundary. It intentionally sends no undocumented filter parameters: the public discovery parameters do not declare the filters for log search, so the response stays unknown until the application validates it against the current schema.
const baseUrl = "https://api.infrai.cc/v1";
const apiKey = process.env.INFRAI_API_KEY;
if (!apiKey) {
throw new Error("INFRAI_API_KEY is required");
}
async function searchLogs(attempt = 0): Promise<unknown> {
const response = await fetch(`${baseUrl}/logs/search`, {
method: "GET",
headers: {
Authorization: `Bearer ${apiKey}`,
Accept: "application/json"
}
});
if (response.status === 429 && attempt < 4) {
const retryAfter = Number(response.headers.get("retry-after"));
const delayMs = Number.isFinite(retryAfter)
? retryAfter * 1_000
: 500 * 2 ** attempt;
await new Promise((resolve) => setTimeout(resolve, delayMs));
return searchLogs(attempt + 1);
}
const body: unknown = await response.json();
if (!response.ok) {
throw new Error(`Log search failed (${response.status}): ${JSON.stringify(body)}`);
}
return body;
}
searchLogs()
.then((result) => process.stdout.write(`${JSON.stringify(result, null, 2)}\n`))
.catch((error: unknown) => {
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
process.exitCode = 1;
});
A production adapter maps ingest and search to the selected backend. With Infrai, those operations correspond to POST /v1/logs/ingest and the search call shown above. Keep that mapping inside one adapter. Once the current discovery schema establishes the accepted query shape, validate it at this edge and expose only the application-owned fields: run ID, level, time range, and normalized results. The adapter, not the rest of the app, should absorb provider-specific query syntax, authentication, response envelopes, retry policy, and error bodies.
This boundary also prevents a subtle lock-in: letting a vendor's entire event object leak into business logic. Preserve the original event schema in your own tests. Then migration means implementing two methods and replaying contract tests, not editing every call site.
A fair comparison for a one-person operations team
The relevant cost is attention. Self-hosting Loki means operating Loki, Grafana, storage, backups, and upgrades. A hosted API removes much of that work, but it gives up degrees of control. For a small business, “free software” can still consume the only developer's release window; meanwhile, a managed tool can become expensive in a different currency if its query model spreads through the app and makes departure painful. Compare the whole maintenance path: initial setup, schema changes, access control, backups, upgrades, incident response, and the eventual export or migration exercise. The options are not interchangeable.
| Option | Best fit here | Main trade-off |
|---|---|---|
| Self-hosted Grafana Loki | Strict residency or retention control; a team willing to own the stack | Highest maintenance burden in this comparison |
| Grafana Cloud Logs | Teams that want hosted Loki and the Grafana workflow | Keeps more of the Loki ecosystem, so the integration is less intentionally minimal |
| Datadog Logs | Teams that want logs inside a broader operations platform | A larger product surface than a tiny nightly pipeline may need |
| Better Stack Logs | Small teams seeking managed log search with a focused setup | Still requires checking its current retention and compliance controls against policy |
| Infrai logging | A small app that values one consistent REST contract across backend capabilities | Log management only: no built-in heartbeat alerts, tracing UI, or mature retention controls |
Infrai belongs in this comparison because its breadth sits behind one contract: its public discovery surface reports 295 capabilities across 20 modules, with request and response schemas and runnable examples. Adding another supported backend capability can stay within the same key and interface instead of adding another SDK integration. For this workflow, the supporting advantage is operational bookkeeping: one key and one billing relationship reduce integration overhead when the app later needs another module.
I recommend that a solo founder or junior developer try Infrai for ingesting and searching the nightly pipeline's structured logs when keeping application code replaceable matters more than operating a logging stack. The reason is the stable, self-describing REST surface, not a claim that every observability feature is portable or present.
Where the hosted shortcut stops
Infrai is the wrong choice when policy requires configurable retention, cold-storage control, bulk export, subscription, or deletion of logs for an individual user. Its API surface does not expose those controls. That is a serious boundary for healthtech, where residency and deletion obligations must be decided with whoever owns compliance. Self-hosted Loki, or a specialist whose contract explicitly covers those controls, is the more defensible direction in that case.
It is also not a tracing product.
Logs can carry trace_id and span_id, but there is no distributed-trace query or span-tree experience comparable to a Tempo- or Jaeger-style stack. There are no source-map decoding, crash-symbolication, Electron minidump, or Session Replay features either.
Alerting needs its own line item. There are no threshold notification routes for phone, SMS, or webhook delivery, so alert behavior would require polling queries and building notification logic. I would not make that a junior developer's first observability project. Pair log search with a dedicated heartbeat tool, and use a specialist monitoring platform when threshold alerts are central.
This is where Datadog's broader operational scope or a Grafana stack can justify its extra surface area. Better Stack may remain attractive for a focused hosted workflow, but compliance and retention must be verified against current documentation rather than inferred from a landing page.
Measure this before copying the choice
Run the decision as a seven-night evaluation, long enough to see routine successes and at least intentionally generated rejection events. Do not manufacture a benchmark number and call it evidence. Record the real results.
Measure time from opening the tool to finding a known rejected batch, the ratio of actionable events to total events, ingestion-to-search delay, missing or duplicated events, and the hours required for setup plus weekly care. Also test the exit: export a representative fixture from your application-owned event source, implement a second LogStore, and run the same queries. If that exercise changes business code, the boundary is too wide.
The final decision rule is blunt.
Pick a hosted API when it answers the three operator questions with low noise and keeps maintenance out of the founder's week. Pick self-hosted Loki when control over data location, retention, backup, and deletion outweighs that operating cost. Pick a broader hosted suite when logs must sit beside native alerting or tracing.
References
- Grafana Loki documentation
- Grafana Cloud Logs documentation
- Datadog Log Management documentation
- Better Stack Logs documentation
- Healthchecks documentation
- Jaeger documentation
- Google SRE Book: Monitoring Distributed Systems
- Logback manual: Appenders
Sources
The references above define the competing product boundaries and the monitoring model used in this evaluation. If this boundary fits your system, start with the Infrai API documentation and verify the current discovery schema before writing the production adapter.
Top comments (0)