fix(core): Ensure metrics past MAX_METRIC_BUFFER_SIZE are not swallowed - #18212

Merged
andreiborza merged 3 commits into
developfrom
ab/fix-metrics-swallowing
Nov 17, 2025
Merged

fix(core): Ensure metrics past MAX_METRIC_BUFFER_SIZE are not swallowed#18212
andreiborza merged 3 commits into
developfrom
ab/fix-metrics-swallowing

Conversation

@andreiborza

@andreiborzaandreiborza commented Nov 14, 2025

Copy link
Copy Markdown
Member

Looks like we swallowed the metric that triggers a flush when MAX_METRIC_BUFFER_SIZE is surpassed.

Test demonstrating issue: f0737fa
Fix: 1a4e02a

Related logs pr: #18207

Comment on lines +259 to +262
// After flushing the 1000 metrics, the new metric starts a fresh buffer with 1 item
const buffer = _INTERNAL_getMetricBuffer(client);
expect(buffer).toHaveLength(1);
expect(buffer?.[0]?.name).toBe('trigger.flush');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: A metric that triggers a buffer flush is lost because the flush operation clears the buffer after the new metric has been added but before it's processed.
Severity: CRITICAL | Confidence: 1.00

🔍 Detailed Analysis

The _INTERNAL_captureSerializedMetric function incorrectly handles metrics when the buffer reaches MAX_METRIC_BUFFER_SIZE. When a new metric arrives, it's added to the buffer via bufferMap.set(client, [...metricBuffer, serializedMetric]). However, the subsequent flush condition check if (metricBuffer.length >= MAX_METRIC_BUFFER_SIZE) and the flush operation _INTERNAL_flushMetricsBuffer(client, metricBuffer) use the oldmetricBuffer reference (before the new metric was added). This leads to the newly added metric being present in the map when _INTERNAL_flushMetricsBuffer is called, but then being lost when _getBufferMap().set(client, []) clears the entire buffer, including the new metric. This results in data loss for metrics that trigger a buffer flush.

💡 Suggested Fix

Modify _INTERNAL_captureSerializedMetric to ensure that the _INTERNAL_flushMetricsBuffer function is called with the updated buffer, or that the new metric is handled correctly after the old buffer is flushed and cleared, perhaps by re-adding it to a newly cleared buffer.

