Camofox-Browser Structured JSON Logging Format: A Complete Guide to Request IDs

Camofox-browser emits one-line JSON objects for every log entry, automatically injecting a unique request ID (reqId) to enable end-to-end tracing across HTTP requests and domain-specific events.

The camofox-browser project (hosted at jo-inc/camofox-browser) implements a machine-parseable logging system using structured JSON output. This format ensures every log entry includes temporal, severity, and contextual metadata while correlating related operations through request-scoped identifiers.

Core Logging Architecture in server.js

The log() Helper Function

In server.js (lines 38-45), the log() function constructs the standardized payload:

function log(level, msg, fields = {}) {
  const entry = {
    ts: new Date().toISOString(),
    level,
    msg,
    ...fields,
  };
  const line = JSON.stringify(entry);
  if (level === 'error') {
    process.stderr.write(line + '\n');
  } else {
    process.stdout.write(line + '\n');
  }
}

Each invocation produces a single JSON line written to stdout (or stderr for error-level entries). The base schema includes:

  • ts: ISO-8601 timestamp when the log was created
  • level: Log severity ("info", "warn", or "error")
  • msg: Short event identifier (e.g., "req", "res", "tab created")
  • Dynamic fields: Any additional key/value pairs supplied via the fields argument

Request ID Generation and Correlation

Incoming Request Logging (Lines 62-65)

When an HTTP request arrives, camofox-browser generates a short random request ID (reqId) using the first 8 hexadecimal characters of a UUID. The middleware immediately logs the incoming request:

log('info', 'req', { reqId, method: req.method, path: req.path, userId });

This creates a structured entry with the fields reqId, method, path, and userId, establishing the tracing context for the request lifecycle.

Outgoing Response Logging (Lines 77-79)

Upon request completion, the server logs the response metadata:

log('info', 'res', { reqId, status: res.statusCode, ms });

The res event includes the same reqId, allowing you to calculate duration via the ms field (elapsed milliseconds) and verify the HTTP status code.

JSON Log Format Specification

All later log statements—such as tab creation events, proxy interactions, or error handlers—propagate the originating reqId when available. This design enables end-to-end tracing of a request through the entire server stack.

Example log sequence:

{"ts":"2026-04-15T12:34:56.789Z","level":"info","msg":"req","reqId":"a1b2c3d4","method":"POST","path":"/tabs/123/navigate","userId":"agent1"}
{"ts":"2026-04-15T12:34:57.012Z","level":"info","msg":"tab created","reqId":"a1b2c3d4","tabId":"123","userId":"agent1","url":"https://example.com"}
{"ts":"2026-04-15T12:34:57.123Z","level":"info","msg":"res","reqId":"a1b2c3d4","status":200,"ms":334}

In this sequence, the first line records the request intake, the second shows a domain-specific event (tab creation) carrying the same reqId, and the third records the response timing. The consistent reqId value (a1b2c3d4) correlates these separate log entries into a single trace.

Module Integration and Propagation

The structured logger is centralized in server.js and consumed across the codebase. Modules such as lib/youtube.js and lib/fly.js import the log helper or receive it via dependency injection, inheriting the same JSON format and request ID propagation logic.

Notably, lib/metrics.js handles Prometheus metrics separately and does not write to the structured logger, maintaining a clean separation between metrics collection and log aggregation.

Summary

  • Base format: Every log is a single-line JSON object with ts, level, msg, and dynamic fields written to stdout/stderr.
  • Request tracing: A unique 8-character hex reqId (derived from a UUID) correlates all log entries belonging to a single HTTP request.
  • Lifecycle events: The system logs msg: "req" on entry and msg: "res" on exit, including timing (ms) and status codes.
  • Source location: Core implementation resides in server.js (lines 38-45, 62-65, 77-79), with downstream modules importing the helper.

Frequently Asked Questions

What fields are included in every camofox-browser log entry?

Every log entry contains three base fields: ts (ISO-8601 timestamp), level (severity string), and msg (event identifier). Additional contextual fields—such as reqId, method, status, or custom domain data—are spread into the object via the fields parameter of the log() function.

How is the request ID generated in camofox-browser?

The request ID (reqId) is generated from the first 8 hexadecimal characters of a UUID. This short identifier is created when an HTTP request first arrives and is subsequently injected into all related log entries for that request lifecycle, enabling distributed tracing across asynchronous operations.

Where does camofox-browser write its structured logs?

The logging system writes JSON lines to stdout for all non-error levels (info, warn). Entries with level error are routed to stderr. This separation allows containerized environments and log aggregation systems to handle errors differently from informational output while maintaining the same JSON schema.

Correlate entries by filtering for the reqId field. Since the middleware propagates this identifier from the initial "req" event through subsequent operations (like "tab created") to the final "res" event, you can trace a complete request lifecycle by selecting all logs where reqId matches your target value.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →