Skip to content
Merged
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
56 changes: 37 additions & 19 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,22 +163,40 @@ use_frameworks!
```
**NOTE:** You do **NOT** need to add `DdSdkReactNative` here manually, `pod install` should find and install it automatically

Now you can go back to your `App.js/tsx` and use `@flashcatcloud/mobile-react-native` from there
Now you can go back to your `App.js/tsx` and use `@flashcatcloud/mobile-react-native` from there.

Wrap your app root in `DatadogProvider`. It installs the JavaScript auto-instrumentation
during its own render pass and initializes the native SDK afterwards, so requests made while
the app starts up are still collected. Initializing by hand with `DdSdkReactNative.initialize()`
reverses that order and those requests produce no resource event at all — see
[migrating to DatadogProvider](./docs/migrating_to_datadog_provider.md).

Example code:
```
import { DdSdkReactNative, DdSdkReactNativeConfiguration } from '@flashcatcloud/mobile-react-native';
import {
DatadogProvider,
DatadogProviderConfiguration,
TrackingConsent,
} from '@flashcatcloud/mobile-react-native';

const config = new DatadogProviderConfiguration(
"<CLIENT_TOKEN>",
"<ENVIRONMENT_NAME>",
"<RUM_APPLICATION_ID>",
true, // track User interactions (e.g.: Tap on buttons)
true, // track XHR Resources
true, // track Errors
TrackingConsent.GRANTED
)
config.firstPartyHosts = ['example.com'];

const App: () => React$Node = () => {
const config = new DdSdkReactNativeConfiguration(
"<CLIENT_TOKEN>",
"<ENVIRONMENT_NAME>",
"<RUM_APPLICATION_ID>",
true, // track User interactions (e.g.: Tap on buttons)
true, // track XHR Resources
true // track Errors
)
DdSdkReactNative.initialize(config);
...
return (
<DatadogProvider configuration={config}>
...
</DatadogProvider>
);
}
```

Then your project should work without problems ✅
Expand All @@ -190,7 +208,7 @@ If it doesn't, you should fix it before shipping ❌
Many great ideas for new features come from the community, and we'd be happy to
consider yours!

To share your request, you can open an [issue](https://github.com/flashcat/fc-sdk-reactnative/issues/new)
To share your request, you can open an [issue](https://github.com/flashcatcloud/fc-sdk-reactnative/issues/new)
with the details about what you'd like to see. At a minimum, please provide:

- The goal of the new feature;
Expand All @@ -205,7 +223,7 @@ or UI, contact our support team via https://docs.datadoghq.com/help/ for direct,
faster assistance.

You may submit bug reports concerning the Datadog SDK for Android by
[opening a Github issue](https://github.com/flashcat/fc-sdk-reactnative/issues/new).
[opening a Github issue](https://github.com/flashcatcloud/fc-sdk-reactnative/issues/new).
At a minimum, please provide:

- A description of the problem;
Expand Down Expand Up @@ -233,20 +251,20 @@ the bug are best.
## Have a patch?

We welcome code contributions to the library, which you can
[submit as a pull request](https://github.com/flashcat/fc-sdk-reactnative/pull/new/master).
[submit as a pull request](https://github.com/flashcatcloud/fc-sdk-reactnative/compare).
Before you submit a PR, make sure that you first create an Issue to explain the
bug or the feature your patch covers, and make sure another Issue or PR doesn't
already exist.

To create a pull request:

1. **Fork the repository** from https://github.com/flashcat/fc-sdk-reactnative ;
1. **Fork the repository** from https://github.com/flashcatcloud/fc-sdk-reactnative ;
2. **Make any changes** for your patch;
3. **Write tests** that demonstrate how the feature works or how the bug is fixed;
4. **Update any documentation** such as `docs/GettingStarted.md`, especially for
new features;
4. **Update any documentation** — the [core package README](./packages/core/README.md)
and the guides under `docs/`, especially for new features;
5. **Submit the pull request** from your fork back to this
[repository](https://github.com/flashcat/fc-sdk-reactnative) .
[repository](https://github.com/flashcatcloud/fc-sdk-reactnative) .


The pull request will be run through our CI pipeline, and a project member will
Expand Down
51 changes: 47 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,47 @@ yarn add @flashcatcloud/mobile-react-native

Then initialize the SDK with your Flashcat client token and RUM application ID. Data is sent to the Flashcat `CN` site by default; use the `STAGING` site or `customEndpoints` for other environments.

```javascript
import {
DatadogProvider,
DatadogProviderConfiguration,
TrackingConsent
} from '@flashcatcloud/mobile-react-native';

