Skip to content

Commit 045e90a

Browse files
authored
Merge pull request #964 from DataDog/sbarrio/fix/file-based-configuration-issues
[RUM-11388] Fix FileBasedConfiguration related issues
2 parents 604e724 + 89f08ac commit 045e90a

File tree

6 files changed

+157
-134
lines changed

6 files changed

+157
-134
lines changed

example/datadog-configuration.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"$schema": "./node_modules/@datadog/mobile-react-native/datadog-configuration.schema.json",
3+
"configuration": {
4+
"applicationId": "APP_ID",
5+
"batchSize": "SMALL",
6+
"clientToken": "CLIENT_TOKEN",
7+
"env": "ENVIRONMENT",
8+
"longTaskThresholdMs": 1000,
9+
"nativeCrashReportEnabled": true,
10+
"sessionSamplingRate": 100,
11+
"site": "US1",
12+
"telemetrySampleRate": 20,
13+
"trackBackgroundEvents": false,
14+
"trackErrors": true,
15+
"trackInteractions": true,
16+
"trackResources": true,
17+
"trackingConsent": "GRANTED",
18+
"verbosity": "DEBUG"
19+
}
20+
}

example/src/App.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import AboutScreen from './screens/AboutScreen';
77
import style from './screens/styles';
88
import { navigationRef } from './NavigationRoot';
99
import { DdRumReactNavigationTracking, ViewNamePredicate } from '@datadog/mobile-react-navigation';
10-
import {DatadogProvider} from '@datadog/mobile-react-native'
10+
import {DatadogProvider, FileBasedConfiguration} from '@datadog/mobile-react-native'
1111
import { Route } from "@react-navigation/native";
1212
import { NestedNavigator } from './screens/NestedNavigator/NestedNavigator';
1313
import { getDatadogConfig, onDatadogInitialization } from './ddUtils';
@@ -19,9 +19,25 @@ const viewPredicate: ViewNamePredicate = function customViewNamePredicate(route:
1919
return "Custom RN " + trackedName;
2020
}
2121

