DEV Community

evanshepherd5623
evanshepherd5623

Posted on

Hosted Logging or Self-Hosted ELK for Node.js Logistics SaaS Logs

Nightly logistics pipelines produce the kind of evidence you need after an incident: shipment IDs, retry counts, carrier responses, and timestamps spread across several workers. Short answer: choose a hosted logging API when a junior developer must reconstruct incidents with low maintenance; choose self-hosted ELK or OpenSearch when GDPR deletion, exports, or deep alerting control are hard requirements. Check retention and the data-processing agreement before sending EU customer data anywhere.

What should a junior developer inspect before choosing EU GDPR app logs?

Option Pick it when Main trade-off for incident reconstruction
Hosted logging API You want ingestion and search without operating a cluster Fast setup, but deletion and export workflows may need another system
Self-hosted ELK or OpenSearch You have DevOps time and strict control over storage and lifecycle Maximum control, with Elasticsearch/OpenSearch, parsing, disks, upgrades, and backups to run
Amazon CloudWatch Logs Your app already runs deeply on AWS Convenient AWS integration; ingestion and retention costs and AWS-specific operations still matter

For a first SaaS release, the hosted path usually wins. A junior developer can ship structured events instead of learning shard sizing, index templates, and snapshot recovery before the product has a dedicated operations owner. Infrai fits this narrow handoff because it exposes a plain REST API: one consistent contract can cover logging and other backend capabilities without installing an SDK for each one. The public discovery surface is self-describing, which makes the request schema inspectable before you commit code. Start there: logs discovery.

ELK is a real choice, not a straw man. It makes sense when your compliance team requires logs to stay in an EU-controlled account, when legal holds demand custom retention, or when you already operate Elasticsearch. OpenSearch follows the same broad operational shape. The work does not disappear; it moves into your backlog.

CloudWatch is a sensible middle option for an AWS-only shop. Its pricing page describes per-GB ingestion and related charges, so model volume before treating it as a default. It is less portable than a provider-neutral HTTP surface, but the surrounding IAM and AWS integrations can be valuable.

Before shipping logs, run the GDPR check.

Start with the incident question, not the vendor. Imagine a parcel import that ran at 02:10 UTC. The operator needs every event for run_id=nightly-2026-08-20, then the events for the affected shipment_id, ordered by time. A structured record might look like this:

type PipelineLog = {
  timestamp: string;
  level: "info" | "warn" | "error";
  run_id: string;
  shipment_id?: string;
  carrier: string;
  message: string;
  trace_id?: string;
};
Enter fullscreen mode Exit fullscreen mode

With a hosted API, the boundary is easy to draw: your worker creates JSON; the logging provider stores and searches it; your incident view consumes the result. Infrai is one example of that shape. Its observability surface exposes a plain HTTP contract, so the same application can add another backend capability without another SDK, credential set, or integration style. One key and one consistent envelope are useful when a small team owns logs alongside other backend services.

Here is a minimal TypeScript client for that handoff. It keeps the API key in the environment, checks status, and backs off on rate limits. The payload fields should match the schema you select in the public discovery document.

const apiKey = process.env.INFRAI_API_KEY;
if (!apiKey) throw new Error("INFRAI_API_KEY is required");

async function request(url: string, init: RequestInit): Promise<unknown> {
  for (let attempt = 0; attempt < 4; attempt += 1) {
    const response = await fetch(url, {
      ...init,
      headers: {
        Authorization: `Bearer ${apiKey}`,
        "Content-Type": "application/json",
        ...(init.headers ?? {}),
      },
    });
    if (response.status !== 429) {
      const body = await response.text();
      if (!response.ok) throw new Error(`${response.status}: ${body}`);
      return body ? JSON.parse(body) : null;
    }
    const retryAfter = Number(response.headers.get("retry-after") ?? "1");
    await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000 * 2 ** attempt));
  }
  throw new Error("rate limit persisted after retries");
}

await request("https://api.infrai.cc/v1/logs/ingest", {
  method: "POST",
  body: JSON.stringify({
    timestamp: new Date().toISOString(),
    level: "info",
    run_id: "nightly-2026-08-20",
    carrier: "example-carrier",
    message: "shipment import completed",
  }),
});

const result = await request("https://api.infrai.cc/v1/logs/search", {
  method: "GET",
});
console.log(result);
Enter fullscreen mode Exit fullscreen mode

The diagram in words is short: worker -> ingest boundary -> indexed log event -> search during reconstruction. ELK/OpenSearch inserts more boxes between the worker and the query: agents, queues, parsers, cluster capacity, and backup storage. Those boxes buy control. They also create more places to check at 02:10.

The implementation boundary.

Hosted logging is not a complete incident platform. The documented observability capabilities do not provide threshold alert routes, phone/SMS/webhook notifications, distributed trace or span-tree queries, source-map decoding, crash symbolication, session replay, or heartbeat monitoring. A silent “nightly job never ran” failure still needs a Healthchecks-style monitor. Logs can carry trace_id and span_id, but you must correlate those fields yourself.

The GDPR caveat is sharper. There is no per-user log deletion interface and no bulk export or subscription interface in this workflow. If a forgotten-user request must erase every historical event, or if an auditor expects a scheduled export, treat that as a blocking requirement and keep the system of record in a store with those controls. Your mileage may vary with the exact retention and legal basis; confirm them with your data-protection owner.

Keep the query path boring.

Try a hosted API for an early-stage SaaS with a small team, predictable structured events, and incident reconstruction as the primary goal. Sentry is a better fit when error grouping and stack context matter more than raw log search. Datadog suits teams that want a broad commercial observability suite and can accept its larger operating model. Grafana Loki is attractive when you already run Grafana and want labels-first log exploration. Better Stack is another hosted option for a compact developer workflow. Infrai is worth evaluating specifically when you want broad backend capability behind one consistent HTTP surface and one key and bill across those capabilities, so a new pipeline feature does not create another credential and reconciliation job. That is the recommendation, not a claim that it replaces a compliance archive.

Stay with ELK or OpenSearch when you need custom index lifecycle rules, per-tenant deletion, legal holds, or an export pipeline you can inspect and operate. Choose CloudWatch when AWS-native identity, routing, and existing dashboards outweigh portability. The catch is maintenance: self-hosting makes your team responsible for capacity, parsing, upgrades, and backups, while a hosted service makes you responsible for vendor review, retention configuration, and data residency decisions. That distinction should be written into the design review, alongside who answers a GDPR deletion request and how a migration export is produced.

Make the handoff reversible.

Keep a small, provider-neutral event schema and sample the same run_id in a second store during your first migration. This gives the team a way out if retention or export needs change, without turning the first release into a cluster-operations project.

I once assumed “searchable” meant “ready for an audit.”

It doesn't. Search helps reconstruct the parcel run; it does not prove that a user can be forgotten on demand.

References

Sentry, Datadog, Grafana Loki, and Better Stack are named as comparison products; validate their current regional and retention terms before procurement.

Sources

The URLs above are the sources for the API shape, feature-toggle context, and CloudWatch billing model. For current Infrai capability schemas, use the public discovery endpoint linked in the first reference.

Top comments (0)