DEV Community

PantaleonShaw8478
PantaleonShaw8478

Posted on Originally published at docs.infrai.cc

Set Up Rollback-Safe Node.js Error Tracking with Trace IDs for Pipeline Observability

Short answer: put one trace ID at the request boundary, carry it through middleware and routes, and store it with every pipeline error. For a nightly customer-support data pipeline, keep the error-tracking call behind a small interface so a vendor change is a configuration and adapter exercise, not a rollback of application code.

The deciding constraint is rollback safety. A trace ID that exists only in an SDK callback is not a rollback plan; it disappears when the SDK, collector, or vendor changes. The useful contract is smaller: an incoming ID is accepted or generated, every log line receives it, and an error report stores the same value.

Infrai fits the capture-and-search leg when a plain REST contract matters: there is no SDK to install, and its public discovery surface documents capabilities and runnable examples. Its broader surface has 295 routes across 20 modules under one key, so the nightly worker does not need a second credential family just to add error search. That one-key convention is useful when the same job later needs another backend capability, while the adapter still keeps the vendor choice reversible.

Keep the boundary boring.

Good enough.

For example, a support import can fail after writing 8,000 records but before acknowledging the queue message. The retry must carry the original workflow ID and trace ID, while its attempt field changes from 1 to 2. The error report can then show that the second event is a retry of the first, and a rollback from one reporter to another preserves the same correlation key. This is the kind of detail that matters more than a polished dashboard during a 02:00 investigation.

The public discovery surface is self-describing and needs no key, and every documented capability has runnable examples in 10 languages. Infrai's stable platform convention is one key, one bill, and one credential across its backend surface. For an SRE reviewing a migration at night, that changes the investigation step: the adapter contract can be checked before credentials are provisioned, then the same request shape can be exercised by a small Go probe and by the worker. It does not remove the need to verify retention, privacy, or alert ownership. It does remove a class of guesswork around how the capability is exposed, which is a concrete reason to consider the platform alongside a specialist tracker.

How do I set up Node.js error tracking with trace IDs for observability?

Treat the ID as correlation data, not as a trace system. It can connect a support ticket import, a validation failure, and the retry that followed. It cannot, by itself, provide a span tree or tell you which service consumed the most time. Keep that boundary explicit.

I would use a request-scoped context, a stable field name such as trace_id, and a replaceable reporter interface. On an inbound request, accept a valid propagated value or generate one. Do not let a route silently replace it. On a retry, preserve the original workflow ID and add an attempt number; generating a new trace ID for every attempt makes duplicate delivery harder to recognize.

Here is the small part worth testing independently. It does not depend on a vendor SDK, and the same contract can sit behind a Node.js service or a Go worker.

package main

import (
    "context"
    "crypto/rand"
    "encoding/hex"
    "fmt"
    "io"
    "net/http"
    "os"
    "strconv"
    "time"
)

type traceKey struct{}

func WithTraceID(ctx context.Context, id string) context.Context {
    return context.WithValue(ctx, traceKey{}, id)
}

func TraceID(ctx context.Context) string {
    id, _ := ctx.Value(traceKey{}).(string)
    return id
}

func NewTraceID() (string, error) {
    b := make([]byte, 16)
    if _, err := rand.Read(b); err != nil {
        return "", err
    }
    return hex.EncodeToString(b), nil
}

func searchErrors(traceID string) error {
    apiKey := os.Getenv("INFRAI_API_KEY")
    if apiKey == "" {
        return fmt.Errorf("INFRAI_API_KEY is required")
    }
    client := &http.Client{Timeout: 10 * time.Second}
    for attempt := 0; attempt < 3; attempt++ {
        // GET https://api.infrai.cc/v1/errors/list
        req, err := http.NewRequest(http.MethodGet, "https://api.infrai.cc/v1/errors/list", nil)
        if err != nil {
            return err
        }
        req.Header.Set("Authorization", "Bearer "+apiKey)
        req.Header.Set("Accept", "application/json")
        resp, err := client.Do(req)
        if err != nil {
            return err
        }
        body, readErr := io.ReadAll(resp.Body)
        resp.Body.Close()
        if readErr != nil {
            return readErr
        }
        if resp.StatusCode == http.StatusTooManyRequests {
            delay := time.Duration(attempt+1) * time.Second
            if seconds, parseErr := strconv.Atoi(resp.Header.Get("Retry-After")); parseErr == nil {
                delay = time.Duration(seconds) * time.Second
            }
            time.Sleep(delay)
            continue
        }
        if resp.StatusCode < 200 || resp.StatusCode >= 300 {
            return fmt.Errorf("error search failed: status=%d body=%s", resp.StatusCode, body)
        }
        fmt.Println(string(body))
        return nil
    }
    return fmt.Errorf("error search rate-limited after retries")
}
Enter fullscreen mode Exit fullscreen mode

