otel-expo-style

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

OTel Expo Style

Expo 环境下的 OTel 实践规范

Preserve existing runtime guards. If the app avoids native SDKs in Expo Go or an unsupported runtime branch, initialize OTel only inside the supported branch.
ts
const isExpoGo = process.env.EXPO_PUBLIC_RUNTIME === "expo-go";

if (!isExpoGo) {
  initObservability();
  Sentry.init({ dsn: process.env.EXPO_PUBLIC_SENTRY_DSN });
}

registerRootComponent(App);
In supported builds, call
initObservability()
before Sentry and before app registration/user code.
保留现有的运行时防护机制。如果应用在Expo Go或不支持的运行时分支中避免使用原生SDK,则仅在支持的分支内初始化OTel。
ts
const isExpoGo = process.env.EXPO_PUBLIC_RUNTIME === "expo-go";

if (!isExpoGo) {
  initObservability();
  Sentry.init({ dsn: process.env.EXPO_PUBLIC_SENTRY_DSN });
}

registerRootComponent(App);
在支持的构建版本中,需在初始化Sentry以及注册应用/执行用户代码之前调用
initObservability()

SDK Shape

SDK 结构规范

Use native OTel JS APIs and browser/mobile-compatible providers/exporters. Do not create
recordCounter
,
sendSuperlogSpan
, or tracking-specific helper files.
ts
export const tracer = trace.getTracer("mugline.mobile");
export const meter = metrics.getMeter("mugline.mobile");
export const ordersSubmitted = meter.createCounter("mug.orders.submitted");
Add automatic fetch/XHR instrumentation when compatible so API calls get spans without wrapping application code.
使用原生OTel JS API以及兼容浏览器/移动端的提供方/导出器。请勿创建
recordCounter
sendSuperlogSpan
或特定于追踪的辅助文件。
ts
export const tracer = trace.getTracer("mugline.mobile");
export const meter = metrics.getMeter("mugline.mobile");
export const ordersSubmitted = meter.createCounter("mug.orders.submitted");
在兼容情况下添加自动fetch/XHR工具,使API调用无需封装应用代码即可生成追踪跨度。

Product Actions

产品操作追踪

Wrap low-risk business operations with native active spans.
ts
await tracer.startActiveSpan("mug.order.submit", async (span) => {
  try {
    span.setAttribute("tenant.id", tenantId);
    ordersSubmitted.add(1, { "tenant.id": tenantId, outcome: "success" });
  } catch (error) {
    span.recordException(error as Error);
    span.setStatus({ code: SpanStatusCode.ERROR });
    throw error;
  } finally {
    span.end();
  }
});
使用原生活跃追踪跨度包裹低风险业务操作。
ts
await tracer.startActiveSpan("mug.order.submit", async (span) => {
  try {
    span.setAttribute("tenant.id", tenantId);
    ordersSubmitted.add(1, { "tenant.id": tenantId, outcome: "success" });
  } catch (error) {
    span.recordException(error as Error);
    span.setStatus({ code: SpanStatusCode.ERROR });
    throw error;
  } finally {
    span.end();
  }
});

Configuration

配置方式

Inline the endpoint and ingest key directly in the observability module. The key is project-scoped + write-only (Sentry-DSN shaped), so source-level configuration is the right default for Expo — and it sidesteps the build-time-vs-runtime quirks of
EXPO_PUBLIC_*
env vars in different build profiles.
ts
const SUPERLOG_ENDPOINT = "https://intake.superlog.sh";
const SUPERLOG_KEY = "superlog_live_…"; // set by superlog-onboard skill on pairing
const SERVICE_NAME = "mugline-mobile";

const exporter = new OTLPTraceExporter({
  url: `${SUPERLOG_ENDPOINT}/v1/traces`,
  headers: { authorization: `Bearer ${SUPERLOG_KEY}` },
});
将端点和接入密钥直接内联到可观测性模块中。该密钥是项目级别的只读密钥(格式类似Sentry-DSN),因此源码级别的配置是Expo环境下的合理默认方案——这也规避了不同构建配置中
EXPO_PUBLIC_*
环境变量在构建时与运行时的特性差异。
ts
const SUPERLOG_ENDPOINT = "https://intake.superlog.sh";
const SUPERLOG_KEY = "superlog_live_…"; // set by superlog-onboard skill on pairing
const SERVICE_NAME = "mugline-mobile";

const exporter = new OTLPTraceExporter({
  url: `${SUPERLOG_ENDPOINT}/v1/traces`,
  headers: { authorization: `Bearer ${SUPERLOG_KEY}` },
});