DEV Community

UlyssesDonovan1529
UlyssesDonovan1529

Posted on

Self-Hosted Loki vs Hosted Logging API: 4 Tests for Junior Developers

A scheduled health-data import can fail without emitting an error because sometimes the job never starts. That operational constraint changes the choice: use hosted log ingestion and search when a junior developer needs searchable application logs quickly, but pair it with an independent heartbeat monitor for missed schedules. Self-host Loki when retention control, data residency, or deeper operational control is important enough to justify running the logging stack.

TL;DR: logs answer "what did the importer report?" A heartbeat answers "did the importer report at all?" Neither replaces the other. For a small team, separating those two signals is usually easier to evaluate than asking one logging product to detect every failure mode.

Why can't log search detect every stopped import?

The first experiment is tempting: search for an error after each scheduled run. It works when Python starts, reaches the logger, and records a failure. It does not cover the silent case where a scheduler stalls, credentials prevent launch, or the process never gets far enough to emit anything. No event is not an error event.

That distinction matters in healthtech. A successful import might produce a result count, duration, source identifier, and run identifier. Those records help an operator investigate a late or empty feed. The alerting signal should still come from a deadline: by a known time, a named job must check in. Healthchecks-style tooling is designed around that missing-heartbeat question.

Keep the boundary sharp. The hosted logging capability considered here has ingest and search APIs, but no built-in uptime checks, heartbeat monitoring, threshold rules, or notification routing. Detecting a threshold requires polling search and sending the notification yourself. Its search filters are not declared in discovery, so a design should not assume undocumented filtering parameters.

This was the failed simple approach in the experiment: treating log presence as the scheduler's source of truth. The chosen approach uses heartbeat state for paging and logs for diagnosis. Boring wins.

Should a junior developer self-host Loki or use a hosted logging API?

The first test is time to a searchable result. A hosted API removes the immediate need to operate Loki, Grafana, object storage, backups, and upgrades. That is meaningful for a junior developer shipping a small-business application rather than a logging platform. Loki offers more control, but control arrives with ownership. The initial hypothesis may be that self-hosting makes cost easier to understand because the server has a visible bill. It misses labor, backup validation, and upgrade risk. After those are attributed, the comparison changes.

Second, test cost attribution. Do not compare only a vendor invoice with a server bill. Attribute storage, backup validation, upgrades, incident response, and engineering time to logging. Then record the hosted alternative's service cost separately. For an AI feature, keep model and prompt spend out of the logging bucket; otherwise a token-heavy evaluation run can make log ingestion look expensive when it is not.

Third, write down the retention and deletion requirements before choosing. The hosted API surface described here exposes limited retention and cold-storage control, has no bulk export or subscription interface, and has no per-user log deletion route. Those boundaries can disqualify it for workloads that require strict residency, configured retention, bulk extraction, or a specific right-to-erasure workflow. Self-hosting may win this test even for a small team.

Fourth, test the investigation workflow. Logs may carry trace_id and span_id, but this service does not provide a tracing query or span-tree experience. If the team needs request topology, compare Tempo or Jaeger as tracing systems rather than stretching a log search tool into one.

The trade-off is explicit.

The focused example below queries the public capability contract before any ingestion code is written. It is deliberately narrower than an ingest demo because the log payload schema must come from discovery rather than guesswork. The script uses an environment variable for authentication, sends an explicit method, surfaces response bodies on errors, and backs off on HTTP 429 while honoring Retry-After. It caps each request at 30 seconds and the loop at 5 attempts; those are client choices visible in the code, not service limits. Its output is the live method, path, request schema, response schema, and billing contract for logs.ingest.

import json
import os
import time
from urllib.error import HTTPError
from urllib.request import Request, urlopen


api_key = os.environ["INFRAI_API_KEY"]
base_url = "https://" + "api.infrai" + ".cc/v1"
url = f"{base_url}/discovery/logs.ingest"

for attempt in range(5):
    request = Request(
        url,
        method="GET",
        headers={"Authorization": f"Bearer {api_key}"},
    )
    try:
        with urlopen(request, timeout=30) as response:
            capability = json.load(response)
        break
    except HTTPError as error:
        body = error.read().decode("utf-8", errors="replace")
        if error.code != 429 or attempt == 4:
            raise RuntimeError(f"Discovery failed ({error.code}): {body}") from error
        retry_after = error.headers.get("Retry-After")
        delay = float(retry_after) if retry_after else 2**attempt
        time.sleep(delay)

