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
20 changes: 20 additions & 0 deletions example/datadog-configuration.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"$schema": "./node_modules/@datadog/mobile-react-native/datadog-configuration.schema.json",
"configuration": {
"applicationId": "APP_ID",
"batchSize": "SMALL",
"clientToken": "CLIENT_TOKEN",
"env": "ENVIRONMENT",
"longTaskThresholdMs": 1000,
"nativeCrashReportEnabled": true,
"sessionSamplingRate": 100,
"site": "US1",
"telemetrySampleRate": 20,
"trackBackgroundEvents": false,
"trackErrors": true,
"trackInteractions": true,
"trackResources": true,
"trackingConsent": "GRANTED",
"verbosity": "DEBUG"
}
}
20 changes: 18 additions & 2 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import AboutScreen from './screens/AboutScreen';
import style from './screens/styles';
import { navigationRef } from './NavigationRoot';
import { DdRumReactNavigationTracking, ViewNamePredicate } from '@datadog/mobile-react-navigation';
import {DatadogProvider} from '@datadog/mobile-react-native'
import {DatadogProvider, FileBasedConfiguration} from '@datadog/mobile-react-native'
import { Route } from "@react-navigation/native";
import { NestedNavigator } from './screens/NestedNavigator/NestedNavigator';
import { getDatadogConfig, onDatadogInitialization } from './ddUtils';
Expand All @@ -19,9 +19,25 @@ const viewPredicate: ViewNamePredicate = function customViewNamePredicate(route:
return "Custom RN " + trackedName;
}

// === Datadog Provider Configuration schemes ===

// 1.- Direct configuration
const configuration = getDatadogConfig(TrackingConsent.GRANTED)

// 2.- File based configuration from .json
// const configuration = new FileBasedConfiguration(require("../datadog-configuration.json"));

// 3.- File based configuration from .json and custom mapper setup
// const configuration = new FileBasedConfiguration( {
// configuration: require("../datadog-configuration.json").configuration,
// errorEventMapper: (event) => event,
// resourceEventMapper: (event) => event,
// actionEventMapper: (event) => event});


