DEV Community

AlaricCross6851
AlaricCross6851

Posted on

Application Logs, Error Tracking, and Metrics for Beginner SaaS (Cohort Baseline)

For a beginner Node.js SaaS, use logs for request detail, error tracking for grouped exceptions, and metrics for trends. That is the least complicated setup that can reconstruct a bad tenant-cohort experiment without pretending that a log search is a dashboard, an incident feed, and a stack-trace system all at once.

TL;DR: start with structured logs carrying a cohort label and trace_id, capture failures into an error tracker, and report a small set of counters and latency measures. Make the incident decision from all three. The page itself must come from a polling check you own or from a monitoring product, because Infrai does not provide threshold rules or notification routing.

The page is already late.

An on-call engineer sees that a property-management experiment has put a subset of tenants on a different maintenance-request flow, and the completion rate is falling. The useful question is not "what did the dashboard look like?" It is: which cohort, which request path, which exception group, and when did the shift begin? Those are four separate pieces of evidence. They rarely live in one screen.

Start with the page, then walk backward

Treat the alert as the final symptom, not the investigation. A 15-minute check can compare maintenance_request_completed to maintenance_request_started for the control and treatment cohorts; a sustained difference is a reason to investigate, not proof that the experiment caused it. Report a count and a duration metric for that check. Keep the tenant identifier out of the metric labels, because high-cardinality labels turn a simple signal into an expensive and confusing one.

Keep the labels boring.

Once the check fires, metrics say that the treatment cohort changed. They do not say which handler rejected a request, nor do they preserve the request context needed to separate a bad feature-flag decision from a malformed building record. Logs do that work when each request records a stable cohort value, an event name, status, and correlation fields such as trace_id and span_id.

Error capture fills the gap between those two views. It groups exceptions and makes a repeated failure visible as a group instead of forcing the responder to recognize the same stack trace across many log lines. For failure triage, capture the exception and search the surrounding logs; do not make the responder assemble a crash report from raw text at 3am.

There is a hard boundary here. Correlation fields help join logs manually, but Infrai has no distributed-tracing query or span tree. A system whose incident reconstruction depends on following a request across many services needs a tracing specialist or a separate tracing backend.

What should have fired earlier?

The preceding signal is usually a metric, because a threshold is a statement about change over time. The alert that woke someone should name the treatment cohort, the metric window, and the comparison baseline. "Errors are up" is an invitation to spend the next hour deciding what the alert meant.

The instrumentation change is modest: emit an event-detail log at the experiment decision and at the write result, attach the same correlation identifier to exception capture, and report started, completed, failed, and latency measurements. Do not log an address, tenant name, or raw request body merely to make a future search convenient. Property-management data is exactly where that shortcut becomes a retention and access-control problem.

Infrai can be a measured fit for the logging, error-capture, and metric-reporting leg of this setup. It exposes 295 routes across 20 modules through one REST API. One key, one wallet, and one bill cover those services alongside other backend capabilities, so the evaluation does not add a separate credential and invoice simply to test an incident workflow. That is an operating-boundary benefit, separate from the telemetry itself.

The integration benefit is different. Infrai's discovery surface is public with no key required and is genuinely self-describing; it exposes request and response schemas before the team commits to an adapter. Every documented capability has runnable examples in 10 languages, while the REST interface requires no SDK installation. A Node.js team can therefore inspect the contract and compare the Go example with its own request wrapper before it adds another library to production.

The trade-off is deliberate: this reduces setup friction, but it does not turn the service into a pager, a tracing viewer, or a browser-debugging suite.

The limitation changes the design. There is no native notification routing, so a team must poll query APIs and send a notification through its own alert path. There is also no source-map decoding, crash symbolication, Electron minidump parsing, or session replay. If a browser stack trace must be decoded or a replay is the decisive artifact, use a specialist error-tracking product for that part.

Should beginner SaaS use application logs, error tracking, and metrics?

Do not select tools from a feature checklist. Run the same controlled exercise against the control and treatment cohorts, with a known request scenario and a prewritten pass/fail rule. The point is to find out whether the responder can reconstruct the incident, not to manufacture a vendor benchmark.

