Skip to content

Find Brisket Client Logs in Axiom

Brisket browser reports are logs with service brisket and event source=browser. Use this runbook when investigating frontend errors, checkout failures, or the tags, extra context, and breadcrumbs previously sent to Sentry.

For Faceted create unavailable reports, inspect attributes.context.submit.serverReason. Payment-past-due rejections use payment_past_due; unsupported GFY characters use unsupported_character. These classifications describe rejected submissions, not failed render jobs.

Explore and Get inspired family-resolution failures include attributes.context.resolution.requestId and elapsedMs. Search server spans for faceted.resolution_request_id with the same UUID. Each open or retry gets a new UUID and fetches a fresh family rather than sharing the five-minute query cache. Requests that never reach the authenticated resolver have no matching server attribute. Gallery, dedicated preset pages, and submission do not yet carry this resolution correlation.

attributes.context.browser.online and visibility describe browser state at report time. They are diagnostic hints, not proof of connectivity. Reports do not add raw prompts, request payloads, or server error messages.

Model changes in preset and custom-prompt forms preserve the selected SFW/NSFW axis, regardless of family axis or option order. Only an explicit rating change can change that axis. If the requested model lacks that rating, the resolver falls back within the same rating; if none is available, submission is blocked. Other later axes still reset to their authored defaults.

The reporting path is browser capture → same-origin POST /api/telemetry → server Pino logger → OpenTelemetry logs → Axiom. The server verifies user identity and supplies the browser source label. Its OTel resource runtime is nodejs, while the forwarded event’s runtime is browser. Filter by the event source; filtering by resource runtime can select the wrong reports.

Sources: browser capture, ingestion route, metadata, and Node exporter.

  • Start with beef-prod for production or beef-staging for staging; verify the effective dataset in the deployment’s BRISKET_OTEL_TRACES_LOGS_HEADERS (x-axiom-dataset). Never copy its authorization value into a query or report.
  • Use the logs/traces dataset, not an *-otel-metrics dataset. See the Axiom dataset inventory.
  • Start with the incident’s time window. If unknown, use the last hour, then widen to 24 hours. Record the timezone and exact window when sharing results.

Production browser-log delivery and the source, severity, and payment-tag queries were verified in beef-prod on 2026-09-22. Live events included breadcrumbs, context, exception stacks, user identity, and browser release. Staging was not checked. Inspect an event if another dataset’s layout differs.

In Axiom, open Query → Builder, select the dataset and time range, and add service.name == brisket under Where. Run and expand an event. In Editor, the equivalent discovery query is:

['beef-prod']
| where _time > ago(1h)
| where ['service.name'] == "brisket"
| sort by _time desc
| limit 20

In the verified production log layout, service.name is a top-level field and event metadata is exposed as attributes.source, attributes.path, attributes.tags, and similar fields. Use ['attributes.source'] in APL. The event viewer displays these fields inside an attributes object.

Do not use ['attributes.custom']['source'] for these browser logs: that filter returned no events even while client reports were arriving. Trace attributes can use a different layout. Inspect body, severity_text, and attributes on a log event before adapting queries to another dataset.

References: Axiom Builder, OTel field mappings.

Replace beef-prod with beef-staging when investigating staging. Each pipe passes matching events to the next step; where filters rows, sort orders them, and limit caps the result.

['beef-prod']
| where _time > ago(1h)
| where ['service.name'] == "brisket"
| where ['attributes.source'] == "browser"
| sort by _time desc
| limit 100

Insert any of these filters before sort and limit. Add one at a time; multiple where lines must all match.

Investigation APL filter
Errors only where severity_text =~ "error"
Message text where body contains "timeout"
Page where ['attributes.path'] == "/checkout"
Verified user where ['attributes.user_id'] == "user_REPLACE_ME"
Frontend build where ['attributes.browser_release'] == "REPLACE_WITH_RELEASE"
Ingestion server build where ['attributes.release'] == "REPLACE_WITH_RELEASE"
Environment where ['attributes.environment'] == "production"
Next.js digest where ['attributes.digest'] == "REPLACE_WITH_DIGEST"

