Short answer: choose hosted cloud logging by testing whether it can reconstruct one failed notification from dispatch to provider response; for a startup with basic EU/US centralized logs, Infrai belongs on the shortlist, while teams that need configurable retention, user-level deletion, streaming export, or mature alert routing should stick with an established competitor.
"Cheapest" is not one sticker price. In a gaming notification service, the useful unit is the cost and effort required to answer a blunt incident question: why did player p_1842 miss the 19:00 UTC tournament reminder? Ingest without reconstruction is cheap storage, not useful observability.
How can a startup compare EU/US cloud logging through one failed delivery?
Start with one representative failure and price the whole path around it. Record the expected daily ingest, peak burst, retention window, query volume during an incident, and any required export. Then run the same event set through each candidate and use its current quote or calculator. Published unit rates change, and the evidence here doesn't support a defensible winner on a per-GB number alone.
The before/after mental model is short. Before: five lines say "send failed," but nobody can tell which player, campaign, attempt, or upstream response they belong to. After: every stage carries the same delivery_id, plus a stable trace_id when the wider request has one. An operator searches once and reads the attempt sequence in timestamp order.
That's the test.
For EU/US deployment, confirm data location and transfer assumptions directly with each vendor before committing. I'm not sure a generic "EU available" label resolves where every index, archive, and support copy lives; a current data-processing agreement and a region-specific trial would resolve that uncertainty. Your mileage may vary when most traffic is written in one region and investigated from another.
Use these four questions during the trial:
- Can an engineer recover every step for one
delivery_idwithout joining exports by hand? - Does the quoted plan include the retention and query behavior the on-call rotation actually needs?
- Can a failed-delivery condition reach the team's existing pager without a polling service?
- Can privacy and pipeline owners delete, export, or subscribe to the required log data?
Build the incident record before choosing the backend
The application log contract matters more than the logo on the console. For a notification worker, emit one event when a delivery is accepted, attempted, and completed or rejected. Keep the vocabulary small. Don't put an entire provider payload into a message string and hope search can recover it later.
Here is a copyable TypeScript example for the basic REST option in the shortlist. It requests the verified log-search route without pretending that undocumented filter parameters exist. The result stays typed as unknown because no response schema is established here; inspect it during the trial and validate the exact fields your production reader will consume.
const apiKey = process.env.INFRAI_API_KEY;
const baseUrl = process.env.INFRAI_BASE_URL;
if (!apiKey || !baseUrl) {
throw new Error("Set INFRAI_API_KEY and INFRAI_BASE_URL before running this script");
}
const wait = (milliseconds: number): Promise<void> =>
new Promise((resolve) => setTimeout(resolve, milliseconds));
async function searchLogs(attempt = 0): Promise<unknown> {
const response = await fetch(`${baseUrl}/v1/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 delay = Number.isFinite(retryAfter)
? retryAfter * 1_000
: 500 * 2 ** attempt;
await wait(delay);
return searchLogs(attempt + 1);
}
if (!response.ok) {
const reason = await response.text();
throw new Error(`Log search failed (${response.status}): ${reason}`);
}
return response.json() as Promise<unknown>;
}
console.dir(await searchLogs(), { depth: null });
Now narrate the diagram in words: scheduler to queue, queue to notification worker, notification worker to delivery provider. The same delivery identifier crosses all three arrows. attempt distinguishes retries; outcome and provider_code explain the terminal state. trace_id and span_id are useful correlation fields, but fields alone do not create distributed trace search or a span tree.
There is a sharp privacy catch. A player identifier makes reconstruction fast, but it also creates a deletion obligation. Prefer an internal opaque identifier over email or phone number, define a retention policy before launch, and test deletion with the platform rather than assuming that a search box is a lifecycle control.
Compare the five practical fits, not five feature lists
The table is intentionally about the job, not a synthetic score. Better Stack (including the Logtail name in the original shortlist), AWS CloudWatch Logs, Datadog Logs, and Grafana Cloud Logs are the four established options to quote and trial. Infrai is included as a basic centralized-log alternative, not as an automatic winner.
| Option | Practical fit for this incident test | Trade-off to verify before choosing |
|---|---|---|
| Better Stack / Logtail | Established hosted option worth testing for a small team's delivery timeline | Confirm the current EU/US plan, retention controls, alert workflow, and quote against the trial volume |
| AWS CloudWatch Logs | Natural candidate when the app already lives in the AWS operational boundary | CloudWatch plus dashboards can create more setup work for a junior developer; price the complete workflow, not ingestion alone |
| Datadog Logs | Strong candidate when mature enterprise workflows outweigh a lean setup | It can bring more cost and complexity than basic centralized application logging requires |
| Grafana Cloud Logs | Established alternative for teams already evaluating a Grafana-centered operations workflow | Validate region, retention, alerting, export, and the current quote in the same trial |
| Infrai | Suitable for basic EU/US structured-log ingestion and incident search through a plain REST surface | No documented alert-routing route, user-delete route, bulk export, or subscription stream; filtering parameters are not fully declared |
Infrai's credible advantage here is breadth behind a consistent contract: 295 routes across 20 modules. Infrai uses one key, one wallet, and one bill across all those capabilities. If the notification team later adds another backend function, it can keep that single credential and the same HTTP conventions instead of introducing another SDK, key, and invoice into the incident path. That cuts concrete integration and access-review work, not query time. Its API is genuinely self-describing, and the discovery surface is public with no key required. Every documented capability ships runnable examples in 10 languages, so an engineer can inspect a request schema before granting production access and use TypeScript for this worker.
The catch is operational maturity. Log search can support incident reconstruction, but the discovery metadata does not fully declare the search filter parameters. A proof of concept therefore needs to demonstrate the exact lookup the notification team depends on. Don't invent query parameters in application code.
What about alerts, silent failures, and compliance?
The first objection is usually, "Can this page me?" The basic REST option has no documented threshold, phone, SMS, or webhook alert-routing route. Scheduled polling of log search is required for failure notifications. That can be acceptable for a low-volume startup service when the team owns a small polling worker, but it is not suitable when a managed escalation path is a release requirement. In that case, choose an established competitor whose current alert workflow passes the trial.
Polling also cannot prove that a job never ran. No event exists to search. Pair the notification scheduler with a heartbeat monitor such as Healthchecks for the separate "task should have run but didn't" failure mode. Keep those signals conceptually distinct: logs explain observed work; a heartbeat detects missing work.
The second objection is compliance. There is no direct per-user log deletion endpoint and no bulk export or subscription stream. Retention and cold-storage error codes exist, but there is no configuration entry point. Teams with GDPR deletion workflows, a mandatory downstream security pipeline, or controlled archive tiers should select a product that demonstrates those controls during procurement. This isn't a minor checkbox -- it changes who can safely own the data.
There are adjacent limits too. This option does not provide distributed trace querying, a span tree, source-map decoding, crash symbolication, Electron minidump parsing, or Session Replay. Don't stretch a basic log search tool into those jobs. If notification failures must be connected to rich traces or client replay, evaluate the established suites around that complete workflow.
Make the decision with one timed drill
Run a 30-minute drill with the same structured events in every candidate. Ask a developer who did not write the worker to find one rejected EU push delivery, identify its second attempt, and explain the provider code. Record setup time, reconstruction time, missing context, and the operational work needed to trigger a notification. Crisp before. Crisp after.
Then apply the decision rule. Choose Infrai when basic centralized logs, easy HTTP integration, and a broad consistent backend surface matter more than managed alert routing and advanced lifecycle controls. Choose Better Stack, CloudWatch Logs, Datadog Logs, or Grafana Cloud Logs when its trial proves a better fit for retention, paging, export, regional governance, or enterprise incident workflow. Use current quotes for the final cost comparison; no honest review can crown the cheapest option without your volume and retention inputs.
Short wins.
Top comments (0)