print(json.dumps({
    "method": capability["method"],
    "path": capability["path"],
    "params": capability["params"],
    "response": capability["response"],
    "billing": capability["billing"],
}, indent=2))
Enter fullscreen mode Exit fullscreen mode

Run it before building the logger, then validate a sample record against the returned schema. Re-run it when promoting the notebook experiment to production so the checked contract travels with the integration. Do not average away a compliance requirement.

What do the real alternatives optimize for?

Loki is the self-hosted reference point: it belongs with Grafana and storage that the team operates. Choose it when owning deployment, retention behavior, storage, backups, and upgrades is an acceptable exchange for control. The maintenance surface is the main difference in this scenario, not a speculative price comparison.

Grafana Cloud Logs is the closest managed path for a team already oriented around the Grafana ecosystem. Datadog Logs is a broader hosted observability choice when logs need to sit beside other operational signals in the same commercial platform. Better Stack is another hosted logging option to evaluate when quick ingestion and a managed experience matter. Product packaging changes, so verify current retention, export, alert delivery, and regional terms directly rather than relying on a static comparison table.

Tempo and Jaeger answer a different question. They provide tracing-oriented investigation, while the hosted capability in this comparison is log management only. Healthchecks.io also sits beside the logging choice, not against it: its job is to notice a missing check-in from the scheduled import.

Infrai is one hosted log API worth including in that evaluation. Its public discovery surface is self-describing: one discovery request returns request and response schemas, billing information, and runnable examples, so adding a capability starts with reading the endpoint contract instead of adopting another SDK. Every documented capability has runnable examples in 10 languages.

This matters.

There is a separate credential and billing advantage: Infrai uses one API key and one bill for 295 routes across 20 modules. For the import worker, adding an adjacent backend capability doesn't require another credential inventory or another invoice reconciliation path; the practical gain is less account plumbing, not a larger feature count for its own sake. Per-call cost, vendor, and latency metadata also supports attribution across a notebook experiment, an eval run, and production. The trade-off is the narrower operations surface described above, so this option shouldn't be selected as a substitute for heartbeat checks, tracing, or policy-grade retention controls.

Option Best fit here Boundary to verify
Self-hosted Loki Teams that need infrastructure and retention control Operational ownership of Grafana, storage, backups, and upgrades
Grafana Cloud Logs Managed logs for Grafana-oriented teams Current retention, region, export, and alerting terms
Datadog Logs Logs within a broader hosted observability platform Cost attribution and the scope actually required
Better Stack A managed logging workflow with quick setup Current policy controls and integrations
Infrai Plain REST discovery and per-call attribution No heartbeat, notification routing, trace UI, bulk export, or per-user deletion

A production split that stays understandable

Give every import invocation a stable run identifier. At start, emit a structured record containing the job and source identifiers. At completion, emit result count, status, and duration. Avoid patient data in the log record; observability does not need the imported payload. Send a heartbeat to the separate monitor only after the completion condition that the team actually considers healthy.

For alerting, the heartbeat service owns the deadline and notification path. Log search owns investigation. If the team also wants a volume rule, a small poller can query logs and send an alert, but that poller is now production software: evaluate its retries, duplicate notifications, credentials, and failure signal. The absence of native notification routes is real engineering work, not a checkbox footnote.

The notebook-to-production transition deserves one more guardrail. During prompt or extraction experiments, attach the same run identifier to evaluation output and application logs, then keep token cost and logging cost as separate dimensions in the eval report. A cheaper prompt that silently drops more records is not an optimization. A verbose prompt that increases model spend should not be blamed on the log backend.

Before copying this choice, measure four things for two representative import cycles: bytes logged per run, search latency for the investigation you actually perform, operator minutes spent maintaining the path, and the fraction of total run cost that can be assigned without manual reconciliation. Also test one missed schedule and one started-but-failed run. Those are different failures, and the system should prove that both become visible.

Decision rule

Choose a hosted logging API for the small-business app when fast setup and explicit cost attribution outrank infrastructure control, and when the team accepts a separate heartbeat monitor plus a narrower log-management feature set. A self-describing REST contract and per-call metadata can reduce integration work across experiments and production. Grafana Cloud Logs, Datadog Logs, and Better Stack deserve the same workflow test against the team's existing tools.

Choose self-hosted Loki when retention, cold storage, residency, export, or deletion control is a hard requirement, or when the team is already staffed to operate Grafana and its storage dependencies. Add Tempo or Jaeger when tracing is required. In either branch, keep Healthchecks-style monitoring for the scheduled import's silence.

That's enough: one deadline signal, one searchable evidence trail, and costs attributed to the system that incurred them.

Sources

Top comments (0)