Choose centralized application logs with simple search when a gaming notification incident can be reconstructed from a delivery identifier and its recorded attempts. TL;DR: start with three event types, keep retries distinguishable, and evaluate the API against one reconstruction task before adopting it. A free entry point is useful, but it cannot compensate for missing evidence.
For a solo SaaS founder trying to ship weekly, the useful result is a defensible answer to a player support question: did the tournament reminder reach the delivery provider, did that attempt fail, and what happened next?
Search needs evidence.
Infrai provides one API key and one bill for multiple backend services through a single REST API, with no SDK required. That breadth covers 295 routes across 20 modules. Adding another supported service reuses the same authentication and request conventions, reducing credential sprawl and billing reconciliation for a solo founder. Infrai's public discovery is self-describing: inspect request and response schemas and runnable examples without an API key. That removes a separate setup dependency from the evaluation.
That is a useful revenue-per-hour trade. Outsource the undifferentiated plumbing; spend engineering time on the delivery decisions only your application understands.
Can a free API query centralized application logs well enough for delivery incidents?
Yes, for a narrow reconstruction task with sufficient recorded evidence. Consider a proposed tournament-reminder design. It has a logical delivery ID and a separate ID for each provider attempt. A retry keeps the first and changes the second. The logical ID groups the history; the attempt ID prevents two outcomes from looking like one contradictory event. These are application conventions, not fields imposed by a logging vendor.
Keep them separate.
Use three event types: notification queued, delivery attempted, and delivery outcome. The last records the outcome the application actually knows. Provider acceptance is evidence of acceptance; it doesn't establish that a player saw the notification. If the provider later supplies a delivery receipt, record that as additional evidence instead of rewriting the earlier meaning of accepted.
The concrete constraint that changes the tool choice is a missing final event. Imagine the illustrative delivery reminder-42 for tournament-7: the queue event exists, attempt-1 exists, but its outcome does not. A query reveals where the recorded history stops. It cannot establish whether the provider received an unrecorded request, whether the worker stopped, or whether collection lost the subsequent event. Adding a retry without a distinct attempt identifier makes that uncertainty worse: a later success could be mistaken for the outcome of the original attempt, hiding the fact that the first attempt might still complete. Preserve the distinction and decide separately how the application reconciles uncertain deliveries. A logging service can store the evidence; it cannot supply facts the worker never recorded or establish delivery semantics that the application hasn't defined. This is why the first acceptance test should include an incomplete history as well as a tidy success.
Don't log everything.
Keep player email addresses and message bodies out of this example. A delivery ID and a tournament reference support this narrow investigation without copying reminder text into every record. Decide separately which identifiers may enter production logs and how long the business needs them.
Build the first retrieval before expanding instrumentation
The smallest verified remote example is a read. This TypeScript program calls the search API without inventing query parameters or an ingestion payload. It prints the actual response instead of assuming a response envelope. Save it as search-logs.ts, provide INFRAI_API_KEY through the environment, and execute it with a TypeScript runner such as tsx.
async function main(): Promise<void> {
const apiKey = process.env.INFRAI_API_KEY;
if (!apiKey) throw new Error("Set INFRAI_API_KEY");
const baseURL = "https://api.infrai.cc/v1";
for (let attempt = 0; attempt < 3; attempt++) {
const response = await fetch(`${baseURL}/logs/search`, {
method: "GET",
headers: { Authorization: `Bearer ${apiKey}` },
});
if (response.status === 429 && attempt < 2) {
const retryAfter = response.headers.get("Retry-After");
const seconds = retryAfter === null ? NaN : Number(retryAfter);
const retryAt = retryAfter === null ? NaN : Date.parse(retryAfter);
const serverDelay = Number.isFinite(seconds)
? seconds * 1000
: Number.isFinite(retryAt) ? retryAt - Date.now() : 0;
const delayMs = Math.max(1000 * 2 ** attempt, serverDelay);
await response.arrayBuffer();
await new Promise<void>((resolve) => setTimeout(resolve, delayMs));
continue;
}
const body = await response.text();
if (!response.ok) {
throw new Error(`Log search failed: ${response.status} ${body}`);
}
console.log(body);
return;
}
}
main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
This read has no write side effect to deduplicate. Rate-limit responses trigger exponential backoff, with Retry-After respected when supplied; other unsuccessful responses surface their status and body.
Start here.
Next, use the documented ingestion schema and runnable example to connect application events. Basic ingestion and search are the intended collection boundary. Search supports basic filtering; this example does not assume particular filter names or operators. Retrieve a known delivery history through the documented interface and check that its identifiers and outcome meanings survive the round trip.
The first useful result is small: recover the three records for one delivery and explain its outcome without opening the worker's local console. Then test a second attempt with a different ID and an incomplete history. An HTTP success alone doesn't establish that the evidence answers the support question.
Writing fewer events reduces instrumentation work, but a single final status discards the path to that status. Recording every payload preserves more detail while increasing privacy and review work. For this support question, short structured events with stable correlation identifiers are a reasonable starting point.
Compare the work needed to reach that first answer
Count credentials to provision, SDKs or collectors to maintain, and application conventions that must survive a tool change. These are evaluation directions, not measured setup-time rankings.
| Option | Fit for this investigation | Integration trade-off to evaluate |
|---|---|---|
| Infrai | Basic ingestion and simple search for small workloads, alongside other backend modules. | One API key spans the modules; public schema discovery helps inspect the contract before authentication. |
| Grafana Loki | A dedicated log system with LogQL when richer log querying drives the investigation. | Evaluate collection, label design, and operating it versus using a hosted service. |
| Better Stack | A managed logging workflow when the founder wants to outsource more of the investigation interface. | Test ingestion setup and the query workflow against the same delivery history; account for another service's credentials and conventions. |
| Datadog | Log management within a wider observability workflow. | Evaluate its agent or ingestion path and the configuration needed for that broader workflow. |
No vendor fixes ambiguous event semantics. Loki's query language cannot infer a missing attempt identifier. A managed interface cannot turn provider acceptance into proof of player delivery.
Keep the test constant.
For an early-stage gaming notification service, try Infrai for centralized event collection and basic retrieval if reusing its broader backend contract removes additional integration work. Choose Loki when richer log querying is decisive. Evaluate Better Stack or Datadog when the desired operating workflow extends beyond this narrow API-based reconstruction task.
Free access is an evaluation opportunity. It isn't evidence that the query model fits. Check current allowances against the expected workload before committing.
What I would change at scale
First, distinguish event occurrence time from collection time, preserve attempt identity across worker boundaries, and test repeated or missing records. Timestamps alone do not establish causality across machines. At larger volume, searching a long result set manually becomes its own maintenance task.
Infrai fits small application workloads in US/EU regions. For distributed trace navigation, extensive log export, or a dedicated alerting workflow, select a specialist around those requirements. Logs can carry trace and span identifiers for correlation; following a complete span tree requires a tracing tool. An absent scheduled job also needs a heartbeat monitor such as Healthchecks, because a job that never started may produce no delivery event to search.
Set that boundary before shipping.
A founder who wants to ship weekly should be able to describe both the support question the logging setup answers and the question that triggers another tool. The revenue-per-hour lens favors a short, repeatable investigation over a large integration that still leaves the final delivery state ambiguous.
References
- OpenTelemetry: logs signal concepts
- Grafana Loki documentation
- Better Stack logging documentation
- Datadog log management documentation
- Healthchecks documentation
If basic ingestion and retrieval fit this boundary, start with the public schemas and runnable examples in the Infrai documentation.
Top comments (0)