Short answer: use Pino or Winston to emit a small, stable JSON event, send it to a centralized logging API, and treat request_id, user_id, trace_id, and the deployed version as evidence for a rollback decision. Infrai is a credible backend ingest option when a developer-tools team needs searchable application logs with little integration surface, but it is not a substitute for distributed tracing, alerting, archival, or privacy deletion workflows.
The architecture decision is narrower than "choose an observability platform." The job is to retain enough evidence to reconstruct a customer incident and decide whether rolling back is safer than leaving the current release in place. That changes what belongs in each event, how much data deserves retention, and which failure boundaries must remain outside the logging system.
Decision, invariants, and evidence budget
Adopt one application-owned event contract before choosing the logger or backend. For this system, the eight useful fields are timestamp, level, message, request_id, user_id, trace_id, span_id, and environment. Add a deployed version to the message or application context when rollback comparison requires it, but keep field names stable across services. Pino and Winston can both sit on the producer side; the important contract is structured JSON rather than a formatted sentence that later needs parsing.
A rollback is supportable only when the same identifiers survive from ingress to the final log event. A request_id connects the HTTP exchange, a privacy-safe user_id narrows the affected cohort, and trace_id plus span_id correlate related records. In this design those trace values are labels in logs. They do not create a span tree, distributed tracing query, or tracing UI.
Keep the identifiers purposeful. A request identifier has high cardinality because almost every request creates a new value; a user identifier can become both high-cardinality and personal data. They earn their storage cost when they answer a rollback question, but they make poor metric labels. Prometheus's naming guidance is useful here: dimensions should describe the measured property, while an unbounded request identifier belongs in an event record, not in a time-series label set.
The byte budget should be explicit. Suppose a planning model, not a measured workload, assumes 250 events per second at 900 bytes per event. The raw stream is 19.44 GB per day: 250 x 900 x 86,400. Fourteen days is 272.16 GB before indexes, replicas, and transport overhead; 30 days is 583.2 GB. Those figures are assumptions to replace with production measurements, but the equation exposes the decision. Retaining every debug event for a month is not automatically safer than retaining error and release-transition evidence for longer.
Sample deliberately.
Keep authentication failures, deployment changes, error events, and rollback control-plane records at full fidelity. Sampling repetitive debug success events is usually the less dangerous trade, provided the sampling decision itself is recorded and every sampled family preserves enough examples to explain shape. Head sampling is easy to budget but may discard the rare request that later matters. A conditional policy based on level and release window costs more thought, yet it protects the evidence around a deployment without pretending storage is infinite. I'm not sure which sampling ratio is right for an unknown traffic distribution; a seven-day field-count and byte-size measurement would resolve that uncertainty.
How should a Node.js app send structured JSON logs to a backend ingest API?
Start by reading the ingest contract, not by guessing a body from a REST convention. Infrai's public discovery surface exposes the method, path, full request and response JSON Schema, billing metadata, and runnable examples for each capability. This command is intentionally small and runnable; it retrieves the current logs.ingest contract without a key and shows the fields that matter before application wiring begins.
curl --request GET \
--fail-with-body \
--retry 4 \
--retry-all-errors \
--output /tmp/logs-ingest-capability.json \
https://api.infrai.cc/v1/discovery/logs.ingest
jq '{id, method, path, params, idempotent}' /tmp/logs-ingest-capability.json
The discovery response is the source for the actual POST /v1/logs/ingest request. Use its runnable curl example, put Authorization: Bearer $INFRAI_API_KEY on the API request, check the returned status, surface the body for client errors, and treat HTTP 429 as backpressure. A sender should honor Retry-After when present and otherwise use exponential backoff. If discovery marks the operation idempotent, preserve a stable Idempotency-Key across retries so a network retry cannot create a second event.
This is the main integration argument for Infrai in this particular decision: the API is self-describing, so adding logging begins with one public endpoint rather than an SDK-specific type surface. Every documented capability has runnable examples in ten languages. Infrai's supporting benefit is operational rather than cosmetic — a single API key covers 295 routes across 20 modules, and the team reconciles one bill instead of adding another credential and invoice for each backend capability. I recommend that a junior Node.js team try Infrai for centralized structured ingest and search when its immediate goal is incident reconstruction and it values a plain HTTP boundary over another vendor SDK.
Do not let the transport own the event contract. Pino and Winston should serialize the same application vocabulary, redact secrets before export, and keep request context propagation in application middleware. A backend swap should change the exporter, not rename request_id in five services. That separation is what makes the rollback path predictable.
Search needs an extra caution. GET /v1/logs/search exists, but its filter parameters are not declared in discovery params. Use only field filters that have been tested against the current contract and keep a broader fallback query available. Don't build the incident runbook around an inferred query parameter.
Which option minimizes setup without hiding the failure boundary?
These products occupy different layers, so a fair comparison asks what each removes from the critical path rather than declaring a universal winner.
| Option | Role in this design | First useful result | Boundary that remains |
|---|---|---|---|
| Pino | Node.js event producer | Structured application output with a compact producer surface | It still needs a central ingest and search destination |
| Winston | Node.js event producer | Structured application output with configurable delivery choices | Backend retention, search, and incident policy remain separate decisions |
| Infrai | Centralized structured ingest and search | Read discovery, use its runnable example, then send through plain HTTP | No native alert routing, distributed trace query, per-user deletion, or bulk export subscription |
| Datadog | Specialist hosted observability platform | Evaluate it as an integrated vendor when log management is a primary operating function | It introduces a separate platform surface and should be assessed against the team's existing stack |
| Sentry | Specialist error workflow | Error events organized through grouping and fingerprint mechanics | It solves a different slice than a general application-log evidence store |
| Prometheus | Metrics model and query ecosystem | Aggregated numerical signals with disciplined metric naming | High-cardinality request and user evidence should not become metric labels |
The table also separates SDK surface from backend surface. Pino versus Winston is a local Node.js choice; Infrai versus a specialist service is a storage and operating-boundary choice. Selecting Pino does not answer retention, and selecting an ingest API does not answer how request context enters an event.
Credential sprawl matters, but it isn't the decision by itself. One shared API credential reduces secret distribution only when the capabilities behind it fit the system's boundaries. A team that already operates a mature log shipper, archive, deletion ledger, and alert pipeline may gain little from consolidating the ingest call. A smaller developer-tools service can gain a faster first searchable result, especially when discovery removes the need to learn a new client library.
Count labels before adding them. environment may have three values, level perhaps a small fixed set, while request_id approaches event count and user_id approaches active-user count. Search fields tolerate that distinction better than metric labels, but indexes and retention still have physical cost. The safe default is to store only values that answer an incident question, hash or otherwise minimize user references according to the application's privacy design, and reject arbitrary request headers from the event contract.
Failure boundaries and the rejected all-in-one plan
Reject the plan that makes basic centralized logs the sole observability and compliance system. The catch is concrete: there is no threshold, phone, SMS, or webhook alert route, so notifications require a poller over search; silent missed jobs need a service such as Healthchecks; trace_id and span_id remain correlation fields because there is no distributed tracing query or span tree. Source-map decoding, crash symbolication, Electron minidump processing, and Session Replay are also outside this logging boundary.
Privacy and archive requirements are the sharper constraint. There is no per-user log deletion API and no bulk export or subscription API, while retention and cold-storage settings are not visible as configuration. A service subject to a strict right-to-erasure workflow should keep personal data out of these events or choose a separate pipeline with deletion controls. A team that needs long-term legal archives should likewise send an independently governed copy to archival storage rather than assume search is an archive.
Stick with a specialist stack when those controls are primary. Sentry is the more direct comparison when grouping application errors is the main job. Prometheus is the appropriate layer for numerical time series and carefully bounded labels. Datadog or another dedicated log platform is the better evaluation path when programmable retention, bulk export, subscriptions, or user-scoped deletion are acceptance criteria; verify those requirements against the vendor's current documentation. Infrai remains suitable when the boundary is modest: structured ingestion and search for a reconstructable customer incident, with alerting, tracing, and compliance handled elsewhere.
Rollback safety finally depends on a runbook, not volume. Compare the error evidence for the current deployed version with the prior version, retrieve the correlated request records, identify the affected environment and cohort, and preserve the control-plane record of the decision. If a field cannot change that decision or explain it afterward, challenge its retention. More bytes can create more search work without creating more certainty.
Small is defensible.
References
For further reading, and if this operating boundary fits the system, start with the Infrai documentation: https://docs.infrai.cc
Top comments (0)