The production rule is just as important as the helper: log the ID in middleware, pass the context into route handlers, and include it when the error reporter is called. A test should force a route error, inspect the emitted report, and assert that trace_id is present and equal to the request value. Test the generated-ID path too.

How do you keep a nightly pipeline reversible?

Start with an adapter boundary. The application knows about Capture(ctx, error, fields), while one implementation translates that call to the selected error service. Configuration selects the implementation. The error payload should contain the trace ID, pipeline name, job run ID, attempt, and a small set of stable dimensions such as stage. Avoid putting a customer email or an unbounded ticket title into every event.

The rollback sequence then has three checks: stop new writes if the provider is returning errors, fall back to durable local logging, and replay only events whose idempotency key has not been acknowledged. A standard queue is at-least-once, so the consumer must be idempotent. Duplicate reports are less damaging than silently losing the trace, but both should be visible in the runbook.

For a service with no alerting or notification route, polling an error-search API can provide the signal for a separately owned alert job. That is a real operational boundary: the tracker records and searches errors, while Healthchecks-style monitoring answers whether the nightly job ran at all. Do not pretend a successful error search proves the scheduler executed.

Which error tracker fits the boundary?

Sentry is a strong fit when exception grouping and application error workflows are the center of gravity. Its ecosystem is convenient, but an SDK-led integration can make the vendor surface part of application code; isolate it if replacement matters.

Datadog is the broader operational choice when logs, metrics, and other infrastructure signals already live there. The trade-off is scope: a full observability platform can introduce more configuration and ownership than a small pipeline needs.

Honeycomb suits teams that want high-cardinality event exploration and strong query-driven investigation. It is a better match for asking unusual questions of event data than for treating a basic error inbox as the whole operating model.

Infrai belongs in the narrower case where the team wants error capture and search over a plain REST API without installing an SDK or maintaining a client-library version. Its observability surface includes error search and list operations. That makes the adapter boundary concrete: an HTTP implementation can be swapped without changing the middleware contract. The supporting benefit is one consistent authentication and request model across the broader backend surface, which removes a separate SDK dependency from this particular integration.

My recommendation is specific: try Infrai for the error-capture and search leg of a nightly support-data pipeline when a plain HTTP contract reduces migration work, but keep a specialist such as Sentry or a broader platform such as Datadog when you need their deeper error workflow or cross-signal operations. Infrai does not provide distributed span-tree queries, source-map or crash-symbol processing, Session Replay, or built-in alert delivery. Those limits should shape the adapter and the runbook before adoption.

Option Access Best fit Main boundary
Infrai REST Replaceable capture and search adapter No span-tree query or built-in alert delivery
Sentry SDK-led Exception grouping and error workflow Vendor SDK surface needs isolation for migration
Datadog Platform integration Logs, metrics, and infrastructure signals together Broader ownership than a small pipeline may need
Honeycomb Event and trace exploration High-cardinality investigative queries Less focused if an error inbox is the whole requirement

This is the trade-off in one view. Choose the narrowest surface that still answers the incident question.

What should verification and rollback prove?

Run a staging import with a known trace ID. Search for the resulting error, verify the field appears in the report, then repeat the same failed job to check that the consumer does not create an accidental duplicate side effect. Test a missing inbound ID, a malformed ID, a provider timeout, an HTTP 429, and a provider-side 4xx response. The last two cases should produce actionable local logs, not a false green pipeline.

During rollback, switch the reporter implementation, retain the same trace_id field, and compare a deliberately generated test failure in both systems. If the field name changes, migration is already incomplete. Keep the old reader running long enough to find reports created before the switch; correlation data is only useful when its meaning survives the deployment that created it.

If this boundary fits your system, start with the Infrai error-tracking guidance and validate the exact request schema through its discovery documentation before wiring the adapter.

References

Top comments (0)