🤖 Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: packages/core/test/lib/metrics/internal.test.ts#L259-L262
Potential issue: The `_INTERNAL_captureSerializedMetric` function incorrectly handles
metrics when the buffer reaches `MAX_METRIC_BUFFER_SIZE`. When a new metric arrives,
it's added to the buffer via `bufferMap.set(client, [...metricBuffer,
serializedMetric])`. However, the subsequent flush condition check `if
(metricBuffer.length >= MAX_METRIC_BUFFER_SIZE)` and the flush operation
`_INTERNAL_flushMetricsBuffer(client, metricBuffer)` use the *old* `metricBuffer`
reference (before the new metric was added). This leads to the newly added metric being
present in the map when `_INTERNAL_flushMetricsBuffer` is called, but then being lost
when `_getBufferMap().set(client, [])` clears the entire buffer, including the new
metric. This results in data loss for metrics that trigger a buffer flush.

Did we get this right? 👍 / 👎 to inform future reviews.

Reference_id: 2692398

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what we are fixing with 1a4e02a

@github-actions

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser24.6 kB--
@sentry/browser - with treeshaking flags23.09 kB--
@sentry/browser (incl. Tracing)41.26 kB--
@sentry/browser (incl. Tracing, Profiling)45.53 kB--
@sentry/browser (incl. Tracing, Replay)79.73 kB--
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags69.4 kB--
@sentry/browser (incl. Tracing, Replay with Canvas)84.42 kB--
@sentry/browser (incl. Tracing, Replay, Feedback)96.58 kB--
@sentry/browser (incl. Feedback)41.27 kB--
@sentry/browser (incl. sendFeedback)29.27 kB--
@sentry/browser (incl. FeedbackAsync)34.2 kB--
@sentry/react26.29 kB--
@sentry/react (incl. Tracing)43.22 kB--
@sentry/vue29.09 kB--
@sentry/vue (incl. Tracing)43.03 kB--
@sentry/svelte24.61 kB--
CDN Bundle26.91 kB+0.02%+3 B 🔺
CDN Bundle (incl. Tracing)41.81 kB+0.01%+4 B 🔺
CDN Bundle (incl. Tracing, Replay)78.33 kB+0.01%+2 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback)83.81 kB+0.01%+3 B 🔺
CDN Bundle - uncompressed78.85 kB+0.02%+12 B 🔺
CDN Bundle (incl. Tracing) - uncompressed124.01 kB+0.01%+12 B 🔺
CDN Bundle (incl. Tracing, Replay) - uncompressed240.04 kB+0.01%+12 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed252.8 kB+0.01%+12 B 🔺
@sentry/nextjs (client)45.34 kB--
@sentry/sveltekit (client)41.64 kB--
@sentry/node-core50.86 kB--
@sentry/node158.08 kB--
@sentry/node - without tracing92.73 kB--
@sentry/aws-serverless106.5 kB--

View base workflow run

@github-actions

Copy link
Copy Markdown
Contributor

node-overhead report 🧳

Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.

ScenarioRequests/s% of BaselinePrev. Requests/sChange %
GET Baseline8,701-11,316-23%
GET With Sentry1,35716%1,654-18%
GET With Sentry (error only)6,25372%7,684-19%
POST Baseline1,213-1,188+2%
POST With Sentry51743%573-10%
POST With Sentry (error only)1,07989%1,040+4%
MYSQL Baseline3,369-4,059-17%
MYSQL With Sentry46614%562-17%
MYSQL With Sentry (error only)2,76282%3,308-17%

View base workflow run

andreiborza added a commit that referenced this pull request Nov 17, 2025
…18207)
Looks like we swallowed the log that triggers a flush when
`MAX_LOG_BUFFER_SIZE` is surpassed.
Test demonstrating issue:
[5697b7d](5697b7d)
Fix:
[f7a4d8b](f7a4d8b)
Related metrics pr: #18212
v9 backport: #18213
@andreiborza
andreiborza merged commit e3ef3f2 into developNov 17, 2025
380 of 383 checks passed
@andreiborza
andreiborza deleted the ab/fix-metrics-swallowing branch November 17, 2025 08:50
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@andreiborza@chargome@s1gr1d
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all \u003cpre\u003e\u003ccode\u003e blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks"); } } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); } })(); (function(){ try { var __m = "github.com"; var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(core): Ensure metrics past MAX_METRIC_BUFFER_SIZE are not swallowed - #18212

Merged
andreiborza merged 3 commits into
developfrom
ab/fix-metrics-swallowing
Nov 17, 2025
Merged

fix(core): Ensure metrics past MAX_METRIC_BUFFER_SIZE are not swallowed#18212
andreiborza merged 3 commits into
developfrom
ab/fix-metrics-swallowing

Conversation

@andreiborza

@andreiborzaandreiborza commented Nov 14, 2025

Copy link
Copy Markdown
Member

Looks like we swallowed the metric that triggers a flush when MAX_METRIC_BUFFER_SIZE is surpassed.

Test demonstrating issue: f0737fa
Fix: 1a4e02a

Related logs pr: #18207

Comment on lines +259 to +262
// After flushing the 1000 metrics, the new metric starts a fresh buffer with 1 item
const buffer = _INTERNAL_getMetricBuffer(client);
expect(buffer).toHaveLength(1);
expect(buffer?.[0]?.name).toBe('trigger.flush');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: A metric that triggers a buffer flush is lost because the flush operation clears the buffer after the new metric has been added but before it's processed.
Severity: CRITICAL | Confidence: 1.00

🔍 Detailed Analysis

The _INTERNAL_captureSerializedMetric function incorrectly handles metrics when the buffer reaches MAX_METRIC_BUFFER_SIZE. When a new metric arrives, it's added to the buffer via bufferMap.set(client, [...metricBuffer, serializedMetric]). However, the subsequent flush condition check if (metricBuffer.length >= MAX_METRIC_BUFFER_SIZE) and the flush operation _INTERNAL_flushMetricsBuffer(client, metricBuffer) use the oldmetricBuffer reference (before the new metric was added). This leads to the newly added metric being present in the map when _INTERNAL_flushMetricsBuffer is called, but then being lost when _getBufferMap().set(client, []) clears the entire buffer, including the new metric. This results in data loss for metrics that trigger a buffer flush.

💡 Suggested Fix

Modify _INTERNAL_captureSerializedMetric to ensure that the _INTERNAL_flushMetricsBuffer function is called with the updated buffer, or that the new metric is handled correctly after the old buffer is flushed and cleared, perhaps by re-adding it to a newly cleared buffer.

🤖 Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: packages/core/test/lib/metrics/internal.test.ts#L259-L262
Potential issue: The `_INTERNAL_captureSerializedMetric` function incorrectly handles
metrics when the buffer reaches `MAX_METRIC_BUFFER_SIZE`. When a new metric arrives,
it's added to the buffer via `bufferMap.set(client, [...metricBuffer,
serializedMetric])`. However, the subsequent flush condition check `if
(metricBuffer.length >= MAX_METRIC_BUFFER_SIZE)` and the flush operation
`_INTERNAL_flushMetricsBuffer(client, metricBuffer)` use the *old* `metricBuffer`
reference (before the new metric was added). This leads to the newly added metric being
present in the map when `_INTERNAL_flushMetricsBuffer` is called, but then being lost
when `_getBufferMap().set(client, [])` clears the entire buffer, including the new
metric. This results in data loss for metrics that trigger a buffer flush.

Did we get this right? 👍 / 👎 to inform future reviews.

Reference_id: 2692398

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what we are fixing with 1a4e02a

@github-actions

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser24.6 kB--
@sentry/browser - with treeshaking flags23.09 kB--
@sentry/browser (incl. Tracing)41.26 kB--
@sentry/browser (incl. Tracing, Profiling)45.53 kB--
@sentry/browser (incl. Tracing, Replay)79.73 kB--
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags69.4 kB--
@sentry/browser (incl. Tracing, Replay with Canvas)84.42 kB--
@sentry/browser (incl. Tracing, Replay, Feedback)96.58 kB--
@sentry/browser (incl. Feedback)41.27 kB--
@sentry/browser (incl. sendFeedback)29.27 kB--
@sentry/browser (incl. FeedbackAsync)34.2 kB--
@sentry/react26.29 kB--
@sentry/react (incl. Tracing)43.22 kB--
@sentry/vue29.09 kB--
@sentry/vue (incl. Tracing)43.03 kB--
@sentry/svelte24.61 kB--
CDN Bundle26.91 kB+0.02%+3 B 🔺
CDN Bundle (incl. Tracing)41.81 kB+0.01%+4 B 🔺
CDN Bundle (incl. Tracing, Replay)78.33 kB+0.01%+2 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback)83.81 kB+0.01%+3 B 🔺
CDN Bundle - uncompressed78.85 kB+0.02%+12 B 🔺
CDN Bundle (incl. Tracing) - uncompressed124.01 kB+0.01%+12 B 🔺
CDN Bundle (incl. Tracing, Replay) - uncompressed240.04 kB+0.01%+12 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed252.8 kB+0.01%+12 B 🔺
@sentry/nextjs (client)45.34 kB--
@sentry/sveltekit (client)41.64 kB--
@sentry/node-core50.86 kB--
@sentry/node158.08 kB--
@sentry/node - without tracing92.73 kB--
@sentry/aws-serverless106.5 kB--

View base workflow run

@github-actions

Copy link
Copy Markdown
Contributor

node-overhead report 🧳

Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.

ScenarioRequests/s% of BaselinePrev. Requests/sChange %
GET Baseline8,701-11,316-23%
GET With Sentry1,35716%1,654-18%
GET With Sentry (error only)6,25372%7,684-19%
POST Baseline1,213-1,188+2%
POST With Sentry51743%573-10%
POST With Sentry (error only)1,07989%1,040+4%
MYSQL Baseline3,369-4,059-17%
MYSQL With Sentry46614%562-17%
MYSQL With Sentry (error only)2,76282%3,308-17%

View base workflow run

andreiborza added a commit that referenced this pull request Nov 17, 2025
…18207)
Looks like we swallowed the log that triggers a flush when
`MAX_LOG_BUFFER_SIZE` is surpassed.
Test demonstrating issue:
[5697b7d](5697b7d)
Fix:
[f7a4d8b](f7a4d8b)
Related metrics pr: #18212
v9 backport: #18213
@andreiborza
andreiborza merged commit e3ef3f2 into developNov 17, 2025
380 of 383 checks passed
@andreiborza
andreiborza deleted the ab/fix-metrics-swallowing branch November 17, 2025 08:50
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@andreiborza@chargome@s1gr1d
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(core): Ensure metrics past MAX_METRIC_BUFFER_SIZE are not swallowed - #18212

Merged
andreiborza merged 3 commits into
developfrom
ab/fix-metrics-swallowing
Nov 17, 2025
Merged

fix(core): Ensure metrics past MAX_METRIC_BUFFER_SIZE are not swallowed#18212
andreiborza merged 3 commits into
developfrom
ab/fix-metrics-swallowing

Conversation

@andreiborza

@andreiborzaandreiborza commented Nov 14, 2025

Copy link
Copy Markdown
Member

Looks like we swallowed the metric that triggers a flush when MAX_METRIC_BUFFER_SIZE is surpassed.

Test demonstrating issue: f0737fa
Fix: 1a4e02a

Related logs pr: #18207

Comment on lines +259 to +262
// After flushing the 1000 metrics, the new metric starts a fresh buffer with 1 item
const buffer = _INTERNAL_getMetricBuffer(client);
expect(buffer).toHaveLength(1);
expect(buffer?.[0]?.name).toBe('trigger.flush');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: A metric that triggers a buffer flush is lost because the flush operation clears the buffer after the new metric has been added but before it's processed.
Severity: CRITICAL | Confidence: 1.00

🔍 Detailed Analysis

The _INTERNAL_captureSerializedMetric function incorrectly handles metrics when the buffer reaches MAX_METRIC_BUFFER_SIZE. When a new metric arrives, it's added to the buffer via bufferMap.set(client, [...metricBuffer, serializedMetric]). However, the subsequent flush condition check if (metricBuffer.length >= MAX_METRIC_BUFFER_SIZE) and the flush operation _INTERNAL_flushMetricsBuffer(client, metricBuffer) use the oldmetricBuffer reference (before the new metric was added). This leads to the newly added metric being present in the map when _INTERNAL_flushMetricsBuffer is called, but then being lost when _getBufferMap().set(client, []) clears the entire buffer, including the new metric. This results in data loss for metrics that trigger a buffer flush.

💡 Suggested Fix

Modify _INTERNAL_captureSerializedMetric to ensure that the _INTERNAL_flushMetricsBuffer function is called with the updated buffer, or that the new metric is handled correctly after the old buffer is flushed and cleared, perhaps by re-adding it to a newly cleared buffer.

🤖 Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: packages/core/test/lib/metrics/internal.test.ts#L259-L262
Potential issue: The `_INTERNAL_captureSerializedMetric` function incorrectly handles
metrics when the buffer reaches `MAX_METRIC_BUFFER_SIZE`. When a new metric arrives,
it's added to the buffer via `bufferMap.set(client, [...metricBuffer,
serializedMetric])`. However, the subsequent flush condition check `if
(metricBuffer.length >= MAX_METRIC_BUFFER_SIZE)` and the flush operation
`_INTERNAL_flushMetricsBuffer(client, metricBuffer)` use the *old* `metricBuffer`
reference (before the new metric was added). This leads to the newly added metric being
present in the map when `_INTERNAL_flushMetricsBuffer` is called, but then being lost
when `_getBufferMap().set(client, [])` clears the entire buffer, including the new
metric. This results in data loss for metrics that trigger a buffer flush.

Did we get this right? 👍 / 👎 to inform future reviews.

Reference_id: 2692398

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what we are fixing with 1a4e02a

@github-actions

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser24.6 kB--
@sentry/browser - with treeshaking flags23.09 kB--
@sentry/browser (incl. Tracing)41.26 kB--
@sentry/browser (incl. Tracing, Profiling)45.53 kB--
@sentry/browser (incl. Tracing, Replay)79.73 kB--
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags69.4 kB--
@sentry/browser (incl. Tracing, Replay with Canvas)84.42 kB--
@sentry/browser (incl. Tracing, Replay, Feedback)96.58 kB--
@sentry/browser (incl. Feedback)41.27 kB--
@sentry/browser (incl. sendFeedback)29.27 kB--
@sentry/browser (incl. FeedbackAsync)34.2 kB--
@sentry/react26.29 kB--
@sentry/react (incl. Tracing)43.22 kB--
@sentry/vue29.09 kB--
@sentry/vue (incl. Tracing)43.03 kB--
@sentry/svelte24.61 kB--
CDN Bundle26.91 kB+0.02%+3 B 🔺
CDN Bundle (incl. Tracing)41.81 kB+0.01%+4 B 🔺
CDN Bundle (incl. Tracing, Replay)78.33 kB+0.01%+2 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback)83.81 kB+0.01%+3 B 🔺
CDN Bundle - uncompressed78.85 kB+0.02%+12 B 🔺
CDN Bundle (incl. Tracing) - uncompressed124.01 kB+0.01%+12 B 🔺
CDN Bundle (incl. Tracing, Replay) - uncompressed240.04 kB+0.01%+12 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed252.8 kB+0.01%+12 B 🔺
@sentry/nextjs (client)45.34 kB--
@sentry/sveltekit (client)41.64 kB--
@sentry/node-core50.86 kB--
@sentry/node158.08 kB--
@sentry/node - without tracing92.73 kB--
@sentry/aws-serverless106.5 kB--

View base workflow run

@github-actions

Copy link
Copy Markdown
Contributor

node-overhead report 🧳

Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.

ScenarioRequests/s% of BaselinePrev. Requests/sChange %
GET Baseline8,701-11,316-23%
GET With Sentry1,35716%1,654-18%
GET With Sentry (error only)6,25372%7,684-19%
POST Baseline1,213-1,188+2%
POST With Sentry51743%573-10%
POST With Sentry (error only)1,07989%1,040+4%
MYSQL Baseline3,369-4,059-17%
MYSQL With Sentry46614%562-17%
MYSQL With Sentry (error only)2,76282%3,308-17%

View base workflow run

andreiborza added a commit that referenced this pull request Nov 17, 2025
…18207)
Looks like we swallowed the log that triggers a flush when
`MAX_LOG_BUFFER_SIZE` is surpassed.
Test demonstrating issue:
[5697b7d](5697b7d)
Fix:
[f7a4d8b](f7a4d8b)
Related metrics pr: #18212
v9 backport: #18213
@andreiborza
andreiborza merged commit e3ef3f2 into developNov 17, 2025
380 of 383 checks passed
@andreiborza
andreiborza deleted the ab/fix-metrics-swallowing branch November 17, 2025 08:50
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@andreiborza@chargome@s1gr1d
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length \u003e 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(core): Ensure metrics past MAX_METRIC_BUFFER_SIZE are not swallowed - #18212

Merged
andreiborza merged 3 commits into
developfrom
ab/fix-metrics-swallowing
Nov 17, 2025
Merged

fix(core): Ensure metrics past MAX_METRIC_BUFFER_SIZE are not swallowed#18212
andreiborza merged 3 commits into
developfrom
ab/fix-metrics-swallowing

Conversation

@andreiborza

@andreiborzaandreiborza commented Nov 14, 2025

Copy link
Copy Markdown
Member

Looks like we swallowed the metric that triggers a flush when MAX_METRIC_BUFFER_SIZE is surpassed.

Test demonstrating issue: f0737fa
Fix: 1a4e02a

Related logs pr: #18207

Comment on lines +259 to +262
// After flushing the 1000 metrics, the new metric starts a fresh buffer with 1 item
const buffer = _INTERNAL_getMetricBuffer(client);
expect(buffer).toHaveLength(1);
expect(buffer?.[0]?.name).toBe('trigger.flush');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: A metric that triggers a buffer flush is lost because the flush operation clears the buffer after the new metric has been added but before it's processed.
Severity: CRITICAL | Confidence: 1.00

🔍 Detailed Analysis

The _INTERNAL_captureSerializedMetric function incorrectly handles metrics when the buffer reaches MAX_METRIC_BUFFER_SIZE. When a new metric arrives, it's added to the buffer via bufferMap.set(client, [...metricBuffer, serializedMetric]). However, the subsequent flush condition check if (metricBuffer.length >= MAX_METRIC_BUFFER_SIZE) and the flush operation _INTERNAL_flushMetricsBuffer(client, metricBuffer) use the oldmetricBuffer reference (before the new metric was added). This leads to the newly added metric being present in the map when _INTERNAL_flushMetricsBuffer is called, but then being lost when _getBufferMap().set(client, []) clears the entire buffer, including the new metric. This results in data loss for metrics that trigger a buffer flush.

💡 Suggested Fix

Modify _INTERNAL_captureSerializedMetric to ensure that the _INTERNAL_flushMetricsBuffer function is called with the updated buffer, or that the new metric is handled correctly after the old buffer is flushed and cleared, perhaps by re-adding it to a newly cleared buffer.

🤖 Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: packages/core/test/lib/metrics/internal.test.ts#L259-L262
Potential issue: The `_INTERNAL_captureSerializedMetric` function incorrectly handles
metrics when the buffer reaches `MAX_METRIC_BUFFER_SIZE`. When a new metric arrives,
it's added to the buffer via `bufferMap.set(client, [...metricBuffer,
serializedMetric])`. However, the subsequent flush condition check `if
(metricBuffer.length >= MAX_METRIC_BUFFER_SIZE)` and the flush operation
`_INTERNAL_flushMetricsBuffer(client, metricBuffer)` use the *old* `metricBuffer`
reference (before the new metric was added). This leads to the newly added metric being
present in the map when `_INTERNAL_flushMetricsBuffer` is called, but then being lost
when `_getBufferMap().set(client, [])` clears the entire buffer, including the new
metric. This results in data loss for metrics that trigger a buffer flush.

Did we get this right? 👍 / 👎 to inform future reviews.

Reference_id: 2692398

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what we are fixing with 1a4e02a

@github-actions

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser24.6 kB--
@sentry/browser - with treeshaking flags23.09 kB--
@sentry/browser (incl. Tracing)41.26 kB--
@sentry/browser (incl. Tracing, Profiling)45.53 kB--
@sentry/browser (incl. Tracing, Replay)79.73 kB--
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags69.4 kB--
@sentry/browser (incl. Tracing, Replay with Canvas)84.42 kB--
@sentry/browser (incl. Tracing, Replay, Feedback)96.58 kB--
@sentry/browser (incl. Feedback)41.27 kB--
@sentry/browser (incl. sendFeedback)29.27 kB--
@sentry/browser (incl. FeedbackAsync)34.2 kB--
@sentry/react26.29 kB--
@sentry/react (incl. Tracing)43.22 kB--
@sentry/vue29.09 kB--
@sentry/vue (incl. Tracing)43.03 kB--
@sentry/svelte24.61 kB--
CDN Bundle26.91 kB+0.02%+3 B 🔺
CDN Bundle (incl. Tracing)41.81 kB+0.01%+4 B 🔺
CDN Bundle (incl. Tracing, Replay)78.33 kB+0.01%+2 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback)83.81 kB+0.01%+3 B 🔺
CDN Bundle - uncompressed78.85 kB+0.02%+12 B 🔺
CDN Bundle (incl. Tracing) - uncompressed124.01 kB+0.01%+12 B 🔺
CDN Bundle (incl. Tracing, Replay) - uncompressed240.04 kB+0.01%+12 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed252.8 kB+0.01%+12 B 🔺
@sentry/nextjs (client)45.34 kB--
@sentry/sveltekit (client)41.64 kB--
@sentry/node-core50.86 kB--
@sentry/node158.08 kB--
@sentry/node - without tracing92.73 kB--
@sentry/aws-serverless106.5 kB--

View base workflow run

@github-actions

Copy link
Copy Markdown
Contributor

node-overhead report 🧳

Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.

ScenarioRequests/s% of BaselinePrev. Requests/sChange %
GET Baseline8,701-11,316-23%
GET With Sentry1,35716%1,654-18%
GET With Sentry (error only)6,25372%7,684-19%
POST Baseline1,213-1,188+2%
POST With Sentry51743%573-10%
POST With Sentry (error only)1,07989%1,040+4%
MYSQL Baseline3,369-4,059-17%
MYSQL With Sentry46614%562-17%
MYSQL With Sentry (error only)2,76282%3,308-17%

View base workflow run

andreiborza added a commit that referenced this pull request Nov 17, 2025
…18207)
Looks like we swallowed the log that triggers a flush when
`MAX_LOG_BUFFER_SIZE` is surpassed.
Test demonstrating issue:
[5697b7d](5697b7d)
Fix:
[f7a4d8b](f7a4d8b)
Related metrics pr: #18212
v9 backport: #18213
@andreiborza
andreiborza merged commit e3ef3f2 into developNov 17, 2025
380 of 383 checks passed
@andreiborza
andreiborza deleted the ab/fix-metrics-swallowing branch November 17, 2025 08:50
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@andreiborza@chargome@s1gr1d
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(core): Ensure metrics past MAX_METRIC_BUFFER_SIZE are not swallowed - #18212

Merged
andreiborza merged 3 commits into
developfrom
ab/fix-metrics-swallowing
Nov 17, 2025
Merged

fix(core): Ensure metrics past MAX_METRIC_BUFFER_SIZE are not swallowed#18212
andreiborza merged 3 commits into
developfrom
ab/fix-metrics-swallowing

Conversation

@andreiborza

@andreiborzaandreiborza commented Nov 14, 2025

Copy link
Copy Markdown
Member

Looks like we swallowed the metric that triggers a flush when MAX_METRIC_BUFFER_SIZE is surpassed.

Test demonstrating issue: f0737fa
Fix: 1a4e02a

Related logs pr: #18207

Comment on lines +259 to +262
// After flushing the 1000 metrics, the new metric starts a fresh buffer with 1 item
const buffer = _INTERNAL_getMetricBuffer(client);
expect(buffer).toHaveLength(1);
expect(buffer?.[0]?.name).toBe('trigger.flush');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: A metric that triggers a buffer flush is lost because the flush operation clears the buffer after the new metric has been added but before it's processed.
Severity: CRITICAL | Confidence: 1.00

🔍 Detailed Analysis

The _INTERNAL_captureSerializedMetric function incorrectly handles metrics when the buffer reaches MAX_METRIC_BUFFER_SIZE. When a new metric arrives, it's added to the buffer via bufferMap.set(client, [...metricBuffer, serializedMetric]). However, the subsequent flush condition check if (metricBuffer.length >= MAX_METRIC_BUFFER_SIZE) and the flush operation _INTERNAL_flushMetricsBuffer(client, metricBuffer) use the oldmetricBuffer reference (before the new metric was added). This leads to the newly added metric being present in the map when _INTERNAL_flushMetricsBuffer is called, but then being lost when _getBufferMap().set(client, []) clears the entire buffer, including the new metric. This results in data loss for metrics that trigger a buffer flush.

💡 Suggested Fix

Modify _INTERNAL_captureSerializedMetric to ensure that the _INTERNAL_flushMetricsBuffer function is called with the updated buffer, or that the new metric is handled correctly after the old buffer is flushed and cleared, perhaps by re-adding it to a newly cleared buffer.

🤖 Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: packages/core/test/lib/metrics/internal.test.ts#L259-L262
Potential issue: The `_INTERNAL_captureSerializedMetric` function incorrectly handles
metrics when the buffer reaches `MAX_METRIC_BUFFER_SIZE`. When a new metric arrives,
it's added to the buffer via `bufferMap.set(client, [...metricBuffer,
serializedMetric])`. However, the subsequent flush condition check `if
(metricBuffer.length >= MAX_METRIC_BUFFER_SIZE)` and the flush operation
`_INTERNAL_flushMetricsBuffer(client, metricBuffer)` use the *old* `metricBuffer`
reference (before the new metric was added). This leads to the newly added metric being
present in the map when `_INTERNAL_flushMetricsBuffer` is called, but then being lost
when `_getBufferMap().set(client, [])` clears the entire buffer, including the new
metric. This results in data loss for metrics that trigger a buffer flush.

Did we get this right? 👍 / 👎 to inform future reviews.

Reference_id: 2692398

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what we are fixing with 1a4e02a

@github-actions

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser24.6 kB--
@sentry/browser - with treeshaking flags23.09 kB--
@sentry/browser (incl. Tracing)41.26 kB--
@sentry/browser (incl. Tracing, Profiling)45.53 kB--
@sentry/browser (incl. Tracing, Replay)79.73 kB--
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags69.4 kB--
@sentry/browser (incl. Tracing, Replay with Canvas)84.42 kB--
@sentry/browser (incl. Tracing, Replay, Feedback)96.58 kB--
@sentry/browser (incl. Feedback)41.27 kB--
@sentry/browser (incl. sendFeedback)29.27 kB--
@sentry/browser (incl. FeedbackAsync)34.2 kB--
@sentry/react26.29 kB--
@sentry/react (incl. Tracing)43.22 kB--
@sentry/vue29.09 kB--
@sentry/vue (incl. Tracing)43.03 kB--
@sentry/svelte24.61 kB--
CDN Bundle26.91 kB+0.02%+3 B 🔺
CDN Bundle (incl. Tracing)41.81 kB+0.01%+4 B 🔺
CDN Bundle (incl. Tracing, Replay)78.33 kB+0.01%+2 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback)83.81 kB+0.01%+3 B 🔺
CDN Bundle - uncompressed78.85 kB+0.02%+12 B 🔺
CDN Bundle (incl. Tracing) - uncompressed124.01 kB+0.01%+12 B 🔺
CDN Bundle (incl. Tracing, Replay) - uncompressed240.04 kB+0.01%+12 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed252.8 kB+0.01%+12 B 🔺
@sentry/nextjs (client)45.34 kB--
@sentry/sveltekit (client)41.64 kB--
@sentry/node-core50.86 kB--
@sentry/node158.08 kB--
@sentry/node - without tracing92.73 kB--
@sentry/aws-serverless106.5 kB--

View base workflow run

@github-actions

Copy link
Copy Markdown
Contributor

node-overhead report 🧳

Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.

ScenarioRequests/s% of BaselinePrev. Requests/sChange %
GET Baseline8,701-11,316-23%
GET With Sentry1,35716%1,654-18%
GET With Sentry (error only)6,25372%7,684-19%
POST Baseline1,213-1,188+2%
POST With Sentry51743%573-10%
POST With Sentry (error only)1,07989%1,040+4%
MYSQL Baseline3,369-4,059-17%
MYSQL With Sentry46614%562-17%
MYSQL With Sentry (error only)2,76282%3,308-17%

View base workflow run

andreiborza added a commit that referenced this pull request Nov 17, 2025
…18207)
Looks like we swallowed the log that triggers a flush when
`MAX_LOG_BUFFER_SIZE` is surpassed.
Test demonstrating issue:
[5697b7d](5697b7d)
Fix:
[f7a4d8b](f7a4d8b)
Related metrics pr: #18212
v9 backport: #18213
@andreiborza
andreiborza merged commit e3ef3f2 into developNov 17, 2025
380 of 383 checks passed
@andreiborza
andreiborza deleted the ab/fix-metrics-swallowing branch November 17, 2025 08:50
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@andreiborza@chargome@s1gr1d
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(core): Ensure metrics past MAX_METRIC_BUFFER_SIZE are not swallowed - #18212

Merged
andreiborza merged 3 commits into
developfrom
ab/fix-metrics-swallowing
Nov 17, 2025
Merged

fix(core): Ensure metrics past MAX_METRIC_BUFFER_SIZE are not swallowed#18212
andreiborza merged 3 commits into
developfrom
ab/fix-metrics-swallowing

Conversation

@andreiborza

@andreiborzaandreiborza commented Nov 14, 2025

Copy link
Copy Markdown
Member

Looks like we swallowed the metric that triggers a flush when MAX_METRIC_BUFFER_SIZE is surpassed.

Test demonstrating issue: f0737fa
Fix: 1a4e02a

Related logs pr: #18207

Comment on lines +259 to +262
// After flushing the 1000 metrics, the new metric starts a fresh buffer with 1 item
const buffer = _INTERNAL_getMetricBuffer(client);
expect(buffer).toHaveLength(1);
expect(buffer?.[0]?.name).toBe('trigger.flush');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: A metric that triggers a buffer flush is lost because the flush operation clears the buffer after the new metric has been added but before it's processed.
Severity: CRITICAL | Confidence: 1.00

🔍 Detailed Analysis

The _INTERNAL_captureSerializedMetric function incorrectly handles metrics when the buffer reaches MAX_METRIC_BUFFER_SIZE. When a new metric arrives, it's added to the buffer via bufferMap.set(client, [...metricBuffer, serializedMetric]). However, the subsequent flush condition check if (metricBuffer.length >= MAX_METRIC_BUFFER_SIZE) and the flush operation _INTERNAL_flushMetricsBuffer(client, metricBuffer) use the oldmetricBuffer reference (before the new metric was added). This leads to the newly added metric being present in the map when _INTERNAL_flushMetricsBuffer is called, but then being lost when _getBufferMap().set(client, []) clears the entire buffer, including the new metric. This results in data loss for metrics that trigger a buffer flush.

💡 Suggested Fix

Modify _INTERNAL_captureSerializedMetric to ensure that the _INTERNAL_flushMetricsBuffer function is called with the updated buffer, or that the new metric is handled correctly after the old buffer is flushed and cleared, perhaps by re-adding it to a newly cleared buffer.

🤖 Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: packages/core/test/lib/metrics/internal.test.ts#L259-L262
Potential issue: The `_INTERNAL_captureSerializedMetric` function incorrectly handles
metrics when the buffer reaches `MAX_METRIC_BUFFER_SIZE`. When a new metric arrives,
it's added to the buffer via `bufferMap.set(client, [...metricBuffer,
serializedMetric])`. However, the subsequent flush condition check `if
(metricBuffer.length >= MAX_METRIC_BUFFER_SIZE)` and the flush operation
`_INTERNAL_flushMetricsBuffer(client, metricBuffer)` use the *old* `metricBuffer`
reference (before the new metric was added). This leads to the newly added metric being
present in the map when `_INTERNAL_flushMetricsBuffer` is called, but then being lost
when `_getBufferMap().set(client, [])` clears the entire buffer, including the new
metric. This results in data loss for metrics that trigger a buffer flush.

Did we get this right? 👍 / 👎 to inform future reviews.

Reference_id: 2692398

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what we are fixing with 1a4e02a

@github-actions

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser24.6 kB--
@sentry/browser - with treeshaking flags23.09 kB--
@sentry/browser (incl. Tracing)41.26 kB--
@sentry/browser (incl. Tracing, Profiling)45.53 kB--
@sentry/browser (incl. Tracing, Replay)79.73 kB--
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags69.4 kB--
@sentry/browser (incl. Tracing, Replay with Canvas)84.42 kB--
@sentry/browser (incl. Tracing, Replay, Feedback)96.58 kB--
@sentry/browser (incl. Feedback)41.27 kB--
@sentry/browser (incl. sendFeedback)29.27 kB--
@sentry/browser (incl. FeedbackAsync)34.2 kB--
@sentry/react26.29 kB--
@sentry/react (incl. Tracing)43.22 kB--
@sentry/vue29.09 kB--
@sentry/vue (incl. Tracing)43.03 kB--
@sentry/svelte24.61 kB--
CDN Bundle26.91 kB+0.02%+3 B 🔺
CDN Bundle (incl. Tracing)41.81 kB+0.01%+4 B 🔺
CDN Bundle (incl. Tracing, Replay)78.33 kB+0.01%+2 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback)83.81 kB+0.01%+3 B 🔺
CDN Bundle - uncompressed78.85 kB+0.02%+12 B 🔺
CDN Bundle (incl. Tracing) - uncompressed124.01 kB+0.01%+12 B 🔺
CDN Bundle (incl. Tracing, Replay) - uncompressed240.04 kB+0.01%+12 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed252.8 kB+0.01%+12 B 🔺
@sentry/nextjs (client)45.34 kB--
@sentry/sveltekit (client)41.64 kB--
@sentry/node-core50.86 kB--
@sentry/node158.08 kB--
@sentry/node - without tracing92.73 kB--
@sentry/aws-serverless106.5 kB--

View base workflow run

@github-actions

Copy link
Copy Markdown
Contributor

node-overhead report 🧳

Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.

ScenarioRequests/s% of BaselinePrev. Requests/sChange %
GET Baseline8,701-11,316-23%
GET With Sentry1,35716%1,654-18%
GET With Sentry (error only)6,25372%7,684-19%
POST Baseline1,213-1,188+2%
POST With Sentry51743%573-10%
POST With Sentry (error only)1,07989%1,040+4%
MYSQL Baseline3,369-4,059-17%
MYSQL With Sentry46614%562-17%
MYSQL With Sentry (error only)2,76282%3,308-17%

View base workflow run

andreiborza added a commit that referenced this pull request Nov 17, 2025
…18207)
Looks like we swallowed the log that triggers a flush when
`MAX_LOG_BUFFER_SIZE` is surpassed.
Test demonstrating issue:
[5697b7d](5697b7d)
Fix:
[f7a4d8b](f7a4d8b)
Related metrics pr: #18212
v9 backport: #18213
@andreiborza
andreiborza merged commit e3ef3f2 into developNov 17, 2025
380 of 383 checks passed
@andreiborza
andreiborza deleted the ab/fix-metrics-swallowing branch November 17, 2025 08:50
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@andreiborza@chargome@s1gr1d
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(core): Ensure metrics past MAX_METRIC_BUFFER_SIZE are not swallowed - #18212

Merged
andreiborza merged 3 commits into
developfrom
ab/fix-metrics-swallowing
Nov 17, 2025
Merged

fix(core): Ensure metrics past MAX_METRIC_BUFFER_SIZE are not swallowed#18212
andreiborza merged 3 commits into
developfrom
ab/fix-metrics-swallowing

Conversation

@andreiborza

@andreiborzaandreiborza commented Nov 14, 2025

Copy link
Copy Markdown
Member

Looks like we swallowed the metric that triggers a flush when MAX_METRIC_BUFFER_SIZE is surpassed.

Test demonstrating issue: f0737fa
Fix: 1a4e02a

Related logs pr: #18207

Comment on lines +259 to +262
// After flushing the 1000 metrics, the new metric starts a fresh buffer with 1 item
const buffer = _INTERNAL_getMetricBuffer(client);
expect(buffer).toHaveLength(1);
expect(buffer?.[0]?.name).toBe('trigger.flush');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: A metric that triggers a buffer flush is lost because the flush operation clears the buffer after the new metric has been added but before it's processed.
Severity: CRITICAL | Confidence: 1.00

🔍 Detailed Analysis

The _INTERNAL_captureSerializedMetric function incorrectly handles metrics when the buffer reaches MAX_METRIC_BUFFER_SIZE. When a new metric arrives, it's added to the buffer via bufferMap.set(client, [...metricBuffer, serializedMetric]). However, the subsequent flush condition check if (metricBuffer.length >= MAX_METRIC_BUFFER_SIZE) and the flush operation _INTERNAL_flushMetricsBuffer(client, metricBuffer) use the oldmetricBuffer reference (before the new metric was added). This leads to the newly added metric being present in the map when _INTERNAL_flushMetricsBuffer is called, but then being lost when _getBufferMap().set(client, []) clears the entire buffer, including the new metric. This results in data loss for metrics that trigger a buffer flush.

💡 Suggested Fix

Modify _INTERNAL_captureSerializedMetric to ensure that the _INTERNAL_flushMetricsBuffer function is called with the updated buffer, or that the new metric is handled correctly after the old buffer is flushed and cleared, perhaps by re-adding it to a newly cleared buffer.

🤖 Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: packages/core/test/lib/metrics/internal.test.ts#L259-L262
Potential issue: The `_INTERNAL_captureSerializedMetric` function incorrectly handles
metrics when the buffer reaches `MAX_METRIC_BUFFER_SIZE`. When a new metric arrives,
it's added to the buffer via `bufferMap.set(client, [...metricBuffer,
serializedMetric])`. However, the subsequent flush condition check `if
(metricBuffer.length >= MAX_METRIC_BUFFER_SIZE)` and the flush operation
`_INTERNAL_flushMetricsBuffer(client, metricBuffer)` use the *old* `metricBuffer`
reference (before the new metric was added). This leads to the newly added metric being
present in the map when `_INTERNAL_flushMetricsBuffer` is called, but then being lost
when `_getBufferMap().set(client, [])` clears the entire buffer, including the new
metric. This results in data loss for metrics that trigger a buffer flush.

Did we get this right? 👍 / 👎 to inform future reviews.

Reference_id: 2692398

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what we are fixing with 1a4e02a

@github-actions

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser24.6 kB--
@sentry/browser - with treeshaking flags23.09 kB--
@sentry/browser (incl. Tracing)41.26 kB--
@sentry/browser (incl. Tracing, Profiling)45.53 kB--
@sentry/browser (incl. Tracing, Replay)79.73 kB--
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags69.4 kB--
@sentry/browser (incl. Tracing, Replay with Canvas)84.42 kB--
@sentry/browser (incl. Tracing, Replay, Feedback)96.58 kB--
@sentry/browser (incl. Feedback)41.27 kB--
@sentry/browser (incl. sendFeedback)29.27 kB--
@sentry/browser (incl. FeedbackAsync)34.2 kB--
@sentry/react26.29 kB--
@sentry/react (incl. Tracing)43.22 kB--
@sentry/vue29.09 kB--
@sentry/vue (incl. Tracing)43.03 kB--
@sentry/svelte24.61 kB--
CDN Bundle26.91 kB+0.02%+3 B 🔺
CDN Bundle (incl. Tracing)41.81 kB+0.01%+4 B 🔺
CDN Bundle (incl. Tracing, Replay)78.33 kB+0.01%+2 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback)83.81 kB+0.01%+3 B 🔺
CDN Bundle - uncompressed78.85 kB+0.02%+12 B 🔺
CDN Bundle (incl. Tracing) - uncompressed124.01 kB+0.01%+12 B 🔺
CDN Bundle (incl. Tracing, Replay) - uncompressed240.04 kB+0.01%+12 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed252.8 kB+0.01%+12 B 🔺
@sentry/nextjs (client)45.34 kB--
@sentry/sveltekit (client)41.64 kB--
@sentry/node-core50.86 kB--
@sentry/node158.08 kB--
@sentry/node - without tracing92.73 kB--
@sentry/aws-serverless106.5 kB--

View base workflow run

@github-actions

Copy link
Copy Markdown
Contributor

node-overhead report 🧳

Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.

ScenarioRequests/s% of BaselinePrev. Requests/sChange %
GET Baseline8,701-11,316-23%
GET With Sentry1,35716%1,654-18%
GET With Sentry (error only)6,25372%7,684-19%
POST Baseline1,213-1,188+2%
POST With Sentry51743%573-10%
POST With Sentry (error only)1,07989%1,040+4%
MYSQL Baseline3,369-4,059-17%
MYSQL With Sentry46614%562-17%
MYSQL With Sentry (error only)2,76282%3,308-17%

View base workflow run

andreiborza added a commit that referenced this pull request Nov 17, 2025
…18207)
Looks like we swallowed the log that triggers a flush when
`MAX_LOG_BUFFER_SIZE` is surpassed.
Test demonstrating issue:
[5697b7d](5697b7d)
Fix:
[f7a4d8b](f7a4d8b)
Related metrics pr: #18212
v9 backport: #18213
@andreiborza
andreiborza merged commit e3ef3f2 into developNov 17, 2025
380 of 383 checks passed
@andreiborza
andreiborza deleted the ab/fix-metrics-swallowing branch November 17, 2025 08:50
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@andreiborza@chargome@s1gr1d
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(core): Ensure metrics past MAX_METRIC_BUFFER_SIZE are not swallowed - #18212

Merged
andreiborza merged 3 commits into
developfrom
ab/fix-metrics-swallowing
Nov 17, 2025
Merged

fix(core): Ensure metrics past MAX_METRIC_BUFFER_SIZE are not swallowed#18212
andreiborza merged 3 commits into
developfrom
ab/fix-metrics-swallowing

Conversation

@andreiborza

@andreiborzaandreiborza commented Nov 14, 2025

Copy link
Copy Markdown
Member

Looks like we swallowed the metric that triggers a flush when MAX_METRIC_BUFFER_SIZE is surpassed.

Test demonstrating issue: f0737fa
Fix: 1a4e02a

Related logs pr: #18207

Comment on lines +259 to +262
// After flushing the 1000 metrics, the new metric starts a fresh buffer with 1 item
const buffer = _INTERNAL_getMetricBuffer(client);
expect(buffer).toHaveLength(1);
expect(buffer?.[0]?.name).toBe('trigger.flush');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: A metric that triggers a buffer flush is lost because the flush operation clears the buffer after the new metric has been added but before it's processed.
Severity: CRITICAL | Confidence: 1.00

🔍 Detailed Analysis

The _INTERNAL_captureSerializedMetric function incorrectly handles metrics when the buffer reaches MAX_METRIC_BUFFER_SIZE. When a new metric arrives, it's added to the buffer via bufferMap.set(client, [...metricBuffer, serializedMetric]). However, the subsequent flush condition check if (metricBuffer.length >= MAX_METRIC_BUFFER_SIZE) and the flush operation _INTERNAL_flushMetricsBuffer(client, metricBuffer) use the oldmetricBuffer reference (before the new metric was added). This leads to the newly added metric being present in the map when _INTERNAL_flushMetricsBuffer is called, but then being lost when _getBufferMap().set(client, []) clears the entire buffer, including the new metric. This results in data loss for metrics that trigger a buffer flush.

💡 Suggested Fix

Modify _INTERNAL_captureSerializedMetric to ensure that the _INTERNAL_flushMetricsBuffer function is called with the updated buffer, or that the new metric is handled correctly after the old buffer is flushed and cleared, perhaps by re-adding it to a newly cleared buffer.

🤖 Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: packages/core/test/lib/metrics/internal.test.ts#L259-L262
Potential issue: The `_INTERNAL_captureSerializedMetric` function incorrectly handles
metrics when the buffer reaches `MAX_METRIC_BUFFER_SIZE`. When a new metric arrives,
it's added to the buffer via `bufferMap.set(client, [...metricBuffer,
serializedMetric])`. However, the subsequent flush condition check `if
(metricBuffer.length >= MAX_METRIC_BUFFER_SIZE)` and the flush operation
`_INTERNAL_flushMetricsBuffer(client, metricBuffer)` use the *old* `metricBuffer`
reference (before the new metric was added). This leads to the newly added metric being
present in the map when `_INTERNAL_flushMetricsBuffer` is called, but then being lost
when `_getBufferMap().set(client, [])` clears the entire buffer, including the new
metric. This results in data loss for metrics that trigger a buffer flush.

Did we get this right? 👍 / 👎 to inform future reviews.

Reference_id: 2692398

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what we are fixing with 1a4e02a

@github-actions

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser24.6 kB--
@sentry/browser - with treeshaking flags23.09 kB--
@sentry/browser (incl. Tracing)41.26 kB--
@sentry/browser (incl. Tracing, Profiling)45.53 kB--
@sentry/browser (incl. Tracing, Replay)79.73 kB--
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags69.4 kB--
@sentry/browser (incl. Tracing, Replay with Canvas)84.42 kB--
@sentry/browser (incl. Tracing, Replay, Feedback)96.58 kB--
@sentry/browser (incl. Feedback)41.27 kB--
@sentry/browser (incl. sendFeedback)29.27 kB--
@sentry/browser (incl. FeedbackAsync)34.2 kB--
@sentry/react26.29 kB--
@sentry/react (incl. Tracing)43.22 kB--
@sentry/vue29.09 kB--
@sentry/vue (incl. Tracing)43.03 kB--
@sentry/svelte24.61 kB--
CDN Bundle26.91 kB+0.02%+3 B 🔺
CDN Bundle (incl. Tracing)41.81 kB+0.01%+4 B 🔺
CDN Bundle (incl. Tracing, Replay)78.33 kB+0.01%+2 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback)83.81 kB+0.01%+3 B 🔺
CDN Bundle - uncompressed78.85 kB+0.02%+12 B 🔺
CDN Bundle (incl. Tracing) - uncompressed124.01 kB+0.01%+12 B 🔺
CDN Bundle (incl. Tracing, Replay) - uncompressed240.04 kB+0.01%+12 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed252.8 kB+0.01%+12 B 🔺
@sentry/nextjs (client)45.34 kB--
@sentry/sveltekit (client)41.64 kB--
@sentry/node-core50.86 kB--
@sentry/node158.08 kB--
@sentry/node - without tracing92.73 kB--
@sentry/aws-serverless106.5 kB--

View base workflow run

@github-actions

Copy link
Copy Markdown
Contributor

node-overhead report 🧳

Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.

ScenarioRequests/s% of BaselinePrev. Requests/sChange %
GET Baseline8,701-11,316-23%
GET With Sentry1,35716%1,654-18%
GET With Sentry (error only)6,25372%7,684-19%
POST Baseline1,213-1,188+2%
POST With Sentry51743%573-10%
POST With Sentry (error only)1,07989%1,040+4%
MYSQL Baseline3,369-4,059-17%
MYSQL With Sentry46614%562-17%
MYSQL With Sentry (error only)2,76282%3,308-17%

View base workflow run

andreiborza added a commit that referenced this pull request Nov 17, 2025
…18207)
Looks like we swallowed the log that triggers a flush when
`MAX_LOG_BUFFER_SIZE` is surpassed.
Test demonstrating issue:
[5697b7d](5697b7d)
Fix:
[f7a4d8b](f7a4d8b)
Related metrics pr: #18212
v9 backport: #18213
@andreiborza
andreiborza merged commit e3ef3f2 into developNov 17, 2025
380 of 383 checks passed
@andreiborza
andreiborza deleted the ab/fix-metrics-swallowing branch November 17, 2025 08:50
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@andreiborza@chargome@s1gr1d