Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

Unsampled pageload span is profiled when profileLifecycle is 'trace' (browser UI profiling)

Đang mở Phù hợp với người mới
#25,497 1 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

@Jxxunnn đang làm issue này rồi.

Từ ngày 19/10/2026.

  • #25498 của @Jxxunnn — đang mở

Đánh giá

Độ khó
2/5
Thời gian dự kiến
1-3 giờ
Mức phù hợp với người mới
82/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
javascript, typescript
Lĩnh vực
frontend, performance

Hướng nghiên cứu

Bắt đầu với packages/browser/src/profiling/UIProfiler.ts và so sánh notifyRootSpanActive() với listener spanStart trong _setupTraceLifecycleListeners(). Kiểm tra các bài kiểm thử profiling hiện có để xem chúng đã bao phủ trường hợp span gốc đang hoạt động và không được lấy mẫu tại thời điểm thiết lập hay chưa. Công việc hoàn tất khi trường hợp đó không khởi động profiler hoặc gửi một phần dữ liệu profile, trong khi các span gốc được lấy mẫu vẫn khởi động profiling.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

Browser Waiting for: Product Owner
Is there an existing issue for this?
How do you use Sentry?

Sentry Saas (sentry.io)

Which SDK are you using?

@sentry/browser

SDK Version

@sentry/browser 11.8.0 (also reproduced on 11.4.0; UIProfiler.ts on develop is unchanged as of 2026-10-19)

Framework Version

No response

Link to Sentry event

No response

Reproduction Example/SDK Setup
import * as Sentry from '@sentry/browser';

Sentry.init({
  dsn: '<dsn>',
  integrations: [Sentry.browserTracingIntegration(), Sentry.browserProfilingIntegration()],
  tracesSampleRate: 0, // pageload span NOT sampled -> expect NO profiling
  profileSessionSampleRate: 1,
  profileLifecycle: 'trace',
});

The page is served with Document-Policy: js-profiling.

Steps to Reproduce
  1. Initialize the SDK with profileLifecycle: 'trace', profileSessionSampleRate: 1 and tracesSampleRate: 0 (see SDK setup above).
  2. Load the page. The pageload span is not sampled (isRecording() === false, traceFlags === 0).
  3. Observe that new Profiler(...) is called once and a profile_chunk envelope is sent when the pageload span ends.
Expected Result

The pageload span is not sampled, so trace lifecycle profiling should not start. This is how root spans started after setup are already handled.

Actual Result

The profiler starts for the unsampled pageload span and a profile_chunk is sent.

I checked this in Chromium with a window.Profiler stub that counts constructor calls and an in-memory transport:

  • tracesSampleRate: 0, profileSessionSampleRate: 1: profiler started once, profile_chunk sent
  • tracesSampleRate: 0, profileSessionSampleRate: 0: profiler not started (control)
  • tracesSampleRate: 1, profileSessionSampleRate: 1: profiler started once, profile_chunk and the pageload span sent (expected)
  • tracesSampleRate: 0, profileSessionSampleRate: 1, pageload instrumentation off, an unsampled root span started after init: profiler not started

The last case shows that only the root span that is already active at setup skips the sampling check.

Additional Context
Root cause (source walkthrough)

In packages/browser/src/profiling/integration.ts (develop):

  • After profiler.initialize(client), setup calls profiler.notifyRootSpanActive(rootSpan) for the active root span. The comment says "If there is an active, sampled root span already, notify the profiler".
  • Setup calls it again in a setTimeout(0). This is the path that picks up the pageload span that browserTracingIntegration starts in afterAllSetup.

In packages/browser/src/profiling/UIProfiler.ts:

  • The spanStart listener registered by _setupTraceLifecycleListeners() returns early when !span.isRecording() ("Only count sampled root spans").
  • notifyRootSpanActive() only checks the lifecycle mode and _sessionSampled. It then registers the span and calls _beginProfiling() without checking rootSpan.isRecording().

So an unsampled root span that is already active at setup starts the profiler. The unsampled span still emits spanEnd, so the profile runs for the length of the pageload.

#17619, which added the trace lifecycle, describes it as "Starts when the first sampled root span starts".

Impact

With profileSessionSampleRate: 1, unsampled pageload spans can still start UI profiling in supported browsers. Reducing tracesSampleRate, even to 0, does not prevent this startup path. This can add unintended profiling overhead and profile usage, without a sampled pageload span to correlate with the resulting chunks.

Related

#22927 was the same kind of gap in the Node trace lifecycle, there for the session sampling decision.

Suggested fix

Return early in notifyRootSpanActive() when !rootSpan.isRecording(), matching the spanStart listener. Happy to open a PR.

Ngôn ngữ chính
TypeScript
Star
8.8k
Fork
1.9k
Merge trung bình
1 ngày 11 giờ
Pull request đã merge (30 ngày)
578

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của getsentry/sentry-javascript

Tất cả issue của getsentry/sentry-javascript

Issue tương tự

Thêm issue về TypeScript

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.