export default function App() {
return (
<DatadogProvider configuration={getDatadogConfig(TrackingConsent.GRANTED)} onInitialization={onDatadogInitialization}>
<DatadogProvider configuration={configuration} onInitialization={onDatadogInitialization}>
<NavigationContainer ref={navigationRef} onReady={() => {
DdRumReactNavigationTracking.startTrackingViews(navigationRef.current, viewPredicate)
}}>
Expand Down
4 changes: 2 additions & 2 deletions packages/codepush/src/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ describe('AppCenter Codepush integration', () => {
};

const configuration = new FileBasedConfiguration({
configuration: { configuration: autoInstrumentationConfig }
configuration: autoInstrumentationConfig
});

render(<DatadogCodepushProvider configuration={configuration} />);
Expand Down Expand Up @@ -346,7 +346,7 @@ describe('AppCenter Codepush integration', () => {
};

const configuration = new FileBasedConfiguration({
configuration: { configuration: autoInstrumentationConfig }
configuration: autoInstrumentationConfig
});

render(<DatadogCodepushProvider configuration={configuration} />);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,44 +56,7 @@ export class FileBasedConfiguration extends DatadogProviderConfiguration {
const resolveJSONConfiguration = (
userSpecifiedConfiguration: unknown
): Record<string, any> => {
if (
userSpecifiedConfiguration === undefined ||
userSpecifiedConfiguration === null
) {
try {
// This corresponds to a file located at the root of a RN project.
// /!\ We have to write the require this way as dynamic requires are not supported by Hermes.
// eslint-disable-next-line global-require, @typescript-eslint/no-var-requires
const jsonContent = require('../../../../../../datadog-configuration.json');

if (
typeof jsonContent !== 'object' ||
!jsonContent['configuration']
) {
console.error(`Failed to parse the Datadog configuration file located at the root of the project.
Your configuration must validate the node_modules/@datadog/mobile-react-native/datadog-configuration.schema.json JSON schema.
You can use VSCode to check your configuration by adding the following line to your JSON file:
{
"$schema": "./node_modules/@datadog/mobile-react-native/datadog-configuration.schema.json",
}`);

return {};
}

return jsonContent.configuration as Record<string, any>;
} catch (error) {
console.error(`Failed to read Datadog configuration file at the root of the project.
If you don't have a datadog-configuration.json file at the same level as your node_modules directory,\
please use the following syntax:\n
new FileBasedConfiguration({configuration: require('./file/to/configuration-file.json')})
`);
return {};
}
}
if (
typeof userSpecifiedConfiguration !== 'object' ||
!(userSpecifiedConfiguration as any)['configuration']
) {
if (typeof userSpecifiedConfiguration !== 'object') {
console.error(`Failed to parse the Datadog configuration file you provided.
Your configuration must validate the node_modules/@datadog/mobile-react-native/datadog-configuration.schema.json JSON schema.
You can use VSCode to check your configuration by adding the following line to your JSON file:
Expand All @@ -104,10 +67,7 @@ You can use VSCode to check your configuration by adding the following line to y
return {};
}

return (userSpecifiedConfiguration as any)['configuration'] as Record<
string,
any
>;
return (userSpecifiedConfiguration as any) as Record<string, any>;
};

export const getJSONConfiguration = (
Expand All @@ -130,6 +90,16 @@ export const getJSONConfiguration = (
} => {
const configuration = resolveJSONConfiguration(userSpecifiedConfiguration);

if (
configuration.clientToken === undefined ||
configuration.env === undefined ||
configuration.applicationId === undefined
) {
console.warn(
'DATADOG: Warning: Malformed json configuration file - clientToken, applicationId and env are mandatory properties.'
);
}

return {
clientToken: configuration.clientToken,
env: configuration.env,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,35 +16,99 @@ import malformedConfiguration from './__fixtures__/malformed-configuration.json'

describe('FileBasedConfiguration', () => {
describe('with user-specified configuration', () => {
it('resolves configuration fields', () => {
const configuration = new FileBasedConfiguration(
configurationAllFields
);

expect(configuration).toMatchInlineSnapshot(`
FileBasedConfiguration {
"actionEventMapper": null,
"actionNameAttribute": "action-name-attr",
"additionalConfiguration": {},
"applicationId": "fake-app-id",
"batchProcessingLevel": "MEDIUM",
"batchSize": "MEDIUM",
"bundleLogsWithRum": true,
"bundleLogsWithTraces": true,
"clientToken": "fake-client-token",
"customEndpoints": {},
"env": "fake-env",
"errorEventMapper": null,
"firstPartyHosts": [
{
"match": "example.com",
"propagatorTypes": [
"b3multi",
"tracecontext",
],
},
],
"initializationMode": "SYNC",
"logEventMapper": null,
"longTaskThresholdMs": 44,
"nativeCrashReportEnabled": false,
"nativeInteractionTracking": false,
"nativeLongTaskThresholdMs": 200,
"nativeViewTracking": false,
"proxyConfig": undefined,
"resourceEventMapper": null,
"resourceTracingSamplingRate": 33,
"serviceName": undefined,
"sessionSamplingRate": 100,
"site": "US5",
"telemetrySampleRate": 20,
"trackBackgroundEvents": false,
"trackErrors": true,
"trackFrustrations": true,
"trackInteractions": true,
"trackResources": true,
"trackWatchdogTerminations": false,
"trackingConsent": "not_granted",
"uploadFrequency": "AVERAGE",
"useAccessibilityLabel": false,
"verbosity": "warn",
"vitalsUpdateFrequency": "AVERAGE",
}
`);
});

it('prints a warning message when the configuration file cannot be parsed correctly', () => {
const warnSpy = jest.spyOn(console, 'warn');
getJSONConfiguration(malformedConfiguration);

expect(warnSpy).toHaveBeenCalledWith(
'DATADOG: Warning: Malformed json configuration file - clientToken, applicationId and env are mandatory properties.'
);
});

it('resolves all properties from a given file path', () => {
const config = new FileBasedConfiguration({
configuration: {
configuration: {
applicationId: 'fake-app-id',
env: 'fake-env',
clientToken: 'fake-client-token',
trackInteractions: true,
trackResources: true,
trackErrors: true,
trackingConsent: 'NOT_GRANTED',
longTaskThresholdMs: 44,
site: 'US5',
verbosity: 'WARN',
actionNameAttribute: 'action-name-attr',
useAccessibilityLabel: false,
resourceTracingSamplingRate: 33,
firstPartyHosts: [
{
match: 'example.com',
propagatorTypes: [
'B3MULTI',
'TRACECONTEXT',
'B3',
'DATADOG'
]
}
]
}
applicationId: 'fake-app-id',
env: 'fake-env',
clientToken: 'fake-client-token',
trackInteractions: true,
trackResources: true,
trackErrors: true,
trackingConsent: 'NOT_GRANTED',
longTaskThresholdMs: 44,
site: 'US5',
verbosity: 'WARN',
actionNameAttribute: 'action-name-attr',
useAccessibilityLabel: false,
resourceTracingSamplingRate: 33,
firstPartyHosts: [
{
match: 'example.com',
propagatorTypes: [
'B3MULTI',
'TRACECONTEXT',
'B3',
'DATADOG'
]
}
]
}
});
expect(config).toMatchInlineSnapshot(`
Expand Down Expand Up @@ -103,11 +167,9 @@ describe('FileBasedConfiguration', () => {
it('applies default values to configuration from a given file path', () => {
const config = new FileBasedConfiguration({
configuration: {
configuration: {
applicationId: 'fake-app-id',
env: 'fake-env',
clientToken: 'fake-client-token'
}
applicationId: 'fake-app-id',
env: 'fake-env',
clientToken: 'fake-client-token'
}
});
expect(config).toMatchInlineSnapshot(`
Expand Down Expand Up @@ -159,11 +221,9 @@ describe('FileBasedConfiguration', () => {
const resourceEventMapper = () => null;
const config = new FileBasedConfiguration({
configuration: {
configuration: {
applicationId: 'fake-app-id',
env: 'fake-env',
clientToken: 'fake-client-token'
}
applicationId: 'fake-app-id',
env: 'fake-env',
clientToken: 'fake-client-token'
},
actionEventMapper,
errorEventMapper,
Expand All @@ -188,62 +248,20 @@ describe('FileBasedConfiguration', () => {
it('prints a warning message when the first party hosts contain unknown propagator types', () => {
const config = new FileBasedConfiguration({
configuration: {
configuration: {
applicationId: 'fake-app-id',
env: 'fake-env',
clientToken: 'fake-client-token',
firstPartyHosts: [
{
match: 'example.com',
propagatorTypes: ['UNKNOWN']
}
]
}
applicationId: 'fake-app-id',
env: 'fake-env',
clientToken: 'fake-client-token',
firstPartyHosts: [
{
match: 'example.com',
propagatorTypes: ['UNKNOWN']
}
]
}
});
expect(config.firstPartyHosts).toHaveLength(0);
});
});
describe('with resolved file configuration', () => {
it('resolves configuration fields', () => {
const configuration = getJSONConfiguration(configurationAllFields);

expect(configuration).toMatchInlineSnapshot(`
{
"actionNameAttribute": "action-name-attr",
"applicationId": "fake-app-id",
"clientToken": "fake-client-token",
"env": "fake-env",
"firstPartyHosts": [
{
"match": "example.com",
"propagatorTypes": [
"b3multi",
"tracecontext",
],
},
],
"longTaskThresholdMs": 44,
"resourceTracingSamplingRate": 33,
"site": "US5",
"trackErrors": true,
"trackInteractions": true,
"trackResources": true,
"trackingConsent": "not_granted",
"useAccessibilityLabel": false,
"verbosity": "warn",
}
`);
});
it('prints a warning message when the configuration file is not found', () => {
expect(() => getJSONConfiguration(undefined)).not.toThrow();
});
it('prints a warning message when the configuration file cannot be parsed correctly', () => {
expect(() =>
getJSONConfiguration(malformedConfiguration)
).not.toThrow();
});
});

describe('formatPropagatorType', () => {
it('formats all propagatorTypes correctly', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{
"clientToken": "clientToken",
"env": "env",
"applicationId": "applicationId"
}