diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 84f473f4e..d5254cda4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -142,17 +142,26 @@ use_frameworks! Now you can go back to your `App.js/tsx` and use `@datadog/mobile-react-native` from there Example code: ``` -import { DdSdkReactNative, DdSdkReactNativeConfiguration } from '@datadog/mobile-react-native'; +import { DdSdkReactNative, CoreConfiguration, TrackingConsent } from '@datadog/mobile-react-native'; const App: () => React$Node = () => { - const config = new DdSdkReactNativeConfiguration( + const config = new CoreConfiguration( "", "", - "", - true, // track User interactions (e.g.: Tap on buttons) - true, // track XHR Resources - true // track Errors + TrackingConsent.GRANTED, + { + rumConfiguration: { + applicationId: APPLICATION_ID, + trackInteractions: true, + trackResources: true, + trackFrustrations: true, + trackErrors: true, + }, + logsConfiguration: {}, + traceConfiguration: {} + } ) + DdSdkReactNative.initialize(config); ... ``` diff --git a/MIGRATION.md b/MIGRATION.md new file mode 100644 index 000000000..f37fa23bc --- /dev/null +++ b/MIGRATION.md @@ -0,0 +1,239 @@ +# Migration Guide + +This document outlines breaking changes and migration steps between major versions of the project. + +## Migration from 2.x to 3.0 + +This section describes the main changes introduced in SDK `3.0` compared to `2.x`. + +### Core SDK Initialization changes + +The configuration object used to initialize the SDK has seen some changes in its structure. +Feature configuration is now split into feature-specific properties: rumConfiguration, logsConfiguration, traceConfiguration. + +Then, RUM, Logs and Trace can be independently configured via their optional configuration objects that are each represented by a property inside the core configuration object. + +**NOTE: clientToken, environment and trackingConsent are mandatory for the Core SDK initialization. +ApplicationID is mandatory for RUM to work.** + +For instance, to configure the SDK and enable RUM, Logs and Trace you'd do the following: + +``` +const config = new CoreConfiguration( + CLIENT_TOKEN, + ENVIRONMENT, + TrackingConsent.GRANTED, + { + rumConfiguration: { + applicationId: APPLICATION_ID, + trackInteractions: true, + trackResources: true, + trackFrustrations: true, + sessionSampleRate: 100, + telemetrySampleRate: 100 + } + }, + logsConfiguration: { + logEventMapper: (logEvent) => { + logEvent.message = `[CUSTOM] ${logEvent.message}`; + return logEvent; + } + }, + traceConfiguration: {} +); + +... + +await DdSdkReactNative.initialize(config); +``` + +Or if using the DatadogProvider wrapper: + +``` +const configuration = new DatadogProviderConfiguration( + CLIENT_TOKEN, + ENVIRONMENT, + TrackingConsent.GRANTED, + { + batchSize: BatchSize.SMALL, + uploadFrequency: UploadFrequency.FREQUENT, + batchProcessingLevel: BatchProcessingLevel.MEDIUM, + additionalConfiguration: { + customProperty: "sdk-example-app" + }, + rumConfiguration: { + applicationId: APPLICATION_ID, + trackInteractions: true, + trackResources: true, + trackErrors: true, + sessionSampleRate: 100, + nativeCrashReportEnabled: true + }, + logsConfiguration: { + logEventMapper: (logEvent) => { + logEvent.message = `[CUSTOM] ${logEvent.message}`; + return logEvent; + } + }, + traceConfiguration: {} + } +); + +... + + +``` + +**NOTE: Unlike v2.x, which would always enable all feature modules when initializing the SDK, v3 won't initialize nor enable a feature module if there's no configuration for it.** + +### Property renames and relocations + +| Property | New Location | Changes | +| :--- | :--- | :--- | +| `sampleRate` | *Removed* | Deprecated property removed. | +| `sessionSamplingRate` | `RumConfiguration` | Moved and renamed to `sessionSampleRate` | +| `resourceTracingSamplingRate` | `RumConfiguration` | Moved and renamed to `resourceTraceSampleRate`. | +| `proxyConfig` | `CoreConfiguration` | Renamed to `proxyConfiguration`. | +| `serviceName` | `CoreConfiguration` | Renamed to `service`. | +| `customEndpoints` | *Split* | Split into `customEndpoint` within `RumConfiguration`, `LogsConfiguration`, and `TraceConfiguration` | +| *New Property* | `CoreConfiguration` | `attributeEncoders` added. | +| *New Property* | `RumConfiguration` | `trackMemoryWarnings` added. | +| `nativeCrashReportEnabled` | `RumConfiguration` | Moved. | +| `nativeViewTracking` | `RumConfiguration` | Moved. | +| `nativeInteractionTracking` | `RumConfiguration` | Moved. | +| `firstPartyHosts` | `RumConfiguration` | Moved. | +| `telemetrySampleRate` | `RumConfiguration` | Moved. | +| `nativeLongTaskThresholdMs` | `RumConfiguration` | Moved. | +| `longTaskThresholdMs` | `RumConfiguration` | Moved. | +| `vitalsUpdateFrequency` | `RumConfiguration` | Moved. | +| `trackFrustrations` | `RumConfiguration` | Moved. | +| `trackBackgroundEvents` | `RumConfiguration` | Moved. | +| `bundleLogsWithRum` | `LogsConfiguration` | Moved. | +| `bundleLogsWithTraces` | `LogsConfiguration` | Moved. | +| `trackNonFatalAnrs` | `RumConfiguration` | Moved. | +| `appHangThreshold` | `RumConfiguration` | Moved. | +| `initialResourceThreshold` | `RumConfiguration` | Moved. | +| `trackWatchdogTerminations` | `RumConfiguration` | Moved. | +| `actionNameAttribute` | `RumConfiguration` | Moved. | +| `logEventMapper` | `LogsConfiguration` | Moved. | +| `errorEventMapper` | `RumConfiguration` | Moved. | +| `resourceEventMapper` | `RumConfiguration` | Moved. | +| `actionEventMapper` | `RumConfiguration` | Moved. |`TraceConfiguration`. | +| `useAccessibilityLabel` | `RumConfiguration` | Moved. | +| `trackInteractions` | `RumConfiguration` | Moved. | +| `trackResources` | `RumConfiguration` | Moved. | +| `trackErrors` | `RumConfiguration` | Moved. | + +### FileBasedConfiguration changes + +FileBasedConfiguration now requires a path to a configuration JSON file instead of trying to find a default `datadog-configuration.json` at the app's root level like it did on v2. + +### Changes to SessionReplay configuration +defaultPrivacyLevel has been removed in favor of granular options: imagePrivacyLevel, touchPrivacyLevel and textAndInputPrivacyLevel. + +### Fatal Errors are no longer reported as logs + +Fatal Errors are no longer automatically reported as Logs. Fatal crashes will still be captured, but are no longer duplicated in Logs by default. + +### Context / Attribute encoding +Context / attributes encoding is now safe and deterministic + All attributes passed to Datadog SDK APIs are automatically sanitized and encoded: +Unsupported values (functions, symbols, non-finite numbers, etc.) are dropped with a warning to prevent crashes and undefined behavior +Common types (Date, Error, Map) are properly serialized +Nested objects are flattened using dot notation (a.b.c = value) to match native SDK expectations +Root-level primitives and arrays are wrapped under a context key for schema consistency +Custom encoders can be registered via the attributeEncoders configuration option for domain-specific types + +### Android mindSdkVersion bumped to 23 +Android's minSdkVersion has been bumped to 23. + +### Resource Traces sampling aligned with RUM Sessions +Resource traces are now consistently sampled based on the active RUM session. +You may notice changes in the percentage of reported resources. + +### JS Refresh rate normalization changes +JS refresh rate is now normalized to a 0–60 FPS range. + +### RUM Session sampling changes +v3 modifies the logic to determine whether a trace should be sampled or not, by using the RUM Session ID first, before using the Trace sampling if no session can be found. + +Consistent trace sampling based on RUM Session ID allows RUM clients and the backend to come to a the same decision about sampling without relying on randomness for each trace. + +### Removed APIs + +| API | Status | +| :--- | :--- | +| setUser | Removed in favor of setUserInfo. To completely remove userInfo please use the newly added clearUserInfo | +| setAttributes| Removed in favor of addAttributes | + +### Attributes API +The attribute API has been expanded allowing for addition and removal of single or batches of attributes in bulk.This can be performed with the new granular APIs: addAttributes, removeAttributes, addAttribute and removeAttribute. + +### New APIs + +#### ViewAttributes + +RUM View-level attributes are now automatically propagated to all related child events, including resources, user actions, errors, and long tasks. This ensures consistent metadata across events, making it easier to filter and correlate data on Datadog dashboards. + +To manage View level attributes more effectively, new APIs were added: + +``` +addViewAttribute = (key: string, value: unknown) +removeViewAttribute = (key: string) +addViewAttributes = (attributes: Attributes) +removeViewAttributes = (keys: string[]) +``` + +#### AccountInfo +The AccountInfo API from the native Datadog SDKs has been exposed to React Native as well: + +``` +setAccountInfo = async (accountInfo: { + id: string; + name?: string; + extraInfo?: Record; +}) + +clearAccountInfo = async () + +addAccountExtraInfo = async (extraAccountInfo: Record) +``` + +#### Feature Operations + +``` +startFeatureOperation( + name: string, + operationKey: string | null, + attributes: object +): Promise + +succeedFeatureOperation( + name: string, + operationKey: string | null, + attributes: object +): Promise + +failFeatureOperation( + name: string, + operationKey: string | null, + reason: FeatureOperationFailure, + attributes: object +): Promise +``` + +### New Navigation Tracking Options + +v3 modifies the automatic navigation tracking modules for React Navigation and React Native Navigation and exposes a new NavigationTrackingOptions parameter through the startTracking/startTrackingViews function. + +This `options` object allows to customize the view tracking logic via 3 new optional predicate functions: + +- ViewNamePredicate - a custom naming predicates that decide the display name of views tracked by RUM. +- ViewTrackingPredicate - a custom predicate that decides if a view needs to be tracked by RUM or not. +- ParamsTrackingPredicate - a custom predicate that decides which navigation parameters (if any) need to be tracked alongside the view on RUM. + +All of these are optional, and when not set the default behavior will be used for each one of them. The default behaviours are as follows: + +- ViewNamePredicate - directly forwards the view given name to RUM. +- ViewTrackingPredicate - tracks all views on RUM. +- ParamsTrackingPredicate - does not forward any parameters to RUM. diff --git a/example-new-architecture/App.tsx b/example-new-architecture/App.tsx index 3821d9a66..b5d9a8f58 100644 --- a/example-new-architecture/App.tsx +++ b/example-new-architecture/App.tsx @@ -43,14 +43,16 @@ import {APPLICATION_ID, CLIENT_TOKEN, ENVIRONMENT} from './ddCredentials'; trackInteractions: true, trackResources: true, trackFrustrations: true, + trackErrors: true, sessionSampleRate: 100, - telemetrySampleRate: 100 + telemetrySampleRate: 100, } } ); config.verbosity = SdkVerbosity.DEBUG; config.uploadFrequency = UploadFrequency.FREQUENT; config.batchSize = BatchSize.SMALL; + await DdSdkReactNative.initialize(config); await DdRum.startView('main', 'Main'); diff --git a/example/src/App.tsx b/example/src/App.tsx index a62e1fac2..1427dc5ba 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -6,13 +6,12 @@ import ErrorScreen from './screens/ErrorScreen'; import AboutScreen from './screens/AboutScreen'; import style from './screens/styles'; import { navigationRef } from './NavigationRoot'; -import { DdRumReactNavigationTracking, ViewNamePredicate } from '@datadog/mobile-react-navigation'; -import {DatadogProvider, DatadogProviderConfiguration, FileBasedConfiguration, RumConfiguration} from '@datadog/mobile-react-native' +import { DdRumReactNavigationTracking, NavigationTrackingOptions, ParamsTrackingPredicate, ViewNamePredicate, ViewTrackingPredicate } from '@datadog/mobile-react-navigation'; +import {DatadogProvider } from '@datadog/mobile-react-native' import { Route } from "@react-navigation/native"; import { NestedNavigator } from './screens/NestedNavigator/NestedNavigator'; import { getDatadogConfig, onDatadogInitialization } from './ddUtils'; import { TrackingConsent } from '@datadog/mobile-react-native'; -import { NavigationTrackingOptions, ParamsTrackingPredicate, ViewTrackingPredicate } from '@datadog/mobile-react-navigation/src/rum/instrumentation/DdRumReactNavigationTracking'; const Tab = createBottomTabNavigator(); diff --git a/packages/core/README.md b/packages/core/README.md index 16362628e..1b864b5c2 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -41,23 +41,33 @@ import { const datadogConfiguration = new DatadogProviderConfiguration( '', '', - '', - true, // track User interactions (e.g.: Tap on buttons. You can use 'accessibilityLabel' element property to give tap action the name, otherwise element type will be reported) - true, // track XHR Resources - true // track Errors + TrackingConsent.GRANTED, + { + rumConfiguration: { + applicationId: '', + trackInteractions: true, // track User interactions (e.g.: Tap on buttons. You can use 'accessibilityLabel' element property to give tap action the name, otherwise element type will be reported) + trackResources: true, // track XHR Resources + trackFrustrations: true, // track Frustrations + trackErrors: true, // track errors + nativeCrashReportEnabled: true, // Optional: enable or disable native crash reports + sessionSampleRate: 80, // Optional: sample RUM sessions (here, 80% of session will be sent to Datadog. Default = 100%) + resourceTracingSamplingRate: 80, // Optional: sample tracing integrations for network calls between your app and your backend (here, 80% of calls to your instrumented backend will be linked from the RUM view to the APM view. Default = 20%) + // You need to specify the hosts of your backends to enable tracing with these backends + firstPartyHosts: ['example.com'], // matches 'example.com' and subdomains like 'api.example.com' + }, + logsConfiguration: { + logEventMapper: (logEvent) => { + logEvent.message = `[CUSTOM] ${logEvent.message}`; + return logEvent; + } + }, + traceConfiguration: {} + } ); // Optional: Select your Datadog website (one of "US1", "US3", "US5", "EU1", "AP1", "AP2", or "US1_FED"). Default is "US1". datadogConfiguration.site = 'US1'; -// Optional: enable or disable native crash reports -datadogConfiguration.nativeCrashReportEnabled = true; -// Optional: sample RUM sessions (here, 80% of session will be sent to Datadog. Default = 100%) -datadogConfiguration.sessionSamplingRate = 80; -// Optional: sample tracing integrations for network calls between your app and your backend (here, 80% of calls to your instrumented backend will be linked from the RUM view to the APM view. Default = 20%) -// You need to specify the hosts of your backends to enable tracing with these backends -datadogConfiguration.resourceTracingSamplingRate = 80; -datadogConfiguration.firstPartyHosts = ['example.com']; // matches 'example.com' and subdomains like 'api.example.com' // Optional: set the reported service name (by default, it'll use the package name / bundleIdentifier of your Android / iOS app respectively) -datadogConfiguration.serviceName = 'com.example.reactnative'; +datadogConfiguration.service = 'com.example.reactnative'; // Optional: let the SDK print internal logs (above or equal to the provided level. Default = undefined (meaning no logs)) datadogConfiguration.verbosity = SdkVerbosity.WARN; diff --git a/packages/react-native-apollo-client/README.md b/packages/react-native-apollo-client/README.md index 2e37585dd..97aabc19d 100644 --- a/packages/react-native-apollo-client/README.md +++ b/packages/react-native-apollo-client/README.md @@ -63,10 +63,17 @@ Use a `resourceEventMapper` in your Datadog configuration to remove sensitive da const datadogConfiguration = new DatadogProviderConfiguration( '', '', - '', - true, - true, - true + TrackingConsent.GRANTED, + { + rumConfiguration: { + applicationId: '',, + trackInteractions: true, + trackResources: true, + trackErrors: true, + }, + logsConfiguration: {}, + traceConfiguration: {} + } ); datadogConfiguration.resourceEventMapper = event => { diff --git a/packages/react-navigation/README.md b/packages/react-navigation/README.md index 66f7ceed7..b1a7e35b1 100644 --- a/packages/react-navigation/README.md +++ b/packages/react-navigation/README.md @@ -20,25 +20,53 @@ yarn add @datadog/mobile-react-navigation ### Track view navigation -To track changes in navigation as RUM Views, set the `onReady` callback of your `NavigationContainer` component as follow. You can use the optional `ViewNamePredicate` parameter to replace the automatically detected View name with something more relevant to your use case. - -Returning `null` in the `ViewNamePredicate` prevents the new RUM View from being created. The previous RUM View remains active. +To track changes in navigation as RUM Views, set the `onReady` callback of your `NavigationContainer` component as follow. You can use the optional `NavigationTrackingOptions` parameter to replace the default behaviour of the tracker regarding views, their names and their navigation parameters. ```js import * as React from 'react'; -import { DdRumReactNavigationTracking, ViewNamePredicate } from '@datadog/mobile-react-navigation'; +import { DdRumReactNavigationTracking, ParamsTrackingPredicate, ViewNamePredicate, ViewTrackingPredicate } from '@datadog/mobile-react-navigation'; import { Route } from "@react-navigation/native"; +// Sets a custom name for a tracked view const viewNamePredicate: ViewNamePredicate = function customViewNamePredicate(route: Route, trackedName: string) { return "My custom View Name" } +// Decides if a view should be tracked or not +const viewTrackingPredicate: ViewTrackingPredicate = function customViewTrackingPredicate(route: Route) { + if (route.name === "AlertModal") { + return false; + } + + return true; +} + +// Allows to define what navigation parameters should be tracked for a specific view +const paramsTrackingPredicate: ParamsTrackingPredicate = function customParamsTrackingPredicate(route: Route) { + const filteredParams: any = {}; + if (route.params?.creditCardNumber) { + filteredParams["creditCardNumber"] = "XXXX XXXX XXXX XXXX"; + } + + if (route.params?.username) { + filteredParams["username"] = route.params.username; + } + + return filteredParams; +} + +const navigationTrackingOptions: NavigationTrackingOptions = { + viewNamePredicate, + viewTrackingPredicate, + paramsTrackingPredicate, +} + function App() { const navigationRef = React.useRef(null); return ( { - DdRumReactNavigationTracking.startTrackingViews(navigationRef.current, viewNamePredicate) + DdRumReactNavigationTracking.startTrackingViews(navigationRef.current, navigationTrackingOptions) }}> // … @@ -46,6 +74,13 @@ function App() { ); } ``` + +These predicates are optional, and when not set the default behavior will be used for each one of them. The default behaviors are as follows: + +- ViewNamePredicate - directly forwards the view given name to RUM. +- ViewTrackingPredicate - tracks all views on RUM. +- ParamsTrackingPredicate - does not forward any parameters to RUM. + **Note**: Only one `NavigationContainer` can be tracked at the time. If you need to track another container, stop tracking the previous one first, using `DdRumReactNavigationTracking.stopTrackingViews()`.