22+
// === Datadog Provider Configuration schemes ===
23+
24+
// 1.- Direct configuration
25+
const configuration = getDatadogConfig(TrackingConsent.GRANTED)
26+
27+
// 2.- File based configuration from .json
28+
// const configuration = new FileBasedConfiguration(require("../datadog-configuration.json"));
29+
30+
// 3.- File based configuration from .json and custom mapper setup
31+
// const configuration = new FileBasedConfiguration( {
32+
// configuration: require("../datadog-configuration.json").configuration,
33+
// errorEventMapper: (event) => event,
34+
// resourceEventMapper: (event) => event,
35+
// actionEventMapper: (event) => event});
36+
37+
2238
export default function App() {
2339
return (
24-
<DatadogProvider configuration={getDatadogConfig(TrackingConsent.GRANTED)} onInitialization={onDatadogInitialization}>
40+
<DatadogProvider configuration={configuration} onInitialization={onDatadogInitialization}>
2541
<NavigationContainer ref={navigationRef} onReady={() => {
2642
DdRumReactNavigationTracking.startTrackingViews(navigationRef.current, viewPredicate)
2743
}}>

packages/codepush/src/__tests__/index.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ describe('AppCenter Codepush integration', () => {
279279
};
280280

281281
const configuration = new FileBasedConfiguration({
282-
configuration: { configuration: autoInstrumentationConfig }
282+
configuration: autoInstrumentationConfig
283283
});
284284

285285
render(<DatadogCodepushProvider configuration={configuration} />);
@@ -346,7 +346,7 @@ describe('AppCenter Codepush integration', () => {
346346
};
347347

348348
const configuration = new FileBasedConfiguration({
349-
configuration: { configuration: autoInstrumentationConfig }
349+
configuration: autoInstrumentationConfig
350350
});
351351

352352
render(<DatadogCodepushProvider configuration={configuration} />);

packages/core/src/sdk/FileBasedConfiguration/FileBasedConfiguration.ts

Lines changed: 12 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -56,44 +56,7 @@ export class FileBasedConfiguration extends DatadogProviderConfiguration {
5656
const resolveJSONConfiguration = (
5757
userSpecifiedConfiguration: unknown
5858
): Record<string, any> => {
59-
if (
60-
userSpecifiedConfiguration === undefined ||
61-
userSpecifiedConfiguration === null
62-
) {
63-
try {
64-
// This corresponds to a file located at the root of a RN project.
65-
// /!\ We have to write the require this way as dynamic requires are not supported by Hermes.
66-
// eslint-disable-next-line global-require, @typescript-eslint/no-var-requires
67-
const jsonContent = require('../../../../../../datadog-configuration.json');
68-
69-
if (
70-
typeof jsonContent !== 'object' ||
71-
!jsonContent['configuration']
72-
) {
73-
console.error(`Failed to parse the Datadog configuration file located at the root of the project.
74-
Your configuration must validate the node_modules/@datadog/mobile-react-native/datadog-configuration.schema.json JSON schema.
75-
You can use VSCode to check your configuration by adding the following line to your JSON file:
76-
{
77-
"$schema": "./node_modules/@datadog/mobile-react-native/datadog-configuration.schema.json",
78-
}`);
79-
80-
return {};
81-
}
82-
83-
return jsonContent.configuration as Record<string, any>;
84-
} catch (error) {
85-
console.error(`Failed to read Datadog configuration file at the root of the project.
86-
If you don't have a datadog-configuration.json file at the same level as your node_modules directory,\
87-
please use the following syntax:\n
88-
new FileBasedConfiguration({configuration: require('./file/to/configuration-file.json')})
89-
`);
90-
return {};
91-
}
92-
}
93-
if (
94-
typeof userSpecifiedConfiguration !== 'object' ||
95-
!(userSpecifiedConfiguration as any)['configuration']
96-
) {
59+
if (typeof userSpecifiedConfiguration !== 'object') {
9760
console.error(`Failed to parse the Datadog configuration file you provided.
9861
Your configuration must validate the node_modules/@datadog/mobile-react-native/datadog-configuration.schema.json JSON schema.
9962
You can use VSCode to check your configuration by adding the following line to your JSON file:
@@ -104,10 +67,7 @@ You can use VSCode to check your configuration by adding the following line to y
10467
return {};
10568
}
10669

107-
return (userSpecifiedConfiguration as any)['configuration'] as Record<
108-
string,
109-
any
110-
>;
70+
return (userSpecifiedConfiguration as any) as Record<string, any>;
11171
};
11272

11373
export const getJSONConfiguration = (
@@ -130,6 +90,16 @@ export const getJSONConfiguration = (
13090
} => {
13191
const configuration = resolveJSONConfiguration(userSpecifiedConfiguration);
13292

93+
if (
94+
configuration.clientToken === undefined ||
95+
configuration.env === undefined ||
96+
configuration.applicationId === undefined
97+
) {
98+
console.warn(
99+
'DATADOG: Warning: Malformed json configuration file - clientToken, applicationId and env are mandatory properties.'
100+
);
101+
}
102+
133103
return {
134104
clientToken: configuration.clientToken,
135105
env: configuration.env,

packages/core/src/sdk/FileBasedConfiguration/__tests__/FileBasedConfiguration.test.ts

Lines changed: 105 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -16,35 +16,99 @@ import malformedConfiguration from './__fixtures__/malformed-configuration.json'
1616

1717
describe('FileBasedConfiguration', () => {
1818
describe('with user-specified configuration', () => {
19+
it('resolves configuration fields', () => {
20+
const configuration = new FileBasedConfiguration(
21+
configurationAllFields
22+
);
23+
24+
expect(configuration).toMatchInlineSnapshot(`
25+
FileBasedConfiguration {
26+
"actionEventMapper": null,
27+
"actionNameAttribute": "action-name-attr",
28+
"additionalConfiguration": {},
29+
"applicationId": "fake-app-id",
30+
"batchProcessingLevel": "MEDIUM",
31+
"batchSize": "MEDIUM",
32+
"bundleLogsWithRum": true,
33+
"bundleLogsWithTraces": true,
34+
"clientToken": "fake-client-token",
35+
"customEndpoints": {},
36+
"env": "fake-env",
37+
"errorEventMapper": null,
38+
"firstPartyHosts": [
39+
{
40+
"match": "example.com",
41+
"propagatorTypes": [
42+
"b3multi",
43+
"tracecontext",
44+
],
45+
},
46+
],
47+
"initializationMode": "SYNC",
48+
"logEventMapper": null,
49+
"longTaskThresholdMs": 44,
50+
"nativeCrashReportEnabled": false,
51+
"nativeInteractionTracking": false,
52+
"nativeLongTaskThresholdMs": 200,
53+
"nativeViewTracking": false,
54+
"proxyConfig": undefined,
55+
"resourceEventMapper": null,
56+
"resourceTracingSamplingRate": 33,
57+
"serviceName": undefined,
58+
"sessionSamplingRate": 100,
59+
"site": "US5",
60+
"telemetrySampleRate": 20,
61+
"trackBackgroundEvents": false,
62+
"trackErrors": true,
63+
"trackFrustrations": true,
64+
"trackInteractions": true,
65+
"trackResources": true,
66+
"trackWatchdogTerminations": false,
67+
"trackingConsent": "not_granted",
68+
"uploadFrequency": "AVERAGE",
69+
"useAccessibilityLabel": false,
70+
"verbosity": "warn",
71+
"vitalsUpdateFrequency": "AVERAGE",
72+
}
73+
`);
74+
});
75+
76+
it('prints a warning message when the configuration file cannot be parsed correctly', () => {
77+
const warnSpy = jest.spyOn(console, 'warn');
78+
getJSONConfiguration(malformedConfiguration);
79+
80+
expect(warnSpy).toHaveBeenCalledWith(
81+
'DATADOG: Warning: Malformed json configuration file - clientToken, applicationId and env are mandatory properties.'
82+
);
83+
});
84+
1985
it('resolves all properties from a given file path', () => {
2086
const config = new FileBasedConfiguration({
2187
configuration: {
22-
configuration: {
23-
applicationId: 'fake-app-id',
24-
env: 'fake-env',
25-
clientToken: 'fake-client-token',
26-
trackInteractions: true,
27-
trackResources: true,
28-
trackErrors: true,
29-
trackingConsent: 'NOT_GRANTED',
30-
longTaskThresholdMs: 44,
31-
site: 'US5',
32-
verbosity: 'WARN',
33-
actionNameAttribute: 'action-name-attr',
34-
useAccessibilityLabel: false,
35-
resourceTracingSamplingRate: 33,
36-
firstPartyHosts: [
37-
{
38-
match: 'example.com',
39-
propagatorTypes: [
40-
'B3MULTI',
41-
'TRACECONTEXT',
42-
'B3',
43-
'DATADOG'
44-
]
45-
}
46-
]
47-
}
88+
applicationId: 'fake-app-id',
89+
env: 'fake-env',
90+
clientToken: 'fake-client-token',
91+
trackInteractions: true,
92+
trackResources: true,
93+
trackErrors: true,
94+
trackingConsent: 'NOT_GRANTED',
95+
longTaskThresholdMs: 44,
96+
site: 'US5',
97+
verbosity: 'WARN',
98+
actionNameAttribute: 'action-name-attr',
99+
useAccessibilityLabel: false,
100+
resourceTracingSamplingRate: 33,
101+
firstPartyHosts: [
102+
{
103+
match: 'example.com',
104+
propagatorTypes: [
105+
'B3MULTI',
106+
'TRACECONTEXT',
107+
'B3',
108+
'DATADOG'
109+
]
110+
}
111+
]
48112
}
49113
});
50114
expect(config).toMatchInlineSnapshot(`
@@ -103,11 +167,9 @@ describe('FileBasedConfiguration', () => {
103167
it('applies default values to configuration from a given file path', () => {
104168
const config = new FileBasedConfiguration({
105169
configuration: {
106-
configuration: {
107-
applicationId: 'fake-app-id',
108-
env: 'fake-env',
109-
clientToken: 'fake-client-token'
110-
}
170+
applicationId: 'fake-app-id',
171+
env: 'fake-env',
172+
clientToken: 'fake-client-token'
111173
}
112174
});
113175
expect(config).toMatchInlineSnapshot(`
@@ -159,11 +221,9 @@ describe('FileBasedConfiguration', () => {
159221
const resourceEventMapper = () => null;
160222
const config = new FileBasedConfiguration({
161223
configuration: {
162-
configuration: {
163-
applicationId: 'fake-app-id',
164-
env: 'fake-env',
165-
clientToken: 'fake-client-token'
166-
}
224+
applicationId: 'fake-app-id',
225+
env: 'fake-env',
226+
clientToken: 'fake-client-token'
167227
},
168228
actionEventMapper,
169229
errorEventMapper,
@@ -188,62 +248,20 @@ describe('FileBasedConfiguration', () => {
188248
it('prints a warning message when the first party hosts contain unknown propagator types', () => {
189249
const config = new FileBasedConfiguration({
190250
configuration: {
191-
configuration: {
192-
applicationId: 'fake-app-id',
193-
env: 'fake-env',
194-
clientToken: 'fake-client-token',
195-
firstPartyHosts: [
196-
{
197-
match: 'example.com',
198-
propagatorTypes: ['UNKNOWN']
199-
}
200-
]
201-
}
251+
applicationId: 'fake-app-id',
252+
env: 'fake-env',
253+
clientToken: 'fake-client-token',
254+
firstPartyHosts: [
255+
{
256+
match: 'example.com',
257+
propagatorTypes: ['UNKNOWN']
258+
}
259+
]
202260
}
203261
});
204262
expect(config.firstPartyHosts).toHaveLength(0);
205263
});
206264
});
207-
describe('with resolved file configuration', () => {
208-
it('resolves configuration fields', () => {
209-
const configuration = getJSONConfiguration(configurationAllFields);
210-
211-
expect(configuration).toMatchInlineSnapshot(`
212-
{
213-
"actionNameAttribute": "action-name-attr",
214-
"applicationId": "fake-app-id",
215-
"clientToken": "fake-client-token",
216-
"env": "fake-env",
217-
"firstPartyHosts": [
218-
{
219-
"match": "example.com",
220-
"propagatorTypes": [
221-
"b3multi",
222-
"tracecontext",
223-
],
224-
},
225-
],
226-
"longTaskThresholdMs": 44,
227-
"resourceTracingSamplingRate": 33,
228-
"site": "US5",
229-
"trackErrors": true,
230-
"trackInteractions": true,
231-
"trackResources": true,
232-
"trackingConsent": "not_granted",
233-
"useAccessibilityLabel": false,
234-
"verbosity": "warn",
235-
}
236-
`);
237-
});
238-
it('prints a warning message when the configuration file is not found', () => {
239-
expect(() => getJSONConfiguration(undefined)).not.toThrow();
240-
});
241-
it('prints a warning message when the configuration file cannot be parsed correctly', () => {
242-
expect(() =>
243-
getJSONConfiguration(malformedConfiguration)
244-
).not.toThrow();
245-
});
246-
});
247265

248266
describe('formatPropagatorType', () => {
249267
it('formats all propagatorTypes correctly', () => {
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
{
22
"clientToken": "clientToken",
3-
"env": "env",
43
"applicationId": "applicationId"
54
}

0 commit comments

Comments
 (0)