Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Demo] Add info about React Native app #5704

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 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
1 change: 1 addition & 0 deletions .cspell/en-words.txt
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ quantile
quantiles
quarkus
quoteservice
react-native-app
recommendationservice
redis
relref
Expand Down
4 changes: 3 additions & 1 deletion content/en/docs/demo/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ here.
| C++ | | | [Currency Service](services/currency/) |
| Go | | [Checkout Service](services/checkout/), [Product Catalog Service](services/product-catalog/) | [Checkout Service](services/checkout/), [Product Catalog Service](services/product-catalog/) |
| Java | [Ad Service](services/ad/) | | [Ad Service](services/ad/) |
| JavaScript | | [Frontend](services/frontend/) | [Frontend](services/frontend/), [Payment Service](services/payment/) |
| JavaScript | | | [Payment Service](services/payment/) |
| TypeScript | | [Frontend](services/frontend/), [React Native App](services/react-native-app/) | [Frontend](services/frontend/) |
| Kotlin | | [Fraud Detection Service](services/fraud-detection/) | |
| PHP | | [Quote Service](services/quote/) | [Quote Service](services/quote/) |
| Python | [Recommendation Service](services/recommendation/) | | [Recommendation Service](services/recommendation/) |
Expand All @@ -54,6 +55,7 @@ found here:
- [Recommendation Service](services/recommendation/)
- [Shipping Service](services/shipping/)
- [Image Provider Service](services/imageprovider/)
- [React Native App](services/react-native-app/)

## Scenarios

Expand Down
3 changes: 3 additions & 0 deletions content/en/docs/demo/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ quoteservice(Quote Service):::php
recommendationservice(Recommendation Service):::python
shippingservice(Shipping Service):::rust
queue[(queue<br/>&#40Kafka&#41)]:::java
react-native-app(React Native App):::typescript

adservice ---->|gRPC| flagd

Expand Down Expand Up @@ -73,6 +74,8 @@ recommendationservice -->|gRPC| productcatalogservice
recommendationservice -->|gRPC| flagd

shippingservice -->|HTTP| quoteservice

react-native-app -->|HTTP| frontendproxy
end

classDef dotnet fill:#178600,color:white;
Expand Down
3 changes: 2 additions & 1 deletion content/en/docs/demo/services/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ To visualize request flows, see the [Service Diagram](../architecture/).
| [currencyservice](currency/) | C++ | Converts one money amount to another currency. Uses real values fetched from European Central Bank. It's the highest QPS service. |
| [emailservice](email/) | Ruby | Sends users an order confirmation email (mock/). |
| [frauddetectionservice](fraud-detection/) | Kotlin | Analyzes incoming orders and detects fraud attempts (mock/). |
| [frontend](frontend/) | JavaScript | Exposes an HTTP server to serve the website. Does not require sign up / login and generates session IDs for all users automatically. |
| [frontend](frontend/) | TypeScript | Exposes an HTTP server to serve the website. Does not require sign up / login and generates session IDs for all users automatically. |
julianocosta89 marked this conversation as resolved.
Show resolved Hide resolved
| [loadgenerator](load-generator/) | Python/Locust | Continuously sends requests imitating realistic user shopping flows to the frontend. |
| [paymentservice](payment/) | JavaScript | Charges the given credit card info (mock/) with the given amount and returns a transaction ID. |
| [productcatalogservice](product-catalog/) | Go | Provides the list of products from a JSON file and ability to search products and get individual products. |
| [quoteservice](quote/) | PHP | Calculates the shipping costs, based on the number of items to be shipped. |
| [recommendationservice](recommendation/) | Python | Recommends other products based on what's given in the cart. |
| [shippingservice](shipping/) | Rust | Gives shipping cost estimates based on the shopping cart. Ships items to the given address (mock/). |
| [react-native-app](react-native-app/) | TypeScript | React Native mobile application that provides a UI on top of the shopping services. |
149 changes: 149 additions & 0 deletions content/en/docs/demo/services/react-native-app.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
---
title: React Native App
cSpell:ignore: typeof
---

The React Native app provides a mobile UI for users on Android and iOS devices
to interact with the demo's services. It is built with
[Expo](https://docs.expo.dev/get-started/introduction/) and uses Expo's
file-based routing to layout the screens for the app.

[React Native app source](https://github.com/open-telemetry/opentelemetry-demo/blob/main/src/react-native-app/)

## Instrumentation

The application uses the OpenTelemetry packages to instrument the application at
the JS layer
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
the JS layer
the JS layer.


{{% alert title="Important" color="warning" %}}

The JS OTel packages are supported for node and web environments.
While they work for React Native as well they are not currently explicitly
supported for that environment and may break compatibility with minor version
updates or require workarounds. Building more support for React Native is an
area of active development.

{{% /alert %}}

The main entry point for the application is `app/_layout.tsx` where a hook is
used to initialize the instrumentation and make sure it is loaded before
displaying the UI:

```typescript
import { useTracer } from '@/hooks/useTracer';

const { loaded: tracerLoaded } = useTracer();
```

`hooks/useTracer.ts` contains all the code for setting up instrumentation
including initializing a TracerProvider, establishing an OTLP export,
registering trace context propagators, and registering auto-instrumentation of
network requests.

```typescript
import {
CompositePropagator,
W3CBaggagePropagator,
W3CTraceContextPropagator,
} from '@opentelemetry/core';
import { WebTracerProvider } from '@opentelemetry/sdk-trace-web';
import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
import { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xml-http-request';
import { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch';
import { registerInstrumentations } from '@opentelemetry/instrumentation';
import { Resource } from '@opentelemetry/resources';
import {
ATTR_DEVICE_ID,
ATTR_OS_NAME,
ATTR_OS_VERSION,
ATTR_SERVICE_NAME,
ATTR_SERVICE_VERSION,
} from '@opentelemetry/semantic-conventions/incubating';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import getLocalhost from '@/utils/Localhost';
import { useEffect, useState } from 'react';
import {
getDeviceId,
getSystemVersion,
getVersion,
} from 'react-native-device-info';
import { Platform } from 'react-native';
import { SessionIdProcessor } from '@/utils/SessionIdProcessor';

const Tracer = async () => {
const localhost = await getLocalhost();

const resource = new Resource({
[ATTR_SERVICE_NAME]: 'react-native-app',
[ATTR_OS_NAME]: Platform.OS,
[ATTR_OS_VERSION]: getSystemVersion(),
[ATTR_SERVICE_VERSION]: getVersion(),
[ATTR_DEVICE_ID]: getDeviceId(),
});

const provider = new WebTracerProvider({
resource,
spanProcessors: [
new BatchSpanProcessor(
new OTLPTraceExporter({
url: `http://${localhost}:${process.env.EXPO_PUBLIC_FRONTEND_PROXY_PORT}/otlp-http/v1/traces`,
}),
{
scheduledDelayMillis: 500,
},
),
new SessionIdProcessor(),
],
});

