Skip to content

(feat-V7) Log Tracing #4827

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 31 commits into from
Jun 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
20cd6e9
add experimental support for log tracing
lucas-zimerman May 13, 2025
b177094
project cleanup
lucas-zimerman May 13, 2025
5d432d6
Merge branch 'v7' into lz/v7-test-logs
lucas-zimerman May 21, 2025
7c24aa5
Merge branch 'v7' of https://github.com/getsentry/sentry-react-native…
lucas-zimerman May 22, 2025
14ad53a
enable android log
lucas-zimerman May 22, 2025
cc52bf8
Merge branch 'lz/v7-test-logs' of https://github.com/getsentry/sentry…
lucas-zimerman May 22, 2025
a78e311
use correct content type
lucas-zimerman May 22, 2025
9eb1fb4
Merge branch 'v7' into lz/v7-test-logs
lucas-zimerman May 26, 2025
307ccd1
Merge branch 'v7' of https://github.com/getsentry/sentry-react-native…
lucas-zimerman May 26, 2025
d83d2a2
fix lint
lucas-zimerman May 26, 2025
0f2f574
Merge branch 'lz/v7-test-logs' of https://github.com/getsentry/sentry…
lucas-zimerman May 26, 2025
c0c3818
Update samples/react-native/src/App.tsx
lucas-zimerman May 27, 2025
310aeb0
merge v7 / fix yarn lock
lucas-zimerman May 27, 2025
03c3cfb
fix parenthesis
lucas-zimerman May 27, 2025
600f436
avoid var
lucas-zimerman May 27, 2025
d59fce3
add chcangelog
lucas-zimerman May 27, 2025
ab99989
fix tests an add self hosted requirement
lucas-zimerman May 27, 2025
9cb856d
actually mention 25.2.0
lucas-zimerman May 27, 2025
310b00b
Update CHANGELOG.md
lucas-zimerman May 27, 2025
0982fad
Merge branch 'v7' into lz/v7-test-logs
lucas-zimerman May 27, 2025
3ffd7ca
Merge branch 'v7' into lz/v7-test-logs
lucas-zimerman May 28, 2025
c917647
Merge branch 'v7' into lz/v7-test-logs
lucas-zimerman May 28, 2025
2efdcc9
Merge branch 'v7' into lz/v7-test-logs
lucas-zimerman Jun 3, 2025
1225323
Merge branch 'v7' into lz/v7-test-logs
lucas-zimerman Jun 5, 2025
fc591b5
add full snippet
lucas-zimerman Jun 5, 2025
65c222d
move changelog to unreleased :
lucas-zimerman Jun 5, 2025
c670e44
fix lint
lucas-zimerman Jun 5, 2025
34fb837
Merge branch 'v7' into lz/v7-test-logs
lucas-zimerman Jun 6, 2025
79ca49c
Merge branch 'v7' into lz/v7-test-logs
lucas-zimerman Jun 11, 2025
70cbd55
moved changelog to unreleased
lucas-zimerman Jun 11, 2025
026cc10
moved self hosted warning
lucas-zimerman Jun 11, 2025
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
33 changes: 33 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,44 @@

## Unreleased

#### Features

