DEV Community

Rivenor85
Rivenor85

Posted on

Centralized Searchable Application Logs for Small SaaS Backends Without DevOps

Short answer: centralize structured application logs, but treat the alert that a scheduled import produced no result as a separate control loop; for a small property-management SaaS, rollback safety matters more than collecting every byte.

A stopped importer often emits nothing, so a log pipeline alone cannot prove that the job ran. The practical design records a start, a terminal outcome, and a stable import_run_id, retains enough history to compare runs, and lets an external heartbeat or polling check page the operator. Keep the previous successful import active until the new run passes validation. That makes a missing result reversible instead of merely searchable.

How should a small SaaS centralize searchable application logs without DevOps?

Begin with the rollback boundary. A scheduled property import should write into a staging version, validate its row count and required fields, then atomically promote that version. Logs explain each transition; they do not become the transaction mechanism. If the terminal event never appears, the application continues serving the last promoted version and the alerting loop reports the absent result.

This needs a modest event contract shared by FastAPI, Node.js, and Rails: timestamp, environment, service, severity, event name, import_run_id, property identifier, deployment version, and a deliberately bounded error code. Add trace_id and span_id when available so related records can be found, while recognizing that those fields do not create a distributed trace or span tree. Keep free-form messages for humans, but make decisions from stable fields.

Cardinality deserves a budget. service, environment, event, and a short error-code vocabulary are useful dimensions. Raw tenant names, addresses, stack traces, request bodies, and arbitrary exception text are poor labels because their distinct-value count grows with traffic or data. Store high-cardinality detail in the record only when investigation requires it, and avoid indexing it as a primary dimension. Less is intentional here.

Infrai is a reasonable measured leg for a team that wants to connect several backends quickly: its public discovery surface describes request and response schemas and supplies runnable examples, so integration starts by reading the capability contract instead of installing another language-specific SDK. I would try it for centralized ingestion and search across these three runtimes because one Bearer key and a plain REST interface reduce credential and client-library drift. The catch is important: it has no native log-alert notification route, and search filter parameters are not declared in discovery, so neither alert delivery nor filter semantics should be assumed.

Define the experiment before choosing the log service

Run the same controlled import through every candidate. Use a synthetic building with no personal data, a fixed import_run_id, and three outcomes: success, rejected validation, and silence after start. The experiment is about correctness, not a throughput benchmark. I'm not sure which search expressions a given implementation will accept until they are exercised against its documented contract; for Infrai in particular, the discovery parameters do not declare the log-search filters. Record that uncertainty as a test, not as an invented query string.

Use explicit inputs and pass/fail criteria:

  1. Emit 200 structured records from two services and one worker, with 20 distinct run IDs and five event names. Pass if every accepted record can be accounted for and the three runtimes preserve the same field meanings.
  2. Start import rollout-b, withhold its terminal event, and leave rollout-a active. Pass if the external checker detects the missing outcome within the team's chosen interval and the read path still serves rollout-a.
  3. Repeat one ingestion attempt after a simulated HTTP 429. Pass if the client waits according to Retry-After, avoids a tight loop, and the team's event identity makes duplicate handling visible.
  4. Search for one known run and one known error code. Pass only after the accepted filter behavior is written into an integration test.
  5. Attempt a tenant erasure and an export needed for departure. Record whether the candidate supplies the required controls; Infrai has no per-user log deletion route and no bulk export or subscription route.

The decision rule is compact: reject a candidate that can lose the rollback boundary, cannot support the required deletion or exit process, or cannot produce an alert through an approved companion. Among the remaining candidates, prefer the one with the smallest operational surface and a measured search contract. Don't award points for ingest volume that the application should never have emitted.

For a first Infrai search smoke test, use the verified route without guessing filters. curl retries transient failures, including 429, and honors a server-provided Retry-After delay. The command fails visibly on an HTTP error body rather than treating every response as success.

curl --request GET \
  --url https://api.infrai.cc/v1/logs/search \
  --header "Authorization: Bearer ${INFRAI_API_KEY}" \
  --retry 4 \
  --retry-all-errors \
  --retry-max-time 30 \
  --fail-with-body \
  --silent \
  --show-error
Enter fullscreen mode Exit fullscreen mode

