Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
3 changes: 2 additions & 1 deletion packages/core/src/js/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export type {
UserFeedback,
ErrorEvent,
TransactionEvent,
Metric,
} from '@sentry/core';

export {
Expand Down Expand Up @@ -46,7 +47,6 @@ export {
setCurrentClient,
addEventProcessor,
lastEventId,
metrics,
} from '@sentry/core';

export {
Expand All @@ -63,6 +63,7 @@ export {
consoleLoggingIntegration,
featureFlagsIntegration,
type FeatureFlagsIntegration,
metrics,
} from '@sentry/browser';

export * from './integrations/exports';
Expand Down
7 changes: 3 additions & 4 deletions packages/core/src/js/wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,17 +182,16 @@ export const NATIVE: SentryNativeWrapper = {
for (const rawItem of envelopeItems) {
const [itemHeader, itemPayload] = this._processItem(rawItem);

let bytesContentType: string;
let bytesContentType: string =
typeof itemHeader.content_type === 'string' ? itemHeader.content_type : 'application/octet-stream';
let bytesPayload: number[] | Uint8Array | undefined;

if (typeof itemPayload === 'string') {
bytesContentType = 'text/plain';
bytesPayload = encodeUTF8(itemPayload);
} else if (itemPayload instanceof Uint8Array) {
bytesContentType =
typeof itemHeader.content_type === 'string' ? itemHeader.content_type : 'application/octet-stream';
bytesPayload = itemPayload;
} else {
bytesContentType = 'application/vnd.sentry.items.log+json';
bytesPayload = encodeUTF8(JSON.stringify(itemPayload));
if (!hardCrashed) {
hardCrashed = isHardCrash(itemPayload);
Expand Down
129 changes: 122 additions & 7 deletions packages/core/test/wrapper.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import type { Event, EventEnvelope, EventItem, SeverityLevel } from '@sentry/core';
import type {
EnvelopeItem,
Event,
EventEnvelope,
EventItem,
LogEnvelope, LogSeverityLevel,
MetricEnvelope,
MetricType,
SeverityLevel } from '@sentry/core';
import { createEnvelope, debug } from '@sentry/core';
import * as RN from 'react-native';
import type { Spec } from '../src/js/NativeRNSentry';
Expand Down Expand Up @@ -391,7 +399,7 @@ describe('Tests Native Wrapper', () => {
base64StringFromByteArray(
utf8ToBytes(
'{"event_id":"event0","sent_at":"123"}\n' +
'{"type":"event","content_type":"application/vnd.sentry.items.log+json","length":87}\n' +
'{"type":"event","content_type":"application/octet-stream","length":87}\n' +
'{"event_id":"event0","message":"test","sdk":{"name":"test-sdk-name","version":"2.1.3"}}\n',
),
),
Expand Down Expand Up @@ -423,7 +431,7 @@ describe('Tests Native Wrapper', () => {
base64StringFromByteArray(
utf8ToBytes(
'{"event_id":"event0","sent_at":"123"}\n' +
'{"type":"event","content_type":"application/vnd.sentry.items.log+json","length":93}\n' +
'{"type":"event","content_type":"application/octet-stream","length":93}\n' +
'{"event_id":"event0","sdk":{"name":"test-sdk-name","version":"2.1.3"},"instance":{"value":0}}\n',
),
),
Expand Down Expand Up @@ -466,7 +474,7 @@ describe('Tests Native Wrapper', () => {
base64StringFromByteArray(
utf8ToBytes(
'{"event_id":"event0","sent_at":"123"}\n' +
'{"type":"event","content_type":"application/vnd.sentry.items.log+json","length":50}\n' +
'{"type":"event","content_type":"application/octet-stream","length":50}\n' +
'{"event_id":"event0","message":{"message":"test"}}\n',
),
),
Expand Down Expand Up @@ -505,7 +513,7 @@ describe('Tests Native Wrapper', () => {
base64StringFromByteArray(
utf8ToBytes(
'{"event_id":"event0","sent_at":"123"}\n' +
'{"type":"event","content_type":"application/vnd.sentry.items.log+json","length":124}\n' +
'{"type":"event","content_type":"application/octet-stream","length":124}\n' +
'{"event_id":"event0","exception":{"values":[{"mechanism":{"handled":true,"type":""}}]},"breadcrumbs":[{"message":"crumb!"}]}\n',
),
),
Expand Down Expand Up @@ -534,7 +542,7 @@ describe('Tests Native Wrapper', () => {
base64StringFromByteArray(
utf8ToBytes(
'{"event_id":"event0","sent_at":"123"}\n' +
'{"type":"event","content_type":"application/vnd.sentry.items.log+json","length":58}\n' +
'{"type":"event","content_type":"application/octet-stream","length":58}\n' +
'{"event_id":"event0","breadcrumbs":[{"message":"crumb!"}]}\n',
),
),
Expand Down Expand Up @@ -573,13 +581,120 @@ describe('Tests Native Wrapper', () => {
base64StringFromByteArray(
utf8ToBytes(
'{"event_id":"event0","sent_at":"123"}\n' +
'{"type":"event","content_type":"application/vnd.sentry.items.log+json","length":132}\n' +
'{"type":"event","content_type":"application/octet-stream","length":132}\n' +
'{"event_id":"event0","exception":{"values":[{"mechanism":{"handled":false,"type":"onerror"}}]},"breadcrumbs":[{"message":"crumb!"}]}\n',
),
),
{ hardCrashed: true },
);
});

test('preserves content_type for logs (application/vnd.sentry.items.log+json)', async () => {
const logPayload = {
timestamp: 1234567890,
level: 'info' as LogSeverityLevel,
body: 'test log message',
logger: 'test-logger',
};

const env = createEnvelope<LogEnvelope>({ event_id: 'log0', sent_at: '123' }, [
[
{
type: 'log',
content_type: 'application/vnd.sentry.items.log+json',
item_count: 1,
},
{ items: [logPayload] },
],
]);

await NATIVE.sendEnvelope(env);

const expectedPayload = JSON.stringify({ items: [logPayload] });
const expectedLength = utf8ToBytes(expectedPayload).length;

expect(RNSentry.captureEnvelope).toHaveBeenCalledWith(
base64StringFromByteArray(
utf8ToBytes(
'{"event_id":"log0","sent_at":"123"}\n' +
`{"type":"log","content_type":"application/vnd.sentry.items.log+json","item_count":1,"length":${expectedLength}}\n` +
`${expectedPayload}\n`,
),
),
{ hardCrashed: false },
);
});

test('preserves content_type for metrics (application/vnd.sentry.items.trace-metric+json)', async () => {
const metricsPayload = {
timestamp: 1234567890,
trace_id: 'trace_id',
name: 'metric.name',
type: 'counter' as MetricType,
value: 42,
measurements: {
'metric.name': { value: 42 },
},
};

const env = createEnvelope<MetricEnvelope>({ event_id: 'metric0', sent_at: '123' }, [
[
{
type: 'trace_metric',
content_type: 'application/vnd.sentry.items.trace-metric+json',
item_count: 1,
},
{ items: [metricsPayload] },
],
]);

await NATIVE.sendEnvelope(env);

const expectedPayload = JSON.stringify({ items: [metricsPayload] });
const expectedLength = utf8ToBytes(expectedPayload).length;

expect(RNSentry.captureEnvelope).toHaveBeenCalledWith(
base64StringFromByteArray(
utf8ToBytes(
'{"event_id":"metric0","sent_at":"123"}\n' +
`{"type":"trace_metric","content_type":"application/vnd.sentry.items.trace-metric+json","item_count":1,"length":${expectedLength}}\n` +
`${expectedPayload}\n`,
),
),
{ hardCrashed: false },
);
});

test('preserves custom content_type when provided', async () => {
const payload = {
event_id: 'event0',
message: 'test',
};
const env = createEnvelope({ event_id: 'foo1', sent_at: '123' }, [
[
{
type: 'event',
content_type: 'application/custom-type',
},
payload,
],
]);

await NATIVE.sendEnvelope(env);

const expectedPayload = JSON.stringify(payload);
const expectedLength = utf8ToBytes(expectedPayload).length;
expect(RNSentry.captureEnvelope).toHaveBeenCalledWith(
base64StringFromByteArray(
utf8ToBytes(
'{"event_id":"foo1","sent_at":"123"}\n' +
`{"type":"event","content_type":"application/custom-type","length":${expectedLength}}\n` +
`${expectedPayload}\n`,
),
),
{ hardCrashed: false },
);
});
});

describe('fetchRelease', () => {
Expand Down
4 changes: 2 additions & 2 deletions samples/react-native/src/Screens/ErrorsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,9 @@ const ErrorsScreen = (_props: Props) => {
}}
/>
<Button
title="Send distribution metric"
title="Send count metric with attributes"
onPress={() => {
Sentry.metrics.count('distribution_metric', 100);
Sentry.metrics.count('count_metric', 100, { attributes: { from_test_app: true } });
}}
/>
<Button
Expand Down
Loading