mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
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).
51 lines
2.0 KiB
PHP
51 lines
2.0 KiB
PHP
<?php
|
|
|
|
use Utopia\Console;
|
|
use Utopia\DSN\DSN;
|
|
use Utopia\Span\Exporter;
|
|
use Utopia\Span\Span;
|
|
use Utopia\System\System;
|
|
|
|
/**
|
|
* Export Realtime error spans to a dedicated Sentry project (`_APP_LOGGING_CONFIG_REALTIME`, falling
|
|
* back to `_APP_LOGGING_CONFIG`) — only here, not in app/init/span.php, so the HTTP/worker/CLI
|
|
* servers keep reporting to the default project. Only error-bearing spans are sampled.
|
|
*/
|
|
$loggingConfig = System::getEnv('_APP_LOGGING_CONFIG_REALTIME', '') ?: System::getEnv('_APP_LOGGING_CONFIG', '');
|
|
if (empty($loggingConfig)) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
$dsn = new DSN($loggingConfig);
|
|
|
|
if ($dsn->getScheme() === 'sentry') {
|
|
// utopia/logger DSN (`sentry://PROJECT_ID:KEY@HOST/`) -> standard Sentry DSN (`https://KEY@HOST/PROJECT_ID`).
|
|
$sentryDsn = 'https://' . ($dsn->getPassword() ?? '') . '@' . $dsn->getHost() . '/' . ($dsn->getUser() ?? '');
|
|
$isProduction = System::getEnv('_APP_ENV', 'development') === 'production';
|
|
|
|
Span::addExporter(
|
|
new Exporter\Sentry(
|
|
dsn: $sentryDsn,
|
|
environment: $isProduction ? 'production' : 'staging',
|
|
release: System::getEnv('_APP_VERSION', 'UNKNOWN'),
|
|
serverName: System::getEnv('_APP_LOGGING_SERVICE_IDENTIFIER', \gethostname()),
|
|
),
|
|
sampler: static fn (Span $span): bool => $span->getError() !== null,
|
|
);
|
|
}
|
|
} catch (Throwable $error) {
|
|
Console::warning('Failed to register Realtime Sentry span exporter: ' . $error->getMessage());
|
|
}
|
|
|
|
// Print spans to stdout for local visibility on editions where app/init/span.php — which already
|
|
// installs a Pretty exporter — isn't loaded (it's gated on `_APP_EDITION === 'self-hosted'`).
|
|
if (System::getEnv('_APP_EDITION', 'self-hosted') !== 'self-hosted') {
|
|
Span::addExporter(new Exporter\Pretty(), function (Span $span): bool {
|
|
if (\str_starts_with($span->getAction(), 'listener.')) {
|
|
return $span->getError() !== null;
|
|
}
|
|
return true;
|
|
});
|
|
}
|