provider.register({
propagator: new CompositePropagator({
propagators: [
new W3CBaggagePropagator(),
new W3CTraceContextPropagator(),
],
}),
});

registerInstrumentations({
instrumentations: [
// Some tiptoeing required here, propagateTraceHeaderCorsUrls is required to make the instrumentation
// work in the context of a mobile app even though we are not making CORS requests. `clearTimingResources` must
// be turned off to avoid using the web-only Performance API
new FetchInstrumentation({
propagateTraceHeaderCorsUrls: /.*/,
clearTimingResources: false,
}),

// The React Native implementation of fetch is simply a polyfill on top of XMLHttpRequest:
// https://github.com/facebook/react-native/blob/7ccc5934d0f341f9bc8157f18913a7b340f5db2d/packages/react-native/Libraries/Network/fetch.js#L17
// Because of this when making requests using `fetch` there will an additional span created for the underlying
// request made with XMLHttpRequest. Since in this demo calls to /api/ are made using fetch, turn off
// instrumentation for that path to avoid the extra spans.
new XMLHttpRequestInstrumentation({
ignoreUrls: [/\/api\/.*/],
}),
],
});
};

export interface TracerResult {
loaded: boolean;
}

export const useTracer = (): TracerResult => {
const [loaded, setLoaded] = useState<boolean>(false);

useEffect(() => {
if (!loaded) {
Tracer()
.catch(() => console.warn('failed to setup tracer'))
.finally(() => setLoaded(true));
}
}, [loaded]);

return {
loaded,
};
};
```
Loading