This module utilizes native New Relic agents to expose the Javascript environment. The New Relic SDKs collect crashes, network traffic, and other information for hybrid apps using native components.
- Capture JavaScript errors
- Capture interactions and the sequence they were created
- Pass user information to New Relic to track user sessions
-
React Native 0.60
-
A working React Native application: use an existing project, or create a new one:
npx react-native init NewRelicRNModuleTestApp
-
Access to a New Relic account with either a trial or full license
-
Mac hardware is required to use the Xcode IDE
- Unzip, clone, or copy this repo to a local workspace. Please review the directory structure
- Copy
NewRelicRN.js
andNewRelicRNModule.js
from the local workspace to the app's root directory - Copy the
ios/rnnewrelic
folder from the local workspace to the app's./ios
directory - Copy the
android/app/src/main/java/com
folder from the local workspace to the project'sandroid/app/src/main/java
directory
Screenshots of the project with Android and iOS module files added are here.
- Install the New Relic native Android agent (instructions here)
- Update the app's
MainApplication.java
file (./android/app/src/main/java/'{package}/MainApplication.java')- Add an imports for the module and the native agent at the top of the file:
import com.newrelic.agent.android.NewRelic; import com.rnnewrelic.NewRelicPackage;
- Update the Package Manager: edit the overridden
ReactNativeHost.getPackages()
method to add this module's package:
List<ReactPackage> packages = new PackageList(this).getPackages(); // Packages that cannot be autolinked yet can be added manually here, for example: // Add this line for New Relic packages.add(new NewRelicPackage()); return packages;
-
Move the
NewRelic.start(Context)
call from thedefault (Main) activity
(as detailed in step #5 of the agent installation instructions) to theMainApplication.onCreate()
method.- Change the
Context
parameter fromthis.getApplication()
tothis
- Ensure
GENERATED_TOKEN
has been replaced with a valid New Relic application token
@Override public void onCreate() { super.onCreate(); NewRelic.withApplicationToken("GENERATED_TOKEN").start(this); ... }
MainApplication.java
should look like this after edits. - Change the
- Add an imports for the module and the native agent at the top of the file:
-
Install the New Relic native IOS agent (instructions here with notes regarding agent v7.+):
- Follow instructions to
Configure using Objective-C
- Xcode may fail when running
pod install
. If it does, runsudo xcode-select --switch /Applications/Xcode.app
, thenpod install
again.
- Follow instructions to
-
From XCode, right-click the app project drop down in the workspace
- select
Add files to ...
- add the
./rnnewrelic
folder copied from the local workspace
- select
-
Update the app's
AppDelegate.m
file:- Ensure
APP_TOKEN
has been replaced with a valid New Relic application token when starting the agent
- Ensure
Follow the guidance from React Native to build and deploy your app to an emulator, simulator or device.
From the app's root directory, run:
npx react-native start
, thennpx react-native run-ios
ornpx react-native run-android
The SDK provides a set of exported Javascript methods used to record app data. Integrate the API into the app's App.js
file. Refer to this example, or the example provided below.
Call this to initialize the SDK. Pass a name of the app's landing screen as an argument.
firstScreen
is text
Call this to record a custom error event.
inError
is JavaScript exception
Call this to record a custom error event at
error
level.
inError
is JavaScript exception
Call this to record a custom error event at
warning
level.
inError
is JavaScript exception
Call this to record a custom error event at
critical
level.
inError
is JavaScript exception
Call this to associate a user with custom events.
userId
is text
Call this to record an interaction event.
screen
is text
Call this to record a custom metric.
sampledata
is JSON
import 'react-native-gesture-handler';
import {createAppContainer} from 'react-navigation';
import {createStackNavigator} from 'react-navigation-stack';
import React from 'react';
import {Text, View, Button, ActivityIndicator, FlatList} from 'react-native';
// Include this line below to access the New Relic Function
import {
nrInit,
nrLog,
nrError,
nrWarning,
nrCritical,
nrInteraction,
nrAddUserId,
nrRecordMetric,
} from './NewRelicRN.js';
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = {
error: null,
errorInfo: null,
};
}
componentDidCatch(error, errorInfo) {
// Catch errors in any child components and re-renders with an error message
this.setState({
error: error,
errorInfo: errorInfo,
});
// New Relic can be added to the ErrorBoundary
nrLog(error);
}
render() {
if (this.state.error) {
// Fallback UI if an error occurs
return (
<div>
<h2>{'Oh-no! Something went wrong'}</h2>
<p className="red">
{this.state.error && this.state.error.toString()}
</p>
<div>{'Component Stack Error Details: '}</div>
<p className="red">{this.state.errorInfo.componentStack}</p>
</div>
);
}
// component normally just renders children
return this.props.children;
}
}
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Welcome',
};
render() {
// New Relic can add an interaction line to see what screens are dislayed
nrInteraction('Welcome');
// Create Custom event tables in New Relic Insights
var sampledata = {
cityName: 'Philadelphia',
zipCode: 19134,
username: 'bob',
alive: true,
};
nrRecordMetric('mycustom', sampledata);
const {navigate} = this.props.navigation;
return (
<Button
title="Go to Good HTTP/s Call Interaction"
onPress={() => navigate('Gdata', {name: 'Jane'})}
/>
);
}
}
class DataScreen extends React.Component {
static navigationOptions = {
title: 'Results',
};
constructor(props) {
super(props);
this.state = {isLoading: true};
}
componentDidMount() {
return fetch('https://facebook.github.io/react-native/movies.json')
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
this.setState(
{
isLoading: false,
dataSource: responseJson.movies,
},
function () {},
);
})
.catch((error) => {
// logging function can be added here as well
console.error(error);
nrError(error);
});
}
render() {
// New Relic can add the user to collect what sessions are related to the user
nrAddUserId('bob');
// New Relic can add an interaction line to see what screens are dislayed
nrInteraction('Results');
if (this.state.isLoading) {
return (
<View style={{flex: 1, padding: 20}}>
<ActivityIndicator />
</View>
);
}
const {navigate} = this.props.navigation;
return (
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<Text>Data Screen</Text>
<Button onPress={() => navigate('Bdata')} title="Bad HTTP error" />
<Button onPress={() => navigate('Home')} title="HOME" />
<Button onPress={() => console.log(this.state)} title="Error" />
<FlatList
data={this.state.dataSource}
renderItem={({item}) => (
<Text>
{item.title}, {item.releaseYear}
</Text>
)}
keyExtractor={({id}, index) => id}
/>
</View>
);
}
}
class BadDataScreen extends React.Component {
static navigationOptions = {
title: 'Dataset',
};
constructor(props) {
super(props);
this.state = {isLoading: true};
}
componentDidMount() {
return fetch('https://facebook.github.io/react-native/moviessssssssss.json')
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
this.setState(
{
isLoading: false,
dataSource: responseJson.movies,
},
function () {},
);
})
.catch((error) => {
console.error(error);
// logging function can be added here as well
nrCritical(error);
});
}
render() {
nrInteraction('Dataset');
if (this.state.isLoading) {
return (
<View style={{flex: 1, padding: 20}}>
<ActivityIndicator />
</View>
);
}
const {navigate} = this.props.navigation;
return (
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<Text>Data Screen</Text>
<Button onPress={() => navigate('Bdata')} title="Bad HTTP error" />
<FlatList
data={this.state.dataSource}
renderItem={({item}) => (
<Text>
{item.title}, {item.releaseYear}
</Text>
)}
keyExtractor={({id}, index) => id}
/>
</View>
);
}
}
const MainNavigator = createStackNavigator({
Home: {screen: HomeScreen},
Gdata: {screen: DataScreen},
Bdata: {screen: BadDataScreen},
});
const App = createAppContainer(MainNavigator);
nrInit('Home');
export default App;
New Relic has open-sourced this project. This project is provided AS-IS WITHOUT WARRANTY OR DEDICATED SUPPORT. Issues and contributions should be reported to the project here on GitHub.
We encourage you to bring your experiences and questions to the Explorers Hub where our community members collaborate on solutions and new ideas.
New Relic hosts and moderates an online forum where customers can interact with New Relic employees as well as other customers to get help and share best practices. Like all official New Relic open source projects, there's a related Community topic in the New Relic Explorers Hub. You can find this project's topic/threads here:
https://discuss.newrelic.com/tags/c/full-stack-observability/mobile-apm/reactnative
Issues and enhancement requests can be submitted in the Issues tab of this repository. Please search for and review the existing open issues before submitting a new issue.
Contributions are encouraged! If you submit an enhancement request, we'll invite you to contribute the change yourself. Please review our Contributors Guide.
Keep in mind that when you submit your pull request, you'll need to sign the CLA via the click-through using CLA-Assistant. If you'd like to execute our corporate CLA, or if you have any questions, please drop us an email at opensource@newrelic.com.
The React Native Modules SDK is licensed under the Apache 2.0 License.
The React Native Modules SDK also uses source code from third-party libraries. You can find full details on which libraries are used and the terms under which they are licensed in the third-party notices document.