docs: refresh architecture references for OTel migration

This commit is contained in:
2026-05-11 12:18:44 +02:00
parent 81f2477537
commit e43e03cdee
8 changed files with 86 additions and 66 deletions

View File

@@ -2378,12 +2378,13 @@ footer .colophon {
</div>
<h3 class="trace-h3">The trace tree (one tRPC request)</h3>
<pre class="trace-tree"><code>HTTP transaction (auto, @sentry/nextjs)
└── tRPC procedure span (auto, sentry trpc integration)
└── controller span (op="controller", composed at DI bind time)
└── use-case span (op="use-case", composed at DI bind time)
└── repository span (op="repository", inline per method)
└── Payload Local API call (auto, @sentry/node http)</code></pre>
<p class="trace-p"><strong>Substrate: OpenTelemetry SDK</strong> (ADR-017). Sentry is the exporter via <code>@sentry/opentelemetry</code>. Auto-instrumentations cover HTTP, undici, and pg; feature code emits via <code>ITracer</code> / <code>ILogger</code> interfaces only.</p>
<pre class="trace-tree"><code>HTTP transaction (auto, OTel HttpInstrumentation)
└── tRPC procedure span (auto, OTel + Sentry tRPC integration)
└── controller span (op="controller", composed at DI bind time via OtelTracer)
└── use-case span (op="use-case", composed at DI bind time via OtelTracer)
└── repository span (op="repository", inline per method via ITracer)
└── Payload Local API call (auto, OTel PgInstrumentation / UndiciInstrumentation)</code></pre>
<h3 class="trace-h3">Where instrumentation actually lives</h3>
<p class="trace-p">Two ways spans + captures get attached. <strong>Inline</strong> means the call appears in the layer's own body. <strong>Composed-in</strong> means a higher-order wrapper applied at DI bind time — the body stays vendor-clean.</p>
@@ -2502,16 +2503,16 @@ const wrappedCtrl = withSpan(
</table>
<h3 class="trace-h3">Double-report guard</h3>
<p class="trace-p">Each error gets a non-enumerable <code>__sentryReported</code> flag the first time it's captured. <code>withCapture</code>, <code>SentryLogger</code>, and <code>RecordingLogger</code> all check the flag and bail if it's set. So an error bubbling repo → use-case → controller surfaces in the logger <strong>exactly once</strong>, with the inner-most layer's tags. Helper lives in <code>core-shared/instrumentation/reported-flag.ts</code>.</p>
<p class="trace-p">Each error gets a non-enumerable <code>__sentryReported</code> flag the first time it's captured. <code>withCapture</code>, <code>OtelLogger</code>, and <code>RecordingLogger</code> all check the flag and bail if it's set. So an error bubbling repo → use-case → controller surfaces in the logger <strong>exactly once</strong>, with the inner-most layer's tags. Helper lives in <code>core-shared/instrumentation/reported-flag.ts</code>.</p>
<h3 class="trace-h3">PII rules (R31R38, non-negotiable)</h3>
<ul class="pii-rules">
<li><code>sendDefaultPii: false</code> — every <code>Sentry.init()</code>. CI grep gate.</li>
<li>Replay <strong>default-masks all text + inputs + media</strong>. Allowlist starts empty.</li>
<li><code>beforeSend</code> scrubber strips email / password / token / cookie / authorization / ipaddress keys (substring match).</li>
<li><code>beforeSendTransaction</code> scrubber strips PII query params from URLs.</li>
<li><code>setUser</code> accepts only <code>{ id }</code>. Stripping wrapper warns in dev when other keys passed.</li>
<li>IPv4/IPv6 in event payload string values redacted to <code>[redacted-ip]</code>.</li>
<li><strong>Server-side:</strong> <code>PiiScrubSpanProcessor</code> + <code>PiiScrubLogRecordProcessor</code> run FIRST in the OTel processor chain — attribute-key substring match strips email / password / token / cookie / authorization / ipaddress keys before the Sentry exporter sees the data (R32, R33, ADR-017 §7).</li>
<li><strong>Browser-side:</strong> <code>beforeSend</code> / <code>beforeSendTransaction</code> hooks in <code>init-client*.ts</code> strip the same PII keys (browser does not use the OTel pipeline).</li>
<li><code>setUser</code> accepts only <code>{ id }</code>. No email/username (R36).</li>
<li>IPv4/IPv6 redacted to <code>[redacted-ip]</code> in browser-side scrubbers.</li>
</ul>
</section>