Prefix each filter with |. == is exact equality, =~ is case-insensitive text equality, and contains searches inside text. Check severity values on an actual event before adding the error filter; browser diagnostics include info and warning reports too.

The capture API retains tags and extra; ingestion writes extra as context. There is no requirement for a field named sentry.

This example finds payment-tagged browser reports, including warnings and informational diagnostics:

['beef-prod']
| where _time > ago(1h)
| where ['service.name'] == "brisket"
| where ['attributes.source'] == "browser"
| extend tags = parse_json(tostring(['attributes.tags']))
| where tags.feature == "payment"
| sort by _time desc
| limit 100

extend adds a query-local field. The conversion handles tags represented as JSON text; if the live schema exposes individual tag fields, filter those directly. See Axiom JSON parsing.

Existing tag examples:

Tags are optional. A tag filter excludes untagged global errors, so remove it before concluding that a feature has no failures.

The names below are emitted by the ingestion route. Event metadata is exposed under attributes.*, for example attributes.context and attributes.breadcrumbs. The exporter may normalize exception details; inspect the event before assuming their final path.

Field Meaning
body Captured error or diagnostic message, exported as the OTel log body.
tags Short feature/component labels.
context Sanitized extra details supplied by the caller.
breadcrumbs Up to ten explicitly recorded recent actions, not a full session replay.
user_id Clerk-verified identity; anonymous reports can have no user ID.
path Browser page pathname, without query parameters or fragment.
browser_release Build loaded in the browser; can differ from the server after deployment.
release Ingestion server commit SHA, deployment ID fallback, or unknown.
client_timestamp Browser-reported capture time; distinguish it from the server log’s _time and allow for clock skew.
digest Optional Next.js error digest; not a universal issue ID.
exception Captured error name and stack when the thrown value supplies them.

For a render failure, keep service/time filters, remove source=browser, and search for the same digest to find server reports too. Compare releases and timestamps. Use a trace_id only when present and relevant: this transport does not establish distributed browser tracing or guarantee an end-to-end browser/server trace. Next request errors are handled in instrumentation.ts.

To rank repeated browser errors, replace the starting query’s sort/limit with:

| where severity_text =~ "error"
| summarize occurrences = count() by body
| sort by occurrences desc
| limit 20

This counts identical messages, not Sentry issues or affected users. Messages containing different IDs can form separate groups. To group a custom field, cast it, for example summarize count() by tostring(['attributes.path']).

  1. Confirm the environment, effective dataset, time window, and that the Sentry replacement is deployed. Remove user, release, tag, and severity filters; first look for any Brisket log, then browser reports.
  2. Inspect the live schema and field values. A wrong field path or absent tag is not evidence of zero client errors.
  3. Check stage and exporter configuration. Brisket enables reporting only in staging/production; logs export requires the OTLP URL and traces/logs headers. The endpoint’s 204 response alone does not prove Axiom receipt.
  4. Check delivery failures and reporting limits. Browser queues, per-minute budgets, server admission limits, ignored noise, offline clients, and exporter failures can drop reports. Oversized events can lose context, tags, and breadcrumbs. Account changes clear buffered context.
  5. Expect redaction and truncation. Email, token, payment, and other sensitive values may be replaced; URL queries are removed. Raw stacks can contain compiled frames; automatic browser source-map symbolication is not provided. Credential assignments such as password=... and api_key=... are redacted in message and stack text; authorization and cookie values are removed through the end of their line, including spaces and additional cookies.

Sources: runtime gates, client limits, redaction, and coverage limitations.

When reporting an investigation, include the dataset, exact time range and timezone, query, observed field layout, and matching event count or query link. State whether Axiom was actually queried. If access is unavailable, provide the query to run and label delivery unverified; do not report zero errors.