The Honeycomb OpenTelemetry React Native SDK is Honeycomb’s distribution of OpenTelemetry for React Native applications. It includes instrumentation for things like detecting slow event loops or unhandled exceptions, and provides a component to simplify navigation instrumentation.
This page covers basic usage of the SDK. If you just want to see some code, check out the example on GitHub.
Before you can use Honeycomb’s OpenTelemetry React Native SDK, you need to install it and configure platform-specific dependencies.
Configure Metro to recognize package.json
exports.
To do this, create a new file, metro.config.js
, in your application’s root directory.
Enable package.json
exports in your Metro configuration.
config.resolver.unstable_enablePackageExports = true;
Here’s an example Metro configuration:
const path = require('path');
const { getDefaultConfig } = require('@react-native/metro-config');
const { getConfig } = require('react-native-builder-bob/metro-config');
const pkg = require('../package.json');
const root = path.resolve(__dirname, '..');
const config = getConfig(getDefaultConfig(__dirname), {
root,
pkg,
project: __dirname,
});
// Required to use @opentelemetry package.json "exports" field
config.resolver.unstable_enablePackageExports = true;
module.exports = config;
Install Honeycomb’s OpenTelemetry React Native SDK in your application’s root directory using your preferred package manager.
Install with yarn
:
yarn add @honeycombio/opentelemetry-react-native
Install with npm
:
npm install @honeycombio/opentelemetry-react-native
Install the necessary dependencies for each mobile platform your application supports.
Android dependencies:
Add the following dependencies to your application’s build.gradle
.
dependencies {
//...
implementation "io.honeycomb.android:honeycomb-opentelemetry-android:0.0.16"
implementation "io.opentelemetry.android:android-agent:0.11.0-alpha"
}
If your application’s minSDK
version is lower than 26, add core library desugaring to your android/app/build.gradle
.
android {
compileOptions {
// Enable support for the new language APIs
coreLibraryDesugaringEnabled true
}
dependencies {
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:2.1.5"
}
}
iOS dependencies:
Add the use_frameworks!
option to your application’s Podfile
.
platform :ios, min_ios_version_supported
prepare_react_native_project!
use_frameworks!
From the ios
directory, run pod install
to install the required dependencies.
Initialize the SDK at the start of your React Native application. This ensures that events such as startup time and early view loads are captured.
import { HoneycombReactNativeSDK } from '@honeycombio/opentelemetry-react-native';
import { DiagLogLevel } from '@opentelemetry/api';
const sdk = new HoneycombReactNativeSDK({
// Uncomment the line below to send to EU instance. Defaults to US.
// endpoint: "https://api.eu1.honeycomb.io:443",
apiKey: "YOUR-API-KEY",
serviceName: "YOUR-SERVICE-NAME",
logLevel: DiagLogLevel.DEBUG,
});
sdk.start();
For Android, initialize the SDK at the start of the onCreate()
method in your main Application
class.
// MainApplication.kt
override fun onCreate() {
val options = HoneycombOpentelemetryReactNativeModule.optionsBuilder(this)
// Uncomment the line below to send to EU instance. Defaults to US.
// .setApiEndpoint("https://api.eu1.honeycomb.io:443")
.setApiKey("YOUR-API-KEY")
.setServiceName("YOUR-SERVICE-NAME")
HoneycombOpentelemetryReactNativeModule.configure(this, options)
super.onCreate()
}
For iOS, initialize the SDK at the start of the application()
method in your AppDelegate
class.
// AppDelegate.swift
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
let options = HoneycombReactNative.optionsBuilder()
// Uncomment the line below to send to EU instance. Defaults to US.
// .setAPIEndpoint("https://api.eu1.honeycomb.io:443")
.setAPIKey("YOUR-API-KEY")
.setServiceName("YOUR-SERVICE-NAME")
HoneycombReactNative.configure(options)
}
The Honeycomb React Native SDK can be configured using many of the configuration options from the Honeycomb Web SDK.
import { HoneycombReactNativeSDK } from '@honeycombio/opentelemetry-react-native';
import { DiagLogLevel } from '@opentelemetry/api';
import { ExampleSpanProcessor } from "@/services/ExampleSpanProcessor";
const sdk = new HoneycombReactNativeSDK({
apiKey: "YOUR-API-KEY",
// Uncomment the line below to send to EU instance. Defaults to US.
// endpoint: "https://api.eu1.honeycomb.io:443",
serviceName: "YOUR-SERVICE-NAME",
resourceAttributes: {
"app.environment": "development",
},
logLevel: DiagLogLevel.DEBUG,
fetchInstrumentationConfig: {
propagateTraceHeaderCorsUrls: [
// Regex to match your backend URLs.
// Update to the domains you wish to include.
/.+/g,
]
},
slowEventLoopInstrumentationConfig: {
enabled: true,
},
spanProcessors: [
new ExampleSpanProcessor();
]
});
sdk.start();
Resource attributes are available on every span your instrumentation emits. Adding custom, application-specific attributes makes it easier to correlate your data to important business information.
You can set resource attributes using the resourceAttributes
configuration option.
import { HoneycombReactNativeSDK } from '@honeycombio/opentelemetry-react-native';
const sdk = new HoneycombReactNativeSDK({
apiKey: "YOUR-API-KEY",
// Uncomment the line below to send to EU instance. Defaults to US.
// endpoint: "https://api.eu1.honeycomb.io:443",
serviceName: "YOUR-SERVICE-NAME",
resourceAttributes: {
"app.team": "team name",
},
});
sdk.start();
The SDK includes optional deterministic head sampling.
The sample rate is 1
by default, meaning every trace is exported.
The iOS example below sets a sampleRate
of 40
, meaning 1 in 40 traces will be exported.
This sample rate will only apply to JavaScript/TypeScript traces.
import { HoneycombReactNativeSDK } from '@honeycombio/opentelemetry-react-native';
const sdk = new HoneycombReactNativeSDK({
apiKey: "YOUR-API-KEY",
// Uncomment the line below to send to EU instance. Defaults to US.
// endpoint: "https://api.eu1.honeycomb.io:443",
serviceName: "YOUR-SERVICE-NAME",
sampleRate: 40,
});
sdk.start();
You can configure a sample rate for Android traces with .setSampleRate()
:
// MainApplication.kt
override fun onCreate() {
val options = HoneycombOpentelemetryReactNativeModule.optionsBuilder(this)
// Uncomment the line below to send to EU instance. Defaults to US.
// .setApiEndpoint("https://api.eu1.honeycomb.io:443")
.setApiKey("YOUR-API-KEY")
.setServiceName("YOUR-SERVICE-NAME")
.setSampleRate(40)
HoneycombOpentelemetryReactNativeModule.configure(this, options)
super.onCreate()
}
You can configure a sample rate for iOS traces with .sampleRate()
:
// AppDelegate.swift
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
let options = HoneycombReactNative.optionsBuilder()
// Uncomment the line below to send to EU instance. Defaults to US.
// .setAPIEndpoint("https://api.eu1.honeycomb.io:443")
.setAPIKey("YOUR-API-KEY")
.setServiceName("YOUR-SERVICE-NAME")
.sampleRate(40)
HoneycombReactNative.configure(options)
}
In production, we recommend running an OpenTelemetry Collector. Your application sends telemetry to your Collector instead of directly to Honeycomb. Your Collector then forwards the telemetry data to Honeycomb, keeping your API key stored securely in the Collector’s configuration.
Configure your Collector’s URL by setting the endpoint
option when initializing the Honeycomb React Native SDK:
import { HoneycombReactNativeSDK } from '@honeycombio/opentelemetry-react-native';
const sdk = new HoneycombReactNativeSDK({
endpoint: "http(s)://YOUR-COLLECTOR-URL",
serviceName: "YOUR-SERVICE-NAME",
});
sdk.start();
This example works for all platforms and shows the core configuration needed to connect your application to a Collector.
For Android, use .setApiEndpoint()
:
// MainApplication.kt
override fun onCreate() {
val options = HoneycombOpentelemetryReactNativeModule.optionsBuilder(this)
.setApiEndpoint("http(s)://YOUR-COLLECTOR-URL")
.setServiceName("YOUR-SERVICE-NAME")
HoneycombOpentelemetryReactNativeModule.configure(this, options)
super.onCreate()
}
For iOS, use .setAPIEndpoint()
:
// AppDelegate.swift
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
let options = HoneycombReactNative.optionsBuilder()
.setAPIEndpoint("http(s)://YOUR-COLLECTOR-URL")
.setServiceName("YOUR-SERVICE-NAME")
HoneycombReactNative.configure(options)
}
To send telemetry data directly to Honeycomb, set the apiKey
option with your Ingest API Key.
import { HoneycombReactNativeSDK } from '@honeycombio/opentelemetry-react-native';
const sdk = new HoneycombReactNativeSDK({
apiKey: "YOUR-API-KEY",
// Uncomment the line below to send to EU instance. Defaults to US.
// endpoint: "https://api.eu1.honeycomb.io:443",
serviceName: "YOUR-SERVICE-NAME",
});
sdk.start();
This example works for all platforms and shows the core configuration needed to send data directly to Honeycomb.
For Android, use .setApiKey()
:
// MainApplication.kt
override fun onCreate() {
val options = HoneycombOpentelemetryReactNativeModule.optionsBuilder(this)
// Uncomment the line below to send to EU instance. Defaults to US.
// .setApiEndpoint("https://api.eu1.honeycomb.io:443")
.setApiKey("YOUR-API-KEY")
.setServiceName("YOUR-SERVICE-NAME")
HoneycombOpentelemetryReactNativeModule.configure(this, options)
super.onCreate()
}
For iOS, use .setAPIKey()
:
// AppDelegate.swift
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
let options = HoneycombReactNative.optionsBuilder()
// Uncomment the line below to send to EU instance. Defaults to US.
// .setAPIEndpoint("https://api.eu1.honeycomb.io:443")
.setAPIKey("YOUR-API-KEY")
.setServiceName("YOUR-SERVICE-NAME")
HoneycombReactNative.configure(options)
//...
}
The Honeycomb OpenTelemetry React Native SDK includes auto-instrumentation options for:
Automatic instrumentation is enabled by default. You can enable or disable individual auto-instrumentation libraries in your configuration.
import { HoneycombReactNativeSDK } from '@honeycombio/opentelemetry-react-native';
import { DiagLogLevel } from '@opentelemetry/api';
const sdk = new HoneycombReactNativeSDK({
// Uncomment the line below to send to EU instance. Defaults to US.
// endpoint: "https://api.eu1.honeycomb.io:443",
apiKey: "YOUR-API-KEY",
serviceName: "YOUR-SERVICE-NAME",
logLevel: DiagLogLevel.DEBUG,
// auto-instrumentation options
reactNativeStartupInstrumentationConfig: {
enabled: true,
},
uncaughtExceptionInstrumentationConfig: {
enabled: true,
},
fetchInstrumentationConfig: {
enabled: true,
},
slowEventLoopInstrumentationConfig: {
enabled: true,
},
});
sdk.start();
Automatic instrumentation is a fast way to instrument your code, but you get more insight into your application by adding custom, otherwise known as manual, instrumentation.
You can retrieve the currently active span in a trace and add attributes to it. This lets you add more context to traces and gives you more ways to group or filter traces in your queries.
import { trace } from '@opentelemetry/api';
function handleUser(user: User) {
let currentActiveSpan = trace.getActiveSpan();
currentActiveSpan.setAttribute('user.id', user.getId());
}
For manual tracing, you need to get a tracer:
import { trace } from '@opentelemetry/api';
const tracer = trace.getTracer('example-tracer', '0.1.0');
Create custom spans to get a clear view of the critical parts in your application.
import { trace } from '@opentelemetry/api';
function trackWork() {
const tracer = trace.getTracer('example-tracer', '0.1.0');
const span = tracer.startActiveSpan('do work');
console.log('performing work');
span.end();
}
You can instrument React NativeRouter or Expo Router navigation in your application using the <NavigationInstrumentation>
component.
Add a <NavigationInstrumentation>
component as a child of your <NavigationContainer>
component.
Pass the container ref to your navigation container and your navigation instrumentation components.
import { NavigationInstrumentation } from '@honeycombio/opentelemetry-react-native';
import { useNavigationContainerRef, NavigationContainer } from '@react-navigation/native';
export default function App() {
const navigationRef = useNavigationContainerRef();
return (
<NavigationContainer ref={navigationRef}>
<NavigationInstrumentation ref={navigationRef}>
{/* Navigation/UI code*/}
</NavigationInstrumentation>
</NavigationContainer>
);
}
Wrap your navigation code with a <NavigationInstrumentation>
component and pass the container ref to the <NavigationInstrumentation>
component.
import { NavigationInstrumentation } from '@honeycombio/opentelemetry-react-native';
import { useNavigationContainerRef } from 'expo-router';
export default function App() {
const navigationRef = useNavigationContainerRef();
return (
<NavigationInstrumentation ref={navigationRef}>
{/* Navigation/UI code*/}
</NavigationInstrumentation>
);
}
Running into issues? Here are some common problems and ways to fix them.
To explore common issues when sending data, visit Common Issues with Sending Data in Honeycomb.
If you see an error like this when running your application on iOS:
'HoneycombOpentelemetryReactNative/HoneycombOpentelemetryReactNative-Swift.h' file not found when trying to run for iOS
It usually means your application’s Podfile
is missing the use_frameworks!
line.
To resolve this error:
Add use_frameworks!
immediately below prepare_react_native_project!
in your Podfile
:
prepare_react_native_project!
use_frameworks!
Install the iOS dependencies by navigating to your ios
directory and running pod install
:
cd ios
pod install
Unlike JavaScript code, native code does not hot reload on changes. So if you updated your AppDelegate.swift
or MainApplication.kt
files and still not getting native telemetry you’ll need to rebuild your application.
Stop metro, the simulator, and restart the build. If this still doesn’t work try uninstalling the app and reinstalling it.