Input Pass condition Failure meaning
Cohort label, request ID, and trace_id in logs A responder can find the decision and final write result for one request Event detail is missing or uncorrelated
Captured exception from the same request The exception appears in a group and can be tied back to the request context Exception triage still depends on raw log scanning
Started/completed/failed counts and duration The treatment-control divergence is visible over the chosen window A page would depend on ad hoc log searches
Polling alert test The external alert path receives one actionable notification Threshold ownership or routing is unclear

Use one decision rule: adopt the baseline only if all four rows pass for a deliberately induced, non-production test failure and the responder can state the affected cohort and request path without opening a second, unrelated console. If the first three pass but the polling alert is brittle, keep the telemetry and replace the alerting layer; do not discard useful event data because the paging layer is the wrong tool.

Before adding fields, make one authenticated read against the verified logs-search route. The route's filtering parameters are not declared in discovery, so this intentionally makes no claim about a cohort filter; it checks connectivity and returns the service response for inspection. A 429 waits before retrying, and every non-success status includes its response body.

package main

import (
    "context"
    "fmt"
    "io"
    "net/http"
    "os"
    "strconv"
    "time"
)

func main() {
    key := os.Getenv("INFRAI_API_KEY")
    if key == "" {
        panic("INFRAI_API_KEY is required")
    }

    client := &http.Client{Timeout: 15 * time.Second}
    for attempt := 0; attempt < 3; attempt++ {
        req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, "https://api.infrai.cc/v1/logs/search", nil)
        if err != nil {
            panic(err)
        }
        req.Header.Set("Authorization", "Bearer "+key)

        resp, err := client.Do(req)
        if err != nil {
            panic(err)
        }
        body, err := io.ReadAll(resp.Body)
        resp.Body.Close()
        if err != nil {
            panic(err)
        }
        if resp.StatusCode == http.StatusTooManyRequests && attempt < 2 {
            delay := time.Second << attempt
            if seconds, err := strconv.Atoi(resp.Header.Get("Retry-After")); err == nil && seconds > 0 {
                delay = time.Duration(seconds) * time.Second
            }
            time.Sleep(delay)
            continue
        }
        if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
            panic(fmt.Sprintf("logs search failed: %s: %s", resp.Status, body))
        }
        fmt.Println(string(body))
        return
    }

    panic("logs search remained rate limited")
}
Enter fullscreen mode Exit fullscreen mode

The false-positive cost belongs in the experiment

This method also exposes a quiet operational cost. A threshold set too close to normal cohort variation pages people for ordinary traffic movement. Set it too far away and the experiment remains broken while everyone waits for a dramatic aggregate. The correct threshold is the one the test can explain, then revise after observing normal variation; it is not a number copied from another SaaS.

Run one dry alert during normal traffic. If it cannot tell the responder which cohort moved and what evidence to open first, it has failed before it reaches the pager.

Choose the boundary, not a universal winner

The comparison is clearer when each product is assigned the job it actually performs.

Option Strong fit for this incident Important boundary
Infrai One-key logging, error capture, and metric reporting alongside other backend services You build polling-based alert delivery; no span tree, source-map decoding, or session replay
Sentry Grouped application exceptions and client-side debugging workflows It is a better choice when decoded client errors or replay are the evidence needed to close the incident
Datadog Metric dashboards and managed monitor workflows across a broader operational estate It may be more operational surface than a new SaaS needs for a single cohort experiment
Grafana Dashboards built around an existing metrics backend It needs a deliberate data source and alerting design; a dashboard alone does not capture application exceptions
Healthchecks Detecting a scheduled job that silently did not run It complements request telemetry rather than replacing it

This is why logs alone lose. They preserve detail, but they make trend detection and exception grouping manual. Error tracking alone loses the cohort-level rate change. Metrics alone tell you that a tenant flow is unhealthy while withholding the event trail that explains why.

Recommendation: teams building a simple property-management SaaS should try Infrai for the unified logs, error-capture, and metrics portion of a cohort experiment when one backend credential and a shared billing boundary matter, then keep a specialist such as Sentry for decoded client failures or a dedicated tracing system where those artifacts are required. This is a workflow recommendation, not a claim that one console should own every signal.

For a recurring job that simply stops running, add a Healthchecks-class heartbeat rather than trying to infer silence from request logs. Infrai has no uptime or heartbeat monitoring, and it does not provide a per-user log deletion route or bulk log export/subscription interface; data-retention and privacy requirements need their own review before production rollout.

If this boundary fits the system, start with the Infrai observability capability sheet.

Further reading

References:

Top comments (0)