- Add experimental support for Log tracing ([#4827](https://github.com/getsentry/sentry-react-native/pull/4827))

To enable it add the following code to your Sentry Options:

```typescript
Sentry.init({
// other options...
_experiments: {
enableLogs: true,
},
});
```

You can also filter the logs being collected by adding beforeSendLogs into `_experiments`

```typescript
Sentry.init({
// other options...
_experiments: {
enableLogs: true,
beforeSendLog: (log) => {
return log;
},
}
});
```

### Changes

- Remove deprecated `appOwnership` constant use in Expo Go detection ([#4893](https://github.com/getsentry/sentry-react-native/pull/4893))
- Disable AppStart and NativeFrames in unsupported environments (web, Expo Go) ([#4897](https://github.com/getsentry/sentry-react-native/pull/4897))

### Self Hosted

- It is recommended to use Sentry Self Hosted version `25.2.0` or new for React Native V7 or newer

## 7.0.0-beta.0

### Upgrading from 6.x to 7.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,12 @@ protected void getSentryAndroidOptions(
if (rnOptions.hasKey("enableNdk")) {
options.setEnableNdk(rnOptions.getBoolean("enableNdk"));
}
if (rnOptions.hasKey("_experiments")) {
ReadableMap experiments = rnOptions.getMap("_experiments");
if (experiments.hasKey("enableLogs")) {
options.getLogs().setEnabled(experiments.getBoolean("enableLogs"));
}
}
if (rnOptions.hasKey("spotlight")) {
if (rnOptions.getType("spotlight") == ReadableType.Boolean) {
options.setEnableSpotlight(rnOptions.getBoolean("spotlight"));
Expand Down
20 changes: 20 additions & 0 deletions packages/core/src/js/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type {
UserFeedback,
} from '@sentry/core';
import {
_INTERNAL_flushLogsBuffer,
addAutoIpAddressToSession,
addAutoIpAddressToUser,
BaseClient,
Expand All @@ -31,6 +32,8 @@ import { mergeOutcomes } from './utils/outcome';
import { ReactNativeLibraries } from './utils/rnlibraries';
import { NATIVE } from './wrapper';

const DEFAULT_FLUSH_INTERVAL = 5000;

/**
* The Sentry React Native SDK Client.
*
Expand All @@ -39,6 +42,7 @@ import { NATIVE } from './wrapper';
*/
export class ReactNativeClient extends BaseClient<ReactNativeClientOptions> {
private _outcomesBuffer: Outcome[];
private _logFlushIdleTimeout: ReturnType<typeof setTimeout> | undefined;

/**
* Creates a new React Native SDK instance.
Expand All @@ -59,6 +63,22 @@ export class ReactNativeClient extends BaseClient<ReactNativeClientOptions> {
this.on('postprocessEvent', addAutoIpAddressToUser);
this.on('beforeSendSession', addAutoIpAddressToSession);
}

if (options._experiments?.enableLogs) {
this.on('flush', () => {
_INTERNAL_flushLogsBuffer(this);
});

this.on('afterCaptureLog', () => {
if (this._logFlushIdleTimeout) {
clearTimeout(this._logFlushIdleTimeout);
}

this._logFlushIdleTimeout = setTimeout(() => {
_INTERNAL_flushLogsBuffer(this);
}, DEFAULT_FLUSH_INTERVAL);
});
}
}

/**
Expand Down
7 changes: 5 additions & 2 deletions packages/core/src/js/options.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { makeFetchTransport } from '@sentry/browser';
import type { CaptureContext, ClientOptions, Event, EventHint, Options } from '@sentry/core';
import type { Profiler } from '@sentry/react';
import type { BrowserOptions, Profiler } from '@sentry/react';
import type * as React from 'react';
import { Platform } from 'react-native';
import type { TouchEventBoundaryProps } from './touchevents';
Expand All @@ -9,6 +9,9 @@ import { isExpoGo } from './utils/environment';
type ProfilerProps = React.ComponentProps<typeof Profiler>;
type BrowserTransportOptions = Parameters<typeof makeFetchTransport>[0];

type BrowserExperiments = NonNullable<BrowserOptions['_experiments']>;
type SharedExperimentsSubset = Pick<BrowserExperiments, 'enableLogs' | 'beforeSendLog'>;

export interface BaseReactNativeOptions {
/**
* Enables native transport + device info + offline caching.
Expand Down Expand Up @@ -244,7 +247,7 @@ export interface BaseReactNativeOptions {
/**
* Options which are in beta, or otherwise not guaranteed to be stable.
*/
_experiments?: {
_experiments?: SharedExperimentsSubset & {
[key: string]: unknown;

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/js/wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ export const NATIVE: SentryNativeWrapper = {
typeof itemHeader.content_type === 'string' ? itemHeader.content_type : 'application/octet-stream';
bytesPayload = itemPayload;
} else {
bytesContentType = 'application/json';
bytesContentType = 'application/vnd.sentry.items.log+json';
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Should we use the new content type for all requests or only the ones that contain logs? @krystofwoldrich @kahest
This can create a break changes on self -hosted, and I am not sure which version has support for logging.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

on Sentry JavaScript for example, they use application/vnd.sentry.items.log+json by default on all requests

bytesPayload = encodeUTF8(JSON.stringify(itemPayload));
if (!hardCrashed) {
hardCrashed = isHardCrash(itemPayload);
Expand Down
12 changes: 6 additions & 6 deletions packages/core/test/wrapper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ describe('Tests Native Wrapper', () => {
base64StringFromByteArray(
utf8ToBytes(
'{"event_id":"event0","sent_at":"123"}\n' +
'{"type":"event","content_type":"application/json","length":87}\n' +
'{"type":"event","content_type":"application/vnd.sentry.items.log+json","length":87}\n' +
'{"event_id":"event0","message":"test","sdk":{"name":"test-sdk-name","version":"2.1.3"}}\n',
),
),
Expand Down Expand Up @@ -336,7 +336,7 @@ describe('Tests Native Wrapper', () => {
base64StringFromByteArray(
utf8ToBytes(
'{"event_id":"event0","sent_at":"123"}\n' +
'{"type":"event","content_type":"application/json","length":93}\n' +
'{"type":"event","content_type":"application/vnd.sentry.items.log+json","length":93}\n' +
'{"event_id":"event0","sdk":{"name":"test-sdk-name","version":"2.1.3"},"instance":{"value":0}}\n',
),
),
Expand Down Expand Up @@ -379,7 +379,7 @@ describe('Tests Native Wrapper', () => {
base64StringFromByteArray(
utf8ToBytes(
'{"event_id":"event0","sent_at":"123"}\n' +
'{"type":"event","content_type":"application/json","length":50}\n' +
'{"type":"event","content_type":"application/vnd.sentry.items.log+json","length":50}\n' +
'{"event_id":"event0","message":{"message":"test"}}\n',
),
),
Expand Down Expand Up @@ -418,7 +418,7 @@ describe('Tests Native Wrapper', () => {
base64StringFromByteArray(
utf8ToBytes(
'{"event_id":"event0","sent_at":"123"}\n' +
'{"type":"event","content_type":"application/json","length":124}\n' +
'{"type":"event","content_type":"application/vnd.sentry.items.log+json","length":124}\n' +
'{"event_id":"event0","exception":{"values":[{"mechanism":{"handled":true,"type":""}}]},"breadcrumbs":[{"message":"crumb!"}]}\n',
),
),
Expand Down Expand Up @@ -447,7 +447,7 @@ describe('Tests Native Wrapper', () => {
base64StringFromByteArray(
utf8ToBytes(
'{"event_id":"event0","sent_at":"123"}\n' +
'{"type":"event","content_type":"application/json","length":58}\n' +
'{"type":"event","content_type":"application/vnd.sentry.items.log+json","length":58}\n' +
'{"event_id":"event0","breadcrumbs":[{"message":"crumb!"}]}\n',
),
),
Expand Down Expand Up @@ -486,7 +486,7 @@ describe('Tests Native Wrapper', () => {
base64StringFromByteArray(
utf8ToBytes(
'{"event_id":"event0","sent_at":"123"}\n' +
'{"type":"event","content_type":"application/json","length":132}\n' +
'{"type":"event","content_type":"application/vnd.sentry.items.log+json","length":132}\n' +
'{"event_id":"event0","exception":{"values":[{"mechanism":{"handled":false,"type":"onerror"}}]},"breadcrumbs":[{"message":"crumb!"}]}\n',
),
),
Expand Down
6 changes: 6 additions & 0 deletions samples/react-native/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,12 @@ Sentry.init({
didCallNativeInit,
);
},
_experiments: {
enableLogs: true,
beforeSendLog: (log) => {
return log;
},
},
enableUserInteractionTracing: true,
integrations(integrations) {
integrations.push(
Expand Down
13 changes: 13 additions & 0 deletions samples/react-native/src/Screens/ErrorsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { FallbackRender } from '@sentry/react';
import NativeSampleModule from '../../tm/NativeSampleModule';
import NativePlatformSampleModule from '../../tm/NativePlatformSampleModule';
import { TimeToFullDisplay } from '../utils';
import { logger } from '@sentry/browser';

const { AssetsModule, CppModule, CrashModule } = NativeModules;

Expand Down Expand Up @@ -150,6 +151,18 @@ const ErrorsScreen = (_props: Props) => {
}
}}
/>
<Button
title="Log console"
onPress={() => {
logger.info('info log');
logger.trace('trace log');
logger.debug('debug log');
logger.warn('warn log');
logger.error('error log');

logger.info('info log with data', { database: 'admin', number: 123, obj: { password: 'admin'} });
}}
/>
{Platform.OS === 'android' && (
<>
<Button
Expand Down
Loading