Home Guides Error Logging
Development

Error Logging: A Developer's Guide to Client-Side and Server-Side Logging

Production breaks in two places: in the browser and on the server. Error logging is how you see both—consistently, at scale, with enough context to fix issues before they become outages or silent revenue leaks.

11 min read Updated April 2026 By Inspectlet Team
Key Takeaways
  • Error logging spans the full stack: browser JavaScript errors (including unhandled promise rejections) and server-side exceptions, timeouts, and failed dependencies
  • A mature pipeline captures events, enriches them with correlation IDs and environment metadata, ships them to durable storage, and routes high-severity signals to humans
  • Structured logging (JSON) beats plain text for search, dashboards, and automated alerting at scale
  • Pairing error events with session replay collapses mean time to understand from hours to minutes
  • Treat log levels as a contract with your on-call rotation: misuse of ERROR creates alert fatigue; under-logging leaves blind spots during incidents

What is Error Logging?

Error logging is the practice of recording failures, anomalies, and exceptional conditions from running software so engineers can detect problems, diagnose root causes, and verify fixes. On the web, that almost always means two distinct surfaces: client-side (the user's browser executing JavaScript) and server-side (your application servers, APIs, workers, and databases).

People searching for error logging, browser error logging, web error logging, or a JavaScript error log are usually trying to solve the same underlying problem: production is opaque. Users experience broken checkout flows, blank screens, or silent form failures, while traditional server logs show healthy HTTP 200 responses because the failure never reached the API. Conversely, the UI can look fine while the backend returns 500s or times out—only server logs and traces reveal it.

Effective error logging closes that gap. It is not merely writing strings to a file. At a minimum, a useful error log entry answers: what failed, where in the code or infrastructure it failed, when it happened, who was affected (session, user, tenant), and under what conditions (release version, feature flags, browser, region). The best systems also answer what the user was doing, which is where behavioral tools intersect with classical logging.

Logging vs. Metrics vs. Traces

Logging captures discrete events with rich detail. Metrics aggregate behavior over time (error rate, latency percentiles). Traces follow a single request across services. Modern observability uses all three; error logging is often the first signal that something specific went wrong, while metrics tell you that error volume spiked.

Client-Side vs Server-Side Error Logging

Client-side and server-side logging are complementary, not interchangeable. Understanding their differences determines where you invest tooling and how you correlate incidents end to end.

Client-Side: Browser and JavaScript

Browser error logging focuses on the JavaScript error log: uncaught exceptions, failed dynamic imports, unhandled promise rejections, and optionally network failures surfaced to your application code. The browser sandbox means you never have direct access to the user's machine; you rely on instrumentation inside the page. That instrumentation typically hooks window.onerror and window.addEventListener('unhandledrejection', ...), then POSTs payloads to your backend or a third-party collector.

Challenges unique to the client include minified stack traces (solved with private source maps), cross-origin script restrictions that produce opaque Script error. messages, noise from browser extensions and third-party tags, and the fact that you cannot trust the client clock or tamper-proof the payload without additional design.

For a deep dive into capturing and prioritizing frontend failures, see our guide to JavaScript error tracking—it pairs naturally with the server-side patterns below.

Server-Side: Application and Infrastructure

Server-side error logging covers exceptions thrown in your application code, failed database queries, message queue dead letters, outbound HTTP timeouts to payment processors, and infrastructure events (OOM kills, container restarts). These logs usually have trustworthy timestamps, stable hostnames, and access to secrets management for redacting sensitive fields before persistence.

Server logs excel at proving whether an API contract was violated, which dependency failed, and whether retries exhausted. They are weak at explaining why a user clicked "Pay" three times unless you also log business-context identifiers (cart ID, experiment cohort) and correlate them with client-side session data.

One Request, One Correlation ID

Generate a correlation ID (UUID) at the edge (CDN, API gateway, or first application hop) and return it to the client in a response header. Include the same ID in every server log line and attach it to client-side error reports. During an incident, you can pivot from a user-reported screenshot to the exact server trace in seconds.

Building a Logging Pipeline

A logging pipeline is the path an error takes from occurrence to human awareness (or automated remediation). A production-grade pipeline has five stages: capture, enrichment, transport, storage, and consumption (search, dashboards, alerts).

1. Capture

Instrument both tiers. On the client, register global handlers early—before your application bundle executes deferred logic that might throw. On the server, use framework-level exception handlers (for example Express error middleware, Laravel's reportable exceptions, or PHP's centralized error handler) so nothing escapes unlogged.

2. Enrichment

Attach environment name, service name, release version or Git SHA, region, and user/session identifiers where privacy policy allows. For browser errors, include user agent, viewport size, and URL. For APIs, include route template (not raw URLs with query tokens), HTTP status, and latency.

3. Transport

Ship logs asynchronously. On the client, use sendBeacon or fetch with keepalive: true during page unload so errors during navigation are not dropped. On the server, prefer non-blocking appenders or dedicated log forwarders (Fluent Bit, Vector, Filebeat) over synchronous writes on the request path.

4. Storage

Centralize logs in a searchable system (ELK, Loki, CloudWatch Logs Insights, Datadog, Splunk). Retention policies should reflect compliance needs and debugging utility; 7–30 days hot, longer cold archive for regulated industries.

5. Consumption

Define saved searches for new error fingerprints, rate-based alerts, and integration with PagerDuty, Slack, or Opsgenie. The goal is not to notify on every log line but on novel or spiking error signatures.

// Minimal browser error capture + POST (illustrative)
(function () {
  var endpoint = '/api/client-errors'; // your ingest endpoint

  function send(payload) {
    try {
      if (navigator.sendBeacon) {
        var blob = new Blob([JSON.stringify(payload)], { type: 'application/json' });
        navigator.sendBeacon(endpoint, blob);
      } else {
        fetch(endpoint, { method: 'POST', body: JSON.stringify(payload),
          headers: { 'Content-Type': 'application/json' }, keepalive: true });
      }
    } catch (e) { /* never throw from reporter */ }
  }

  window.addEventListener('error', function (ev) {
    send({
      type: 'error',
      message: ev.message,
      source: ev.filename,
      lineno: ev.lineno,
      colno: ev.colno,
      stack: ev.error && ev.error.stack,
      page: location.href,
      ts: Date.now()
    });
  });

  window.addEventListener('unhandledrejection', function (ev) {
    var r = ev.reason;
    send({
      type: 'unhandledrejection',
      message: r && r.message ? r.message : String(r),
      stack: r && r.stack,
      page: location.href,
      ts: Date.now()
    });
  });
})();
<?php
// PHP: structured application error to stderr / log forwarder
function log_app_error(\Throwable $e, array $context = []): void {
    $record = [
        'ts'       => gmdate('c'),
        'level'    => 'error',
        'msg'      => $e->getMessage(),
        'exc_type' => get_class($e),
        'file'     => $e->getFile(),
        'line'     => $e->getLine(),
        'trace'    => $e->getTraceAsString(),
        'ctx'      => $context,
    ];
    error_log(json_encode($record, JSON_UNESCAPED_SLASHES));
}

Error Logging Built for Real User Sessions

Inspectlet captures JavaScript errors alongside session replay so you can see the clicks, inputs, and navigation that led to each failure.

See the Feature

Log Levels and Severity

Log levels are a prioritization language. When every message is tagged ERROR, on-call engineers cannot tell a cosmetic bug from a data-loss scenario. A practical convention for web applications:

Severity should reflect customer impact and blast radius, not developer frustration. A null pointer in a non-critical widget might be WARN until it affects conversion paths. A payment authorization failure is almost always ERROR or higher even if the exception is caught and shown as a toast.

Avoid Logging Secrets

Never write raw passwords, full payment card numbers, session cookies, or OAuth tokens into logs. If you must record that an authentication failed, log a salted hash of the user identifier or an internal user ID only. Structured logging makes accidental secret leakage more common because objects are serialized wholesale—implement allowlists for fields.

Structured Logging

Structured logging means emitting machine-parseable records (almost always JSON) with consistent keys. Plain English log lines read well in a terminal but resist aggregation: you cannot easily chart payment_timeout per region if each developer phrases messages differently.

Adopt a schema per service: required fields like timestamp, level, service, message, optional error.kind, error.stack, http.route, user.id_hash, trace_id. Version the schema when you make breaking changes. Your log platform can then index fields, build facet filters, and join with trace data.

// Node.js-style structured error (illustrative)
logger.error({
  msg: 'checkout_charge_failed',
  err: { message: err.message, stack: err.stack },
  http: { method: 'POST', route: '/api/checkout' },
  biz: { cart_id: cartId, amount_cents: 4999 },
  trace_id: req.traceId,
});

On the client, keep payloads small and avoid sending full DOM snapshots in the error log itself; that belongs in a dedicated replay pipeline. The JavaScript error log should still include enough identifiers to join with server and replay systems.

Error Logging + Session Replay

Stack traces and server logs tell you what the code did. They rarely tell you what the user intended. Session recording captures the sequence of interactions—clicks, scrolls, form edits, navigations—so you can watch the moments before an error fires.

When error logging is integrated with replay, triage changes fundamentally. Instead of reproducing a bug from a vague ticket, you open the session, observe the exact UI state, and confirm whether the issue is a race condition, a validation edge case, or a third-party script. Product and support teams can participate in debugging without reading stack traces.

Inspectlet's approach ties client-side error capture to the same session timeline as behavioral signals, which is why teams often adopt error logging alongside replay rather than maintaining disconnected tools. The feature page outlines how errors surface in the dashboard and connect to individual recordings.

Monitoring and Alerting

Logging without alerting is archaeology; alerting without tuning is burnout. Effective monitoring turns logs into SLOs: for example, "fewer than 0.1% of checkout sessions emit a JavaScript error" or "API 5xx rate below 0.5% over 5 minutes."

Implement alerts on:

Route severity-appropriate notifications: Slack for triage queues, paging only for customer-visible outages or data risks. Include runbook links and direct queries in the alert body so the responder does not start from a blank search bar.

Approach Best for Trade-offs Typical stack
File-only server logs Single-server apps, early-stage products Hard to search across hosts; no unified client view syslog, plain files, journald
Centralized log platform Multi-instance APIs, microservices Cost at volume; requires discipline on schema ELK, Loki, Datadog, Splunk, CloudWatch
APM + tracing Latency and dependency debugging Less narrative detail than rich log lines unless correlated New Relic, Honeycomb, OpenTelemetry
Client error SDK JavaScript error log, source maps, grouping Third-party noise; privacy review for PII Sentry, Bugsnag, built-in analytics tools
Replay + errors UX and conversion debugging Not a substitute for server metrics; sampling strategy matters Inspectlet and similar platforms
Hybrid observability Mature teams Higher integration effort; single pane of glass is rare Logs + traces + metrics + session data

Ship With Full Visibility

Start capturing errors and replays on your site in minutes. Free tier available—no credit card required to explore.

Start Free

Best Practices

  1. Instrument both sides of every critical journey. Checkout, signup, and password reset should emit correlated client and server logs so you can tell whether failure happened before or after the network boundary.
  2. Sample intentionally. Full-fidelity logging for 100% of sessions is expensive. Use dynamic sampling: higher rates for errors, lower for routine success paths, and always retain complete traces for errored requests.
  3. Version your releases in every log line. When error rates jump, the first question is "what shipped?" If the release SHA is in the payload, you can answer immediately.
  4. Test your logging in CI. A smoke test that triggers a handled exception and asserts the log record shape catches broken appenders before production.
  5. Review logs after every deploy. Schedule a 15-minute window to watch error dashboards; the fastest MTTR teams treat deploys as experiments with instant feedback.
  6. Document ownership. Each service and client bundle should have an on-call rotation and a runbook entry for "where logs live" and "how to trace a request."
  7. Align with privacy and security. Log retention, anonymization, and access controls are part of logging design, especially in GDPR- and HIPAA-sensitive environments.

Together, these practices turn error logging from a passive dump of strings into an operational backbone that supports both proactive reliability work and fast incident response.

Frequently Asked Questions

What is the difference between a JavaScript error log and server error logging?

A JavaScript error log records failures inside the user's browser: uncaught exceptions, promise rejections, and optionally application-level console.error hooks. Server error logging records failures on your infrastructure: unhandled exceptions in API handlers, database errors, and downstream timeouts. You need both to debug full-stack issues.

Why do I see "Script error." with no stack trace?

Cross-origin scripts without proper CORS attributes trigger browser security restrictions that hide error details. Serve your own bundles with correct crossorigin attributes and source maps, and treat third-party script errors as a separate classification from first-party code.

How long should we retain error logs?

Hot retention of 7–30 days is typical for debugging recent releases. Longer retention may be required for compliance or fraud investigation. Balance cost against the probability that you will need to compare a bug report from ninety days ago to today's codebase.

Should errors be logged synchronously on the server request path?

Prefer asynchronous or buffered appenders. Synchronous disk I/O on every request increases tail latency and can amplify outages under load. Use a forwarder process or dedicated logging sidecar for heavy volume.

Can session replay replace error logging?

No. Replay shows behavior; it does not replace structured server logs, metrics, or stack traces for backend failures. The strongest setups correlate replay with the same correlation IDs used in your JavaScript error tracking and API logs.

What is the single highest-impact improvement most teams skip?

Correlation IDs from edge to client to database. Without them, you are stitching timelines by hand across three dashboards. With them, error logging becomes a navigable system instead of a pile of messages.

See Every Error in Context

Client-side error logging with session replay: know what broke and what the user did when it happened.

Start Free