Spans model per-action operations (open/message/close); they're a poor fit for ad-hoc
events with no operation lifecycle. Split logError to dispatch by whether a span is
active:
- Active span (realtime.open / realtime.message / realtime.close catches) -> attach
the error to the existing span; the Sentry span exporter ships it with full operation
context (attributes, duration, trace_id).
- No active span (pub/sub subscriber, onStart, Swoole error handler, updateWorkerDocument)
-> push a utopia/logger Log via the realtimeLogger registry. Goes to Sentry as an event
via the Sentry logger adapter (or to logOwl / Raygun / AppSignal). Same dedicated
Realtime project either way.
Restores the realtimeLogger registry (dropped in the previous "spans only" pass), inlines
the now-single-caller $createLogger closure into the logger registry, and drops the
recordRealtimeErrorSpan helper — logError is the only function on this path now.
Also registers a Pretty span exporter in app/init/realtime/span.php for non-self-hosted
editions so Realtime spans are visible in the container's stdout (on self-hosted the
existing app/init/span.php already provides it; gating avoids duplicate output).
Collapse the multi-line doc blocks on recordRealtimeErrorSpan / pushRealtimeErrorLog /
$createLogger to one line each, drop the redundant require comment, and tighten the
"keep in sync" notes — keeping the cross-references and the double-report hazard.
Return early from the realtimeLogger registry when neither
_APP_LOGGING_CONFIG_REALTIME nor _APP_LOGGING_CONFIG is set, so the no-config
case (typical self-hosted) no longer constructs and throws from new DSN(''),
and tidy the $createLogger doc comment.
The realtimeLogger registry was a ~40-line copy of logger; extract the
DSN -> adapter -> Logger construction into one $createLogger closure used by
both. realtimeLogger now just resolves _APP_LOGGING_CONFIG_REALTIME (falling
back to _APP_LOGGING_CONFIG), skips Sentry — those errors go out as spans via
app/init/realtime/span.php — and delegates the rest. Cross-referenced the two
"sentry" conditions in both files. No behavior change (legacy ;-delimited
config no longer crashes the realtime registry; it disables logging like the
main one).
Move the Realtime Sentry span exporter registration out of app/realtime.php
into app/init/realtime/span.php (mirrors app/init/span.php / app/init/realtime/
connection.php), and split the now-80-line logError() into recordRealtimeErrorSpan()
(span path) and pushRealtimeErrorLog() (legacy utopia/logger path, non-Sentry
providers only), leaving logError() a small orchestrator. No behavior change.
Realtime errors are now recorded onto a span and shipped to a Sentry
project configured via _APP_LOGGING_CONFIG_REALTIME (falls back to
_APP_LOGGING_CONFIG). The Sentry span exporter is registered in
app/realtime.php so it does not affect the HTTP/worker/CLI span
exporters. logError() attaches the error to the active span, or opens a
short-lived realtime.error span for call sites without one (pub/sub
subscriber, onStart, the Swoole error handler), and keeps the legacy
utopia/logger push only for non-Sentry providers; the realtimeLogger
registry now returns null when the provider is Sentry to avoid
double-reporting. Documents _APP_LOGGING_CONFIG_REALTIME.
Replaces the stateful Appwrite\Event\Build queue class with a stateless
BuildPublisher and BuildMessage DTO, matching the publisher pattern used
by audits, certificates, executions, migrations, screenshots, stats, and
usage. Call sites now enqueue messages directly instead of mutating a
shared event object and relying on the API shutdown hook.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Remove query param fallback for impersonateEmail and impersonatePhone
to avoid PII exposure in server logs, browser history, and Referer
headers. Only impersonateUserId (an opaque internal ID) is safe to
pass via URL query param.
Allow impersonation to be specified via URL query params
(?impersonateUserId, ?impersonateEmail, ?impersonatePhone) as a
fallback to the existing headers, enabling Console to embed
impersonation in direct file/image URLs where headers cannot be set.