const config = new DatadogProviderConfiguration(
'<CLIENT_TOKEN>',
'<ENVIRONMENT_NAME>',
'<RUM_APPLICATION_ID>',
true, // track user interactions (taps)
true, // track XHR / fetch resources
true, // track JS errors
TrackingConsent.GRANTED
);
config.site = 'CN';
config.serviceName = '<SERVICE_NAME>';
config.nativeCrashReportEnabled = true;
// Your own backend hosts. Only requests matching these carry tracing headers, which is
// what links a resource in RUM to its backend trace.
config.firstPartyHosts = ['example.com'];

export default function App() {
return (
<DatadogProvider configuration={config}>
<Navigation />
</DatadogProvider>
);
}
```

Wrap the app root, as high in the tree as you can. `DatadogProvider` installs the JavaScript
auto-instrumentation during its own render pass and initializes the native SDK afterwards,
buffering whatever is reported meanwhile — so requests made while the app starts up are
collected. Initializing by hand with `DdSdkReactNative.initialize()` reverses that order and
those requests produce no resource event at all; see [migrating to DatadogProvider][10] for
why, and for the react-native-navigation (Wix) case where the manual call is still required.

The [core package reference][8] documents every configuration option, view tracking and data storage.

The RUM React Native SDK supports [Expo][2].

The RUM React Native SDK supports monitoring hybrid applications.
Expand Down Expand Up @@ -47,8 +88,10 @@ Pull requests are welcome. First, open an issue to discuss what you would like t
For more information, see [Apache License, v2.0][7]

[2]: https://docs.expo.dev/
[4]: https://github.com/flashcat/fc-sdk-reactnative/blob/develop/TROUBLESHOOTING.md
[5]: https://github.com/flashcat/fc-sdk-reactnative/issues?q=is%3Aissue
[6]: https://github.com/flashcat/fc-sdk-reactnative/blob/develop/CONTRIBUTING.md
[7]: https://github.com/flashcat/fc-sdk-reactnative/blob/main/LICENSE
[4]: ./TROUBLESHOOTING.md
[5]: https://github.com/flashcatcloud/fc-sdk-reactnative/issues?q=is%3Aissue
[6]: ./CONTRIBUTING.md
[7]: ./LICENSE
[8]: ./packages/core/README.md
[9]: https://opentelemetry.io/
[10]: ./docs/migrating_to_datadog_provider.md
4 changes: 2 additions & 2 deletions TROUBLESHOOTING.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# TROUBLESHOOTING

### No data is being sent to Datadog
### No data is being sent

See the [dedicated troubleshooting guide](./docs/troubleshooting_no_data.md).

### `Undefined symbols: Swift`

Original issue: https://github.com/flashcat/fc-sdk-reactnative/issues/41
Original issue: https://github.com/flashcatcloud/fc-sdk-reactnative/issues/41

If you have the following error message:

Expand Down
45 changes: 43 additions & 2 deletions docs/migrating_to_datadog_provider.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
## Overview

`DatadogProvider` replaces the manual `DdSdkReactNative.initialize()` call. This is a
correctness change, not a style preference — the two do the same work in the opposite order.

`DdSdkReactNative.initialize()` awaits the native SDK across the bridge and installs the
JavaScript auto-instrumentation only after that resolves. The XHR proxy behind
`track XHR / fetch resources` is a live patch on `XMLHttpRequest.prototype`, not a buffered
call: a request that starts before the patch is applied produces no resource event at all.
It is not dropped later and cannot be recovered — the SDK never sees it. Because most apps
fetch their first screen while starting up, that window usually swallows the requests you
most want to look at. Calling `initialize()` earlier narrows that window but does not close it
from inside a React tree: children mount before any effect of yours can await the call. Closing
it that way means awaiting initialization in your entry file before the app is registered, which
trades startup latency for the coverage the provider gives you for free.

`DatadogProvider` installs the instrumentation during its own render pass, before any child
renders, and initializes the native SDK afterwards. Anything reported meanwhile goes into a
bounded buffer and is flushed once the native SDK is up, so the window is closed rather than
merely narrowed.

The same ordering applies to user interactions and JS errors raised during the first render.

## Change the configuration class

Change your configuration from a `DdSdkReactNativeConfiguration` to a `DatadogProviderConfiguration` instance:
Expand Down Expand Up @@ -28,6 +49,9 @@ export default function App() {
}
```

