Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions packages/browser-utils/src/metrics/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ export function startStandaloneWebVitalSpan(options: StandaloneWebVitalSpanOptio

const { name, transaction, attributes: passedAttributes, startTime } = options;

const { release, environment, sendDefaultPii } = client.getOptions();
const { release, environment } = client.getOptions();
const { userInfo } = client.getDataCollectionOptions();
// We need to get the replay, user, and activeTransaction from the current scope
// so that we can associate replay id, profile id, and a user display to the span
const replay = client.getIntegrationByName<Integration & { getReplayId: () => string }>('Replay');
Expand Down Expand Up @@ -120,7 +121,7 @@ export function startStandaloneWebVitalSpan(options: StandaloneWebVitalSpanOptio
'user_agent.original': WINDOW.navigator?.userAgent,

// This tells Sentry to infer the IP address from the request
'client.address': sendDefaultPii ? '{{auto}}' : undefined,
'client.address': userInfo ? '{{auto}}' : undefined,

...passedAttributes,
};
Expand Down
81 changes: 81 additions & 0 deletions packages/browser-utils/test/metrics/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import * as SentryCore from '@sentry/core';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { startStandaloneWebVitalSpan } from '../../src/metrics/utils';

vi.mock('@sentry/core', async () => {
const actual = await vi.importActual('@sentry/core');
return {
...actual,
getClient: vi.fn(),
getCurrentScope: vi.fn(),
startInactiveSpan: vi.fn(),
};
});

vi.mock('../../src/types', () => ({
WINDOW: {
navigator: { userAgent: 'test-user-agent' },
},
}));

describe('startStandaloneWebVitalSpan', () => {
const mockScope = {
getUser: vi.fn().mockReturnValue(undefined),
getScopeData: vi.fn().mockReturnValue({ contexts: {} }),
};

beforeEach(() => {
vi.mocked(SentryCore.getCurrentScope).mockReturnValue(mockScope as any);
vi.mocked(SentryCore.startInactiveSpan).mockReturnValue({ end: vi.fn() } as any);
});

afterEach(() => {
vi.clearAllMocks();
});

it('sets client.address to {{auto}} when dataCollection.userInfo is true', () => {
const mockClient = {
getOptions: vi.fn().mockReturnValue({ release: '1.0', environment: 'test' }),
getDataCollectionOptions: vi.fn().mockReturnValue({ userInfo: true }),
getIntegrationByName: vi.fn().mockReturnValue(undefined),
};
vi.mocked(SentryCore.getClient).mockReturnValue(mockClient as any);

startStandaloneWebVitalSpan({
name: 'test-vital',
attributes: {},
startTime: 1.0,
});

expect(SentryCore.startInactiveSpan).toHaveBeenCalledWith(
expect.objectContaining({
attributes: expect.objectContaining({
'client.address': '{{auto}}',
}),
}),
);
});

it('does not set client.address when dataCollection.userInfo is false', () => {
const mockClient = {
getOptions: vi.fn().mockReturnValue({ release: '1.0', environment: 'test' }),
getDataCollectionOptions: vi.fn().mockReturnValue({ userInfo: false }),
getIntegrationByName: vi.fn().mockReturnValue(undefined),
};
vi.mocked(SentryCore.getClient).mockReturnValue(mockClient as any);

startStandaloneWebVitalSpan({
name: 'test-vital',
attributes: {},
startTime: 1.0,
});

expect(SentryCore.startInactiveSpan).toHaveBeenCalledWith(
expect.objectContaining({
attributes: expect.not.objectContaining({
'client.address': expect.anything(),
}),
}),
);
});
});
2 changes: 1 addition & 1 deletion packages/core/src/metrics/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ export function _INTERNAL_flushMetricsBuffer(client: Client, maybeMetricBuffer?:
clientOptions._metadata,
clientOptions.tunnel,
client.getDsn(),
clientOptions.sendDefaultPii,
client.getDataCollectionOptions().userInfo,
);

// Clear the metric buffer after envelopes have been constructed.
Expand Down
37 changes: 37 additions & 0 deletions packages/core/test/lib/metrics/internal.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from '../../../src/metrics/internal';
import type { Metric } from '../../../src/types/metric';
import * as loggerModule from '../../../src/utils/debug-logger';
import * as isBrowserModule from '../../../src/utils/isBrowser';
import * as timeModule from '../../../src/utils/time';
import { _INTERNAL_resetSequenceNumber } from '../../../src/utils/timestampSequence';
import { getDefaultTestClientOptions, TestClient } from '../../mocks/client';
Expand Down Expand Up @@ -252,6 +253,42 @@ describe('_INTERNAL_captureMetric', () => {
expect(buffer?.[0]?.name).toBe('trigger.flush');
});

it('includes ingest_settings with auto when dataCollection.userInfo is true', () => {
vi.spyOn(isBrowserModule, 'isBrowser').mockReturnValue(true);

const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, dataCollection: { userInfo: true } });
const client = new TestClient(options);
const scope = new Scope();
scope.setClient(client);

_INTERNAL_captureMetric({ type: 'counter', name: 'test.metric', value: 1 }, { scope });

const sendEnvelope = vi.spyOn(client as any, 'sendEnvelope').mockImplementation(() => {});
_INTERNAL_flushMetricsBuffer(client);

const envelope = sendEnvelope.mock.calls[0]![0];
const envelopeItemPayload = envelope[1][0][1];
expect(envelopeItemPayload.ingest_settings).toEqual({ infer_ip: 'auto', infer_user_agent: 'auto' });
});

it('includes ingest_settings with never when dataCollection.userInfo is not set', () => {
vi.spyOn(isBrowserModule, 'isBrowser').mockReturnValue(true);

const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN });
const client = new TestClient(options);
const scope = new Scope();
scope.setClient(client);

_INTERNAL_captureMetric({ type: 'counter', name: 'test.metric', value: 1 }, { scope });

const sendEnvelope = vi.spyOn(client as any, 'sendEnvelope').mockImplementation(() => {});
_INTERNAL_flushMetricsBuffer(client);

const envelope = sendEnvelope.mock.calls[0]![0];
const envelopeItemPayload = envelope[1][0][1];
expect(envelopeItemPayload.ingest_settings).toEqual({ infer_ip: 'never', infer_user_agent: 'never' });
});

it('does not flush metrics buffer when it is empty', () => {
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN });
const client = new TestClient(options);
Expand Down
Loading