diff --git a/.size-limit.js b/.size-limit.js index cad516a0a49a..043b1d8555bf 100644 --- a/.size-limit.js +++ b/.size-limit.js @@ -8,7 +8,7 @@ module.exports = [ path: 'packages/browser/build/npm/esm/prod/index.js', import: createImport('init'), gzip: true, - limit: '26 KB', + limit: '27 KB', }, { name: '@sentry/browser - with treeshaking flags', @@ -59,7 +59,7 @@ module.exports = [ path: 'packages/browser/build/npm/esm/prod/index.js', import: createImport('init', 'browserTracingIntegration', 'replayIntegration'), gzip: true, - limit: '83 KB', + limit: '84 KB', }, { name: '@sentry/browser (incl. Tracing, Replay) - with treeshaking flags', @@ -96,7 +96,7 @@ module.exports = [ path: 'packages/browser/build/npm/esm/prod/index.js', import: createImport('init', 'browserTracingIntegration', 'replayIntegration', 'feedbackIntegration'), gzip: true, - limit: '100 KB', + limit: '101 KB', }, { name: '@sentry/browser (incl. Feedback)', @@ -138,7 +138,7 @@ module.exports = [ path: 'packages/browser/build/npm/esm/prod/index.js', import: createImport('init', 'metrics', 'logger'), gzip: true, - limit: '28 KB', + limit: '29 KB', }, // React SDK (ESM) { @@ -178,7 +178,7 @@ module.exports = [ path: 'packages/svelte/build/esm/index.js', import: createImport('init'), gzip: true, - limit: '26 KB', + limit: '27 KB', }, // Browser CDN bundles { @@ -197,7 +197,7 @@ module.exports = [ name: 'CDN Bundle (incl. Logs, Metrics)', path: createCDNPath('bundle.logs.metrics.min.js'), gzip: true, - limit: '30 KB', + limit: '31 KB', }, { name: 'CDN Bundle (incl. Tracing, Logs, Metrics)', @@ -283,14 +283,14 @@ module.exports = [ path: createCDNPath('bundle.tracing.replay.logs.metrics.min.js'), gzip: false, brotli: false, - limit: '258.5 KB', + limit: '259 KB', }, { name: 'CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed', path: createCDNPath('bundle.tracing.replay.feedback.min.js'), gzip: false, brotli: false, - limit: '268 KB', + limit: '269 KB', }, { name: 'CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed', diff --git a/dev-packages/browser-integration-tests/suites/public-api/logger/integration/test.ts b/dev-packages/browser-integration-tests/suites/public-api/logger/integration/test.ts index 7315e8cf4f36..8312c2a13e4d 100644 --- a/dev-packages/browser-integration-tests/suites/public-api/logger/integration/test.ts +++ b/dev-packages/browser-integration-tests/suites/public-api/logger/integration/test.ts @@ -23,6 +23,8 @@ sentryTest('should capture console object calls', async ({ getLocalTestUrl, page content_type: 'application/vnd.sentry.items.log+json', }, { + version: 2, + ingest_settings: { infer_ip: 'never', infer_user_agent: 'never' }, items: [ { timestamp: expect.any(Number), diff --git a/dev-packages/browser-integration-tests/suites/public-api/logger/scopeAttributes/test.ts b/dev-packages/browser-integration-tests/suites/public-api/logger/scopeAttributes/test.ts index 4d7970945436..07af615712ff 100644 --- a/dev-packages/browser-integration-tests/suites/public-api/logger/scopeAttributes/test.ts +++ b/dev-packages/browser-integration-tests/suites/public-api/logger/scopeAttributes/test.ts @@ -22,6 +22,8 @@ sentryTest('captures logs with scope attributes', async ({ getLocalTestUrl, page content_type: 'application/vnd.sentry.items.log+json', }, { + version: 2, + ingest_settings: { infer_ip: 'never', infer_user_agent: 'never' }, items: [ { timestamp: expect.any(Number), diff --git a/dev-packages/browser-integration-tests/suites/public-api/logger/simple/test.ts b/dev-packages/browser-integration-tests/suites/public-api/logger/simple/test.ts index db6d174820d7..0a464d896c5d 100644 --- a/dev-packages/browser-integration-tests/suites/public-api/logger/simple/test.ts +++ b/dev-packages/browser-integration-tests/suites/public-api/logger/simple/test.ts @@ -23,6 +23,8 @@ sentryTest('should capture all logging methods', async ({ getLocalTestUrl, page content_type: 'application/vnd.sentry.items.log+json', }, { + version: 2, + ingest_settings: { infer_ip: 'never', infer_user_agent: 'never' }, items: [ { timestamp: expect.any(Number), diff --git a/dev-packages/node-core-integration-tests/suites/light-mode/logs/test.ts b/dev-packages/node-core-integration-tests/suites/light-mode/logs/test.ts index 25096f1be7e5..858e80e0718d 100644 --- a/dev-packages/node-core-integration-tests/suites/light-mode/logs/test.ts +++ b/dev-packages/node-core-integration-tests/suites/light-mode/logs/test.ts @@ -11,6 +11,7 @@ describe('light mode logs', () => { .expect({ log: logsContainer => { expect(logsContainer).toEqual({ + version: 2, items: [ { attributes: { diff --git a/dev-packages/node-core-integration-tests/suites/public-api/logs/test.ts b/dev-packages/node-core-integration-tests/suites/public-api/logs/test.ts index 53c80a6194c5..8afc4402475d 100644 --- a/dev-packages/node-core-integration-tests/suites/public-api/logs/test.ts +++ b/dev-packages/node-core-integration-tests/suites/public-api/logs/test.ts @@ -11,6 +11,7 @@ describe('logger public API', () => { .expect({ log: logsContainer => { expect(logsContainer).toEqual({ + version: 2, items: [ { attributes: { diff --git a/dev-packages/node-integration-tests/suites/public-api/logger/test.ts b/dev-packages/node-integration-tests/suites/public-api/logger/test.ts index 6b9f43e738d2..e992d70c4de3 100644 --- a/dev-packages/node-integration-tests/suites/public-api/logger/test.ts +++ b/dev-packages/node-integration-tests/suites/public-api/logger/test.ts @@ -39,6 +39,7 @@ describe('logs', () => { .expect({ log: logsContainer => { expect(logsContainer).toEqual({ + version: 2, items: [ { timestamp: expect.any(Number), diff --git a/packages/core/src/logs/envelope.ts b/packages/core/src/logs/envelope.ts index c1d5b23e1575..3e30a5680316 100644 --- a/packages/core/src/logs/envelope.ts +++ b/packages/core/src/logs/envelope.ts @@ -4,14 +4,18 @@ import type { SerializedLog } from '../types-hoist/log'; import type { SdkMetadata } from '../types-hoist/sdkmetadata'; import { dsnToString } from '../utils/dsn'; import { createEnvelope } from '../utils/envelope'; +import { isBrowser } from '../utils/isBrowser'; /** * Creates a log container envelope item for a list of logs. * * @param items - The logs to include in the envelope. + * @param inferUserData - If true, tells Relay to infer the end-user IP and User-Agent from the incoming request. + * Only emitted as `ingest_settings` in browser environments. * @returns The created log container envelope item. */ -export function createLogContainerEnvelopeItem(items: Array): LogContainerItem { +export function createLogContainerEnvelopeItem(items: Array, inferUserData?: boolean): LogContainerItem { + const inferSetting = inferUserData ? 'auto' : 'never'; return [ { type: 'log', @@ -19,6 +23,10 @@ export function createLogContainerEnvelopeItem(items: Array): Log content_type: 'application/vnd.sentry.items.log+json', }, { + version: 2, + ...(isBrowser() && { + ingest_settings: { infer_ip: inferSetting, infer_user_agent: inferSetting }, + }), items, }, ]; @@ -33,6 +41,7 @@ export function createLogContainerEnvelopeItem(items: Array): Log * @param metadata - The metadata to include in the envelope. * @param tunnel - The tunnel to include in the envelope. * @param dsn - The DSN to include in the envelope. + * @param inferUserData - If true, tells Relay to infer the end-user IP and User-Agent from the incoming request. * @returns The created envelope. */ export function createLogEnvelope( @@ -40,6 +49,7 @@ export function createLogEnvelope( metadata?: SdkMetadata, tunnel?: string, dsn?: DsnComponents, + inferUserData?: boolean, ): LogEnvelope { const headers: LogEnvelope[0] = {}; @@ -54,5 +64,5 @@ export function createLogEnvelope( headers.dsn = dsnToString(dsn); } - return createEnvelope(headers, [createLogContainerEnvelopeItem(logs)]); + return createEnvelope(headers, [createLogContainerEnvelopeItem(logs, inferUserData)]); } diff --git a/packages/core/src/logs/internal.ts b/packages/core/src/logs/internal.ts index 097ffbb6906e..c1eff9f50fcf 100644 --- a/packages/core/src/logs/internal.ts +++ b/packages/core/src/logs/internal.ts @@ -192,7 +192,13 @@ export function _INTERNAL_flushLogsBuffer(client: Client, maybeLogBuffer?: Array } const clientOptions = client.getOptions(); - const envelope = createLogEnvelope(logBuffer, clientOptions._metadata, clientOptions.tunnel, client.getDsn()); + const envelope = createLogEnvelope( + logBuffer, + clientOptions._metadata, + clientOptions.tunnel, + client.getDsn(), + clientOptions.sendDefaultPii, + ); // Clear the log buffer after envelopes have been constructed. _getBufferMap().set(client, []); diff --git a/packages/core/src/types-hoist/log.ts b/packages/core/src/types-hoist/log.ts index 7c704d3caf77..0f84ebbcbdda 100644 --- a/packages/core/src/types-hoist/log.ts +++ b/packages/core/src/types-hoist/log.ts @@ -64,5 +64,10 @@ export interface SerializedLog { } export type SerializedLogContainer = { + version?: number; + ingest_settings?: { + infer_ip?: 'auto' | 'never'; + infer_user_agent?: 'auto' | 'never'; + }; items: Array; }; diff --git a/packages/core/test/lib/logs/envelope.test.ts b/packages/core/test/lib/logs/envelope.test.ts index 7fbe1a439910..86626364f506 100644 --- a/packages/core/test/lib/logs/envelope.test.ts +++ b/packages/core/test/lib/logs/envelope.test.ts @@ -5,6 +5,7 @@ import type { SerializedLog } from '../../../src/types-hoist/log'; import type { SdkMetadata } from '../../../src/types-hoist/sdkmetadata'; import * as utilsDsn from '../../../src/utils/dsn'; import * as utilsEnvelope from '../../../src/utils/envelope'; +import { isBrowser } from '../../../src/utils/isBrowser'; // Mock utils functions vi.mock('../../../src/utils/dsn', () => ({ @@ -13,20 +14,65 @@ vi.mock('../../../src/utils/dsn', () => ({ vi.mock('../../../src/utils/envelope', () => ({ createEnvelope: vi.fn((_headers, items) => [_headers, items]), })); +vi.mock('../../../src/utils/isBrowser', () => ({ + isBrowser: vi.fn(() => false), +})); + +afterEach(() => { + vi.mocked(isBrowser).mockReturnValue(false); +}); describe('createLogContainerEnvelopeItem', () => { - it('creates an envelope item with correct structure', () => { + it('emits version: 2 without ingest_settings when not in browser', () => { + const mockLog: SerializedLog = { + timestamp: 1713859200, + level: 'info', + body: 'Test log message', + }; + + const result = createLogContainerEnvelopeItem([mockLog], true); + + expect(result[0]).toEqual({ type: 'log', item_count: 1, content_type: 'application/vnd.sentry.items.log+json' }); + expect(result[1]).toEqual({ + version: 2, + items: [mockLog], + }); + }); + + it("includes ingest_settings with 'auto' values when in browser and inferUserData is true", () => { + vi.mocked(isBrowser).mockReturnValue(true); + const mockLog: SerializedLog = { timestamp: 1713859200, - level: 'error', - body: 'Test error message', + level: 'info', + body: 'Test log message', }; - const result = createLogContainerEnvelopeItem([mockLog, mockLog]); + const result = createLogContainerEnvelopeItem([mockLog], true); + + expect(result[1]).toEqual({ + version: 2, + ingest_settings: { infer_ip: 'auto', infer_user_agent: 'auto' }, + items: [mockLog], + }); + }); + + it("includes ingest_settings with 'never' values when in browser and inferUserData is false", () => { + vi.mocked(isBrowser).mockReturnValue(true); - expect(result).toHaveLength(2); - expect(result[0]).toEqual({ type: 'log', item_count: 2, content_type: 'application/vnd.sentry.items.log+json' }); - expect(result[1]).toEqual({ items: [mockLog, mockLog] }); + const mockLog: SerializedLog = { + timestamp: 1713859200, + level: 'info', + body: 'Test log message', + }; + + const result = createLogContainerEnvelopeItem([mockLog], false); + + expect(result[1]).toEqual({ + version: 2, + ingest_settings: { infer_ip: 'never', infer_user_agent: 'never' }, + items: [mockLog], + }); }); }); @@ -133,7 +179,7 @@ describe('createLogEnvelope', () => { expect.arrayContaining([ expect.arrayContaining([ { type: 'log', item_count: 2, content_type: 'application/vnd.sentry.items.log+json' }, - { items: mockLogs }, + { version: 2, items: mockLogs }, ]), ]), );