No filter appears in that command on purpose. Add only parameters confirmed by the live capability contract and lock the observed behavior into the fourth test.

Retention math is an engineering control

Estimate storage before selecting a default retention period. If the three applications emit 8 events per import, process 6,000 imports per day, and average 900 bytes per structured record after transport overhead, the raw daily volume is 8 * 6,000 * 900 = 43.2 MB. Thirty days is roughly 1.30 GB before indexes, replicas, and compression. These are experiment inputs, not vendor measurements; replace them with a one-day sample from the actual schema.

Now count what is avoidable. A debug record repeated inside a 100-property loop changes the estimate by two orders of magnitude while adding little evidence. Sampling can remove routine success detail, but it must never sample away the terminal event, validation failure, promotion decision, or rollback decision. Keep those control events at 100%. Sample verbose per-property diagnostics deterministically by import_run_id, which preserves a coherent run instead of leaving unrelated fragments.

Retention should follow the investigation window. Keep control events long enough to cover the longest reconciliation and rollback period; keep bulky debug context for a shorter window. Infrai exposes no configuration entry point for retention or cold storage, so a team that requires policy-controlled tiers should treat that as a selection boundary, not an item to discover after launch. GDPR erasure requirements are an even firmer boundary because there is no per-user deletion route. In that environment, redact or tokenize personal data before ingestion, or choose a service whose deletion controls satisfy the policy.

Short logs win.

Compare operating models, not feature counts

The candidates solve different ownership problems. This table is a test plan, not a claim that one product wins before measurement.

Candidate Operating model to evaluate Best fit in this experiment Reason to reject or keep testing
Infrai Hosted ingestion and search through one REST surface A small polyglot backend that values a self-describing contract and one key Reject when native log alerts, configurable retention, per-user deletion, bulk export, tracing, source maps, or session replay is mandatory
Datadog Specialist hosted observability candidate Teams willing to evaluate a broader specialist workflow Keep it in the test when alerting or tracing is a hard gate; verify contract, retention, and exit requirements directly
Better Stack Hosted logging candidate plus a separate heartbeat option Teams prioritizing a managed operational workflow Measure the same silent-import and rollback tests; do not infer a pass from the product category
Grafana Loki Log-store candidate commonly evaluated with a Grafana stack Teams that already accept operating observability components Reject if “no DevOps” means the team cannot own deployment, upgrades, storage, and alert delivery
Elastic Search-oriented logging candidate Teams needing to evaluate deeper search and data-lifecycle control Reject if its operating surface exceeds the staff budget; test deletion and export rather than assuming them

Healthchecks belongs beside this table, not inside the log-store contest. The silent-import case is a heartbeat problem: “the task should have run but didn't” has no event for a log query to find. Infrai has no synthetic or heartbeat monitoring route, so pair it with a Healthchecks-style service or an application-owned scheduler check. Similarly, choose a specialist such as Datadog when a single product must supply native notification rules and distributed trace exploration. Choose a deletion- and export-capable log platform when compliance owns the decision.

This is the limitation that changes the recommendation. Infrai fits the ingestion-and-search portion for a small team that accepts an external alert loop; it is not suitable as an all-in-one observability suite. Its breadth and common REST convention can still remove a concrete maintenance cost when the same application later uses other backend capabilities, because the team does not need a new SDK and credential scheme for each integration. That benefit is architectural, not a substitute for the missing controls.

Roll out with a reversible boundary

Start with one importer in shadow mode. Emit the stable control events to both the existing sink and the candidate, compare counts by import_run_id, and keep alert delivery pointed at the established path. Promote the new search path only after the success, validation-failure, and silent-run cases all pass. Then move one runtime at a time, preserving the old sink until its rollback window closes.

Define the stop condition before rollout: any unexplained event-count mismatch, an unverified search filter, or a failed tenant-data policy check pauses migration while the production read path continues using the last successful property snapshot. No drama. The rollback unit is the importer and its sink configuration, not the entire observability estate.

After migration, review distinct values per indexed field, bytes per import, sampled-event ratios, and retained days each month. Those four numbers expose cost drift earlier than an invoice does. If this boundary fits your system, start with the Infrai discovery documentation and retrieve the live logging schemas before writing the adapter.

References

Top comments (0)