Wrap the app root, as high in the tree as you can. The provider only covers what renders
below it, so every level you push it down is a level whose startup requests go uncollected.

## Remove call to DdSdkReactNative.initialize

Remove the call to `DdSdkReactNative.initialize` in your code.
Expand All @@ -53,6 +77,23 @@ export default function App() {

### Delaying the initialization

See the [documentation on asynchronous initialization][1].
Set `initializationMode` on the configuration. `InitializationMode.SYNC` (the default)
initializes the native SDK as the provider renders. `InitializationMode.ASYNC` defers that
native initialization until after the current interactions and animations have finished, so
it does not compete with your first screen:

```javascript
import { InitializationMode } from '@flashcatcloud/mobile-react-native';

config.initializationMode = InitializationMode.ASYNC;
```

Both modes install the JavaScript auto-instrumentation immediately — `ASYNC` delays only the
native initialization, and events reported in the meantime are buffered either way.

### react-native-navigation (Wix)

[1]: https://github.com/flashcat/fc-sdk-reactnative/blob/develop/docs/advanced_configuration.md#delaying-the-initialization
`DatadogProvider` needs a single React root to wrap, and react-native-navigation does not
have one — each screen is registered separately. Keep `DdSdkReactNative.initialize()` there,
and call it at module scope in your entry file, before registering any screen, so the
uninstrumented window is as small as that setup allows.
86 changes: 86 additions & 0 deletions docs/troubleshooting_no_data.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# No data is being sent

Work down this list in order — each step narrows where the data is being lost.

## 1. Confirm the SDK started

Turn on internal logs and read them before changing anything else:

```javascript
import { SdkVerbosity } from '@flashcatcloud/mobile-react-native';

config.verbosity = SdkVerbosity.DEBUG;
```

You are looking for two separate lines. `Datadog SDK was initialized` means the native SDK is
up. `Datadog SDK is tracking XHR resources` means the network instrumentation was installed —
it is only printed when `trackResources` is enabled, and its absence is the single most common
reason an app reports views but no API calls. (Both strings still carry the upstream name this
SDK was forked from; grep for them verbatim.)

If neither line appears, initialization never ran: check that the provider is actually mounted,
and that no exception is being swallowed around it.

## 2. Views and crashes arrive, but no API calls

This is almost always initialization order.

`DdSdkReactNative.initialize()` awaits the native SDK across the bridge and installs the
JavaScript instrumentation only after that resolves. That instrumentation is a live patch on
`XMLHttpRequest.prototype`, not a buffered call: a request that starts before the patch is
applied produces no resource event at all. It is not queued and delivered late — the SDK never
sees it, and nothing can recover it afterwards.

RUM calls such as `DdRum.startView` *are* buffered before initialization, which is why views
and errors survive while resources do not. That asymmetry is what makes this look like a
resource-specific bug when it is really a timing one.

Use `DatadogProvider` instead. It installs the instrumentation during its own render pass,
before any child renders, and initializes the native SDK afterwards. Wrap the app root, as high
in the tree as you can — the provider only covers what renders below it. See
[migrating to DatadogProvider](./migrating_to_datadog_provider.md).

react-native-navigation (Wix) has no single React root to wrap, so it must keep the manual
call. Put it at module scope in your entry file, before any screen is registered.

## 3. Resources arrive but are not linked to backend traces

Set `firstPartyHosts`. The SDK adds tracing headers only to requests whose host matches, so
with it unset every resource is a dead end:

```javascript
config.firstPartyHosts = ['example.com']; // matches example.com and its subdomains
```

Pass bare hosts, not URLs — no scheme, port or path. Also check
`resourceTracingSamplingRate`, which defaults to `20`: at that value four out of five matching
requests carry no tracing headers by design.

## 4. Nothing arrives at all

- **Wrong destination.** `site` accepts `'CN'` (default) and `'STAGING'`. For a private
deployment leave `site` alone and set `customEndpoints` to your own intake URLs instead;
each value is the complete URL including its path, and is passed to the native SDKs as is.
- **Credentials.** The client token and RUM application ID must come from the same application
in the console. A token that is valid but belongs to another application produces a silent
no-op, not an error.
- **Sampling.** `sessionSamplingRate` is a percentage of *sessions*. At a low value most test
runs legitimately report nothing; set it to `100` while integrating.
- **Consent.** Nothing is collected under `TrackingConsent.NOT_GRANTED`, and events collected
under `PENDING` are discarded unless consent is later granted.

## 5. Only in development

Two request kinds are filtered on purpose in dev builds, and only in dev builds: the Expo
`/logs` endpoint and the React Native packager's `/symbolicate`. Both are noise from the
tooling rather than from your app — the first would otherwise loop, since logging an API call
is itself an API call. Your own requests are never filtered.

Also check whether your own configuration disables collection outside release builds. Guards
such as `trackResources: !__DEV__` are easy to forget and behave exactly like a broken SDK.

## Still stuck

Open an [issue](https://github.com/flashcatcloud/fc-sdk-reactnative/issues/new) with the
`SdkVerbosity.DEBUG` output, your configuration with the credentials removed, and the SDK and
React Native versions.
14 changes: 12 additions & 2 deletions example/src/ddUtils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ import {
// (APPLICATION_ID, CLIENT_TOKEN, ENVIRONMENT).
import {APPLICATION_ID, CLIENT_TOKEN, ENVIRONMENT} from './ddCredentials';

// New SDK Setup - not available for react-native-navigation
// Preferred setup: hand this configuration to a <DatadogProvider> wrapping the app root.
// The provider installs the JS auto-instrumentation as it renders and initializes the native
// SDK afterwards, so requests made during startup are still collected.
//
// Not usable with react-native-navigation, which has no single React root to wrap - see
// initializeDatadog below.
export function getDatadogConfig(trackingConsent: TrackingConsent) {
const config = new DatadogProviderConfiguration(
CLIENT_TOKEN,
Expand All @@ -38,7 +43,12 @@ export function getDatadogConfig(trackingConsent: TrackingConsent) {
DdSdkReactNative.setAttributes({campaign: "ad-network"})
}

// Legacy SDK Setup
// Manual setup. Only correct for react-native-navigation, where there is no single React root
// for <DatadogProvider> to wrap - every other app should use getDatadogConfig above.
//
// initialize() awaits the native SDK before it patches XMLHttpRequest, so requests issued
// before that resolves produce no resource event at all. Call it at module scope in the entry
// file, before registering any screen, to keep that window as small as this setup allows.
export function initializeDatadog(trackingConsent: TrackingConsent) {

const config = new DdSdkReactNativeConfiguration(
Expand Down
2 changes: 1 addition & 1 deletion packages/codepush/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,5 @@ If you use `datadog-ci react-native upload` to upload your CodePush bundle and s
- `version` to completely override the version

[1]: https://github.com/microsoft/react-native-code-push
[2]: https://github.com/flashcat/fc-sdk-reactnative/tree/main/packages/core
[2]: ../core
[3]: https://github.com/DataDog/datadog-ci/tree/master/src/commands/react-native#codepush
Loading
Loading