Skip to content

Commit 751d1c9

Browse files
committed
feat!: deintegrate interop layer for OTEL to a separate package
1 parent 1c66df4 commit 751d1c9

File tree

113 files changed

+2409
-1525
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

113 files changed

+2409
-1525
lines changed

docs/docs/docs/core/contributing.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ TODO: write this section.
99
To start developing, first clone the repository:
1010

1111
```bash
12-
git clone https://github.com/callstackincubator/ReactNativeOttrelite
12+
git clone https://github.com/callstackincubator/ottrelite
1313
```
1414

1515
Then, install the dependencies & generate the glue code using Nitro Modules:
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[
2+
{
3+
"type": "file",
4+
"name": "quick-start.mdx",
5+
"label": "Quick Start"
6+
}
7+
]
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# Ottrelite interoperability package with OTEL
2+
3+
### OTEL interoperability
4+
5+
Ottrelite provides interoperability with OpenTelemetry (OTEL) through a set of adapter facilities.
6+
7+
#### Javascript
8+
9+
Firstly, Ottrelite provides its own `TracerProvider` ([`OttreliteTracerProvider.ts`](./src/otel/OttreliteTracerProvider.ts)) that provides adequate configuration for JS (configures the default resource to carry ottrelite's metadata, registers W3C & trace context baggage propagators, by default - `StackContextManager`). Invoking `register` on it, apart from the aforementioned, also calls invokes configuration of the global C++ API provider, described in the section below.
10+
11+
The analogous applies to [`OttreliteMeterProvider`](src/otel/OttreliteMeterProvider.ts). An implementation detail difference is that the meter provider hooks into returned instrument creation methods & their return values dynamically by replacing properties on instances, to call its own logic before the original is executed.
12+
13+
The OTEL API is also hooked into by the [`DevSpanProcessorInterceptor.ts`](src/otel/processor/DevSpanProcessorInterceptor.ts), which can be registered to propagate all OTEL spans live to the [Development API](../../README.md#development-api).
14+
15+
#### C++
16+
17+
##### Usage
18+
19+
The global C++ Tracer and Meter Providers are registered - respectively - from `installGlobalOTELCPPTracerProvider` and `installGlobalOTELCPPMeterProvider` Nitro Module methods. Calling each of those makes sense **only once**. At the first call, the Ottrelite tracer/meter exporters that have been instantiated and registered in JavaScript so far, will also be registered in the C++ API. This is the single-implementation, single-configuration approach that Ottrelite follows: create & configure all tracer/meter exporters in JS, use them from JS, C++, Kotlin/Java & Swift code.
20+
21+
> [!WARNING]
22+
> Invoking the aforementioned install methods more than once will discard all previously registered C++ tracer/meter exporters. It is important to first register all the tracer/meter exporters in JS, and then call the `register()` methods of `OttreliteTracerProvider` and `OttreliteMeterProvider` in JS.
23+
24+
##### Configuration
25+
26+
The `Ottrelite.install` method accepts 3 C++ OTEL SDK - specific configuration options:
27+
28+
1. `cppBatchLogRecordProcessorOptions` - options for the `opentelemetry::sdk::logs::BatchLogRecordProcessorFactory`
29+
2. `cppMetricReaderOptions` - options for the `opentelemetry::sdk::metrics::PeriodicExportingMetricReaderFactory`
30+
3. `cppTraceBatchSpanProcessorOptions` - options for the `opentelemetry::sdk::trace::opentelemetry::sdk::trace::BatchSpanProcessorFactory`
31+
32+
Those can only be passed once and will be used to configure the C++ OTEL SDK, which is the data sink for OTEL traces from all interoperability layers in all languages. However, those options will only affect the C++ data export - other languages will process, report & provide the spans according to their own setup.
33+
34+
##### Implementing a custom exporter
35+
36+
To implement a custom exporter, first create a C++ Nitro Module spec:
37+
38+
```typescript
39+
// in MyOttreliteExporter.nitro.ts
40+
import type { OttreliteExporter } from '@ottrelite/core';
41+
42+
export interface MyOttreliteExporter
43+
extends HybridObject<{ ios: 'c++'; android: 'c++' }>,
44+
OttreliteExporter {}
45+
```
46+
47+
After codegen-ing the C++ glue code from this spec, implement the exporter in C++. The primary methods that are crucial for the implementation are:
48+
49+
- `void initExporter(const OTLPExporterConfig &config);`
50+
- `void exportSpans(const std::vector<SerializedReadableSpan> &spans, const std::function<void(const ExportResult & /* result */)> &resultCallback);`
51+
- `std::shared_ptr<Promise<void>> shutdown();`
52+
- `std::shared_ptr<Promise<void>> forceFlush();`
53+
54+
Those methods are standard for OTEL exporters in according to its specification, yet the methods accept internal Ottrelite object types.
55+
56+
The `OTLPExporterConfig` is Nitro-codegened from [`OTLPExporterConfig.ts`](src/types/OTLPExporterConfig.ts) and represents the most important JS configuration for exporters in general. If some more configuration levels are needed to be covered, please file a PR or issue.
57+
58+
The `ExportResult` is trivial and is a 1:1 CPP-JS mapping of the result type.
59+
60+
The `SerializedReadableSpan` is a representation of a span in JS. Due to some limitations of Nitro, the object currently is not possible to be passed to CPP 1:1, however the overhead of conversion is minimal: some properties are only cast as types, while some need to be remapped:
61+
62+
- due to Nitro codegen problems with recursive type references, some methods need to be masked & some types require aliases
63+
- all `SpanContext` objects are serialized to a string using built-in JS OTEL functionality, which is then parsed on the C++ side using built-in C++ OTEL functionality
64+
65+
For conversion of `SerializedReadableSpan`s to C++ OTEL vector of `Recordable`s, the `::ottrelite::interop::otel::SpanConverter::convertSpans(spans, resourcesMemory)` from `SpanConverter.hpp` can be used:
66+
67+
```cpp
68+
#include "SpanConverter.hpp"
69+
70+
// ...
71+
72+
// converted Resource-s must be kept in memory for the time of export
73+
::ottrelite::interop::otel::ResourcesMemory resourcesMemory{};
74+
75+
auto recordables = ::ottrelite::interop::otel::SpanConverter::convertSpans(spans, resourcesMemory);
76+
77+
// create a span view for the exporter
78+
opentelemetry::nostd::span<std::unique_ptr<opentelemetry::sdk::trace::Recordable>> spanView(
79+
recordables.data(), recordables.size());
80+
81+
// example: call the exporter's Export method
82+
auto otelResult = otelExporterPtr->Export(spanView);
83+
```
84+
85+
More hollistically, a vector of `SerializedReadableSpan` can be converted & exported on an exporter instance using
86+
87+
```cpp
88+
#include "SpanConverter.hpp" // required for ResourcesMemory alias
89+
#include "OTELExporterAdapterUtils.hpp"
90+
91+
// ...
92+
93+
// converted Resource-s must be kept in memory for the time of export
94+
::ottrelite::interop::otel::ResourcesMemory resourcesMemory{};
95+
96+
resultCallback(::ottrelite::interop::otel::OTELExporterAdapterUtils::exportInternalSpansReprsViaOTEL(
97+
resourcesMemory, spans, otlpExporterPtr_));
98+
```
99+
100+
#### Android
101+
102+
TODO: write this section
103+
104+
#### iOS
105+
106+
TODO: write this section

docs/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"private": true,
55
"scripts": {
66
"build:docs": "rspress build",
7-
"check": "biome check --write",
7+
"lint": "biome check",
88
"dev": "rspress dev",
99
"format": "biome format --write",
1010
"preview": "rspress preview"

docs/rspress.config.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,30 @@ export default defineConfig({
3333
pluginTypeDoc({
3434
entryPoints: [
3535
path.join(__dirname, '..', 'packages', 'core', 'src', 'index.ts'),
36+
path.join(
37+
__dirname,
38+
'..',
39+
'packages',
40+
'backend-wrapper-tracy',
41+
'src',
42+
'index.ts'
43+
),
44+
path.join(
45+
__dirname,
46+
'..',
47+
'packages',
48+
'backend-platform',
49+
'src',
50+
'index.ts'
51+
),
52+
path.join(
53+
__dirname,
54+
'..',
55+
'packages',
56+
'interop-otel',
57+
'src',
58+
'index.ts'
59+
),
3660
],
3761
outDir: 'api',
3862
}),

docs/tsconfig.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,14 @@
1313
"useDefineForClassFields": true,
1414
"allowImportingTsExtensions": true
1515
},
16-
"include": ["docs", "rspress.config.ts", "../packages/core/src/"],
16+
"include": [
17+
"docs",
18+
"rspress.config.ts",
19+
"../packages/core/src/",
20+
"../packages/backend-wrapper-tracy/src/",
21+
"../packages/backend-platform/src/",
22+
"../packages/interop-otel/src/"
23+
],
1724
"mdx": {
1825
"checkMdx": true
1926
}

examples/ottrelite-consumer-lib/NitroOttreliteConsumerLib.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Pod::Spec.new do |s|
1111
s.authors = package["author"]
1212

1313
s.platforms = { :ios => min_ios_version_supported, :visionos => 1.0 }
14-
s.source = { :git => "https://github.com/mrousavy/nitro.git", :tag => "#{s.version}" }
14+
s.source = { :git => "https://github.com/mrousavy/nitro.git" }
1515

1616
s.source_files = [
1717
# Implementation (Swift)

examples/ottrelite-consumer-lib/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@
1010
"source": "src/index",
1111
"author": "Callstack <[email protected]>",
1212
"license": "MIT",
13-
"homepage": "https://github.com/callstackincubator/ReactNativeOttrelite#readme",
13+
"homepage": "https://github.com/callstackincubator/ottrelite#readme",
1414
"scripts": {
1515
"build": "nitro-codegen --logLevel=\"debug\" && pnpm run typescript",
1616
"clean": "rm -rf android/build node_modules/**/android/build lib",
1717
"lint": "eslint \"**/*.{js,ts,tsx}\" --fix",
1818
"lint-ci": "eslint \"**/*.{js,ts,tsx}\" -f @jamesacarr/github-actions",
19-
"postinstall": "pnpm run typescript || exit 0;",
19+
"postinstall": "pnpm run build || exit 0;",
2020
"typecheck": "tsc --noEmit",
2121
"typescript": "tsc"
2222
},

examples/rn-app/ios/Podfile.lock

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2500,6 +2500,7 @@ PODS:
25002500
- RCT-Folly/Fabric
25012501
- RCTRequired
25022502
- RCTTypeSafety
2503+
- React-callinvoker
25032504
- React-Core
25042505
- React-debug
25052506
- React-Fabric
@@ -2515,11 +2516,9 @@ PODS:
25152516
- ReactCodegen
25162517
- ReactCommon/turbomodule/bridging
25172518
- ReactCommon/turbomodule/core
2518-
- ReactNativeOttrelite/ottrelite-core (= 0.1.0)
2519-
- ReactNativeOttrelite/ottrelite-otel-wrapper (= 0.1.0)
25202519
- SocketRocket
25212520
- Yoga
2522-
- ReactNativeOttrelite/ottrelite-core (0.1.0):
2521+
- ReactNativeOttreliteBackendPlatform (0.1.0):
25232522
- boost
25242523
- DoubleConversion
25252524
- fast_float
@@ -2547,9 +2546,10 @@ PODS:
25472546
- ReactCodegen
25482547
- ReactCommon/turbomodule/bridging
25492548
- ReactCommon/turbomodule/core
2549+
- ReactNativeOttrelite
25502550
- SocketRocket
25512551
- Yoga
2552-
- ReactNativeOttrelite/ottrelite-otel-wrapper (0.1.0):
2552+
- ReactNativeOttreliteBackendTracy (0.1.0):
25532553
- boost
25542554
- DoubleConversion
25552555
- fast_float
@@ -2561,6 +2561,7 @@ PODS:
25612561
- RCT-Folly/Fabric
25622562
- RCTRequired
25632563
- RCTTypeSafety
2564+
- React-callinvoker
25642565
- React-Core
25652566
- React-debug
25662567
- React-Fabric
@@ -2576,9 +2577,10 @@ PODS:
25762577
- ReactCodegen
25772578
- ReactCommon/turbomodule/bridging
25782579
- ReactCommon/turbomodule/core
2580+
- ReactNativeOttrelite
25792581
- SocketRocket
25802582
- Yoga
2581-
- ReactNativeOttreliteBackendPlatform (0.1.0):
2583+
- ReactNativeOttreliteInteropOTEL (0.1.0):
25822584
- boost
25832585
- DoubleConversion
25842586
- fast_float
@@ -2590,7 +2592,6 @@ PODS:
25902592
- RCT-Folly/Fabric
25912593
- RCTRequired
25922594
- RCTTypeSafety
2593-
- React-callinvoker
25942595
- React-Core
25952596
- React-debug
25962597
- React-Fabric
@@ -2606,10 +2607,11 @@ PODS:
26062607
- ReactCodegen
26072608
- ReactCommon/turbomodule/bridging
26082609
- ReactCommon/turbomodule/core
2609-
- ReactNativeOttrelite
2610+
- ReactNativeOttreliteInteropOTEL/ottrelite-core (= 0.1.0)
2611+
- ReactNativeOttreliteInteropOTEL/ottrelite-otel-wrapper (= 0.1.0)
26102612
- SocketRocket
26112613
- Yoga
2612-
- ReactNativeOttreliteBackendTracy (0.1.0):
2614+
- ReactNativeOttreliteInteropOTEL/ottrelite-core (0.1.0):
26132615
- boost
26142616
- DoubleConversion
26152617
- fast_float
@@ -2637,7 +2639,35 @@ PODS:
26372639
- ReactCodegen
26382640
- ReactCommon/turbomodule/bridging
26392641
- ReactCommon/turbomodule/core
2640-
- ReactNativeOttrelite
2642+
- SocketRocket
2643+
- Yoga
2644+
- ReactNativeOttreliteInteropOTEL/ottrelite-otel-wrapper (0.1.0):
2645+
- boost
2646+
- DoubleConversion
2647+
- fast_float
2648+
- fmt
2649+
- glog
2650+
- hermes-engine
2651+
- NitroModules
2652+
- RCT-Folly
2653+
- RCT-Folly/Fabric
2654+
- RCTRequired
2655+
- RCTTypeSafety
2656+
- React-Core
2657+
- React-debug
2658+
- React-Fabric
2659+
- React-featureflags
2660+
- React-graphics
2661+
- React-ImageManager
2662+
- React-jsi
2663+
- React-NativeModulesApple
2664+
- React-RCTFabric
2665+
- React-renderercss
2666+
- React-rendererdebug
2667+
- React-utils
2668+
- ReactCodegen
2669+
- ReactCommon/turbomodule/bridging
2670+
- ReactCommon/turbomodule/core
26412671
- SocketRocket
26422672
- Yoga
26432673
- RNDeviceInfo (14.0.4):
@@ -2786,6 +2816,7 @@ DEPENDENCIES:
27862816
- "ReactNativeOttrelite (from `../node_modules/@ottrelite/core`)"
27872817
- "ReactNativeOttreliteBackendPlatform (from `../node_modules/@ottrelite/backend-platform`)"
27882818
- "ReactNativeOttreliteBackendTracy (from `../node_modules/@ottrelite/backend-wrapper-tracy`)"
2819+
- "ReactNativeOttreliteInteropOTEL (from `../node_modules/@ottrelite/interop-otel`)"
27892820
- RNDeviceInfo (from `../../../node_modules/react-native-device-info`)
27902821
- RNScreens (from `../../../node_modules/react-native-screens`)
27912822
- SocketRocket (~> 0.7.1)
@@ -2958,6 +2989,8 @@ EXTERNAL SOURCES:
29582989
:path: "../node_modules/@ottrelite/backend-platform"
29592990
ReactNativeOttreliteBackendTracy:
29602991
:path: "../node_modules/@ottrelite/backend-wrapper-tracy"
2992+
ReactNativeOttreliteInteropOTEL:
2993+
:path: "../node_modules/@ottrelite/interop-otel"
29612994
RNDeviceInfo:
29622995
:path: "../../../node_modules/react-native-device-info"
29632996
RNScreens:
@@ -2975,7 +3008,7 @@ SPEC CHECKSUMS:
29753008
hermes-engine: e7491a2038f2618c8cd444ed411a6deb350a3742
29763009
LicensePlist: 5a4ff2e9e038a1203cc058b6335d2eebd3313491
29773010
NitroModules: 33aca4acd8fd5c2a29dc99976680cd99e7263573
2978-
NitroOttreliteConsumerLib: 8d235770d292bc6e9b2e34395b69aef800b05a36
3011+
NitroOttreliteConsumerLib: 2f1860e73bdf3f1aaa185241406a095e8291d811
29793012
RCT-Folly: 846fda9475e61ec7bcbf8a3fe81edfcaeb090669
29803013
RCTDeprecation: 0735ab4f6b3ec93a7f98187b5da74d7916e2cf4c
29813014
RCTRequired: 8fcc7801bfc433072287b0f24a662e2816e89d0c
@@ -3044,9 +3077,10 @@ SPEC CHECKSUMS:
30443077
ReactCodegen: 8125d6ee06ea06f48f156cbddec5c2ca576d62e6
30453078
ReactCommon: 116d6ee71679243698620d8cd9a9042541e44aa6
30463079
ReactNativeLegal: 245741f8e5c1074632334ed3855f046366482a5a
3047-
ReactNativeOttrelite: 4a0b15ce03516d14d94930654f458edfe6b38a4e
3048-
ReactNativeOttreliteBackendPlatform: bb9ccfb30615b7efc3123911767d477dae08c020
3049-
ReactNativeOttreliteBackendTracy: 9e579733eef5b8a152815dd87e3f0974189cdaab
3080+
ReactNativeOttrelite: 8a38e46c9492df1473f5e1d853fd56e1ad239bfe
3081+
ReactNativeOttreliteBackendPlatform: fba8c4dbea090d01d6e24cb39c239effae52fff5
3082+
ReactNativeOttreliteBackendTracy: b7bb5b016abd2ea9a0c442d9c3d6996fa4fd4a17
3083+
ReactNativeOttreliteInteropOTEL: 12ffbcfa0ba04ad891efda1c7efacab537c114fd
30503084
RNDeviceInfo: d863506092aef7e7af3a1c350c913d867d795047
30513085
RNScreens: 40264381e0eca3f0c368c78f192f547ef40caa39
30523086
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748

examples/rn-app/ios/license_plist.yml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ rename:
2727
"@[email protected]": '@ottrelite/backend-platform'
2828
"@[email protected]": '@ottrelite/backend-wrapper-tracy'
2929
"@[email protected]": '@ottrelite/core'
30+
"@[email protected]": '@ottrelite/interop-otel'
3031
"@[email protected]": '@opentelemetry/sdk-metrics'
3132
"@[email protected]": '@react-native-community/slider'
3233
"@[email protected]": '@react-native-vector-icons/material-design-icons'
@@ -526,16 +527,20 @@ manual:
526527
file: '../../../node_modules/@opentelemetry/instrumentation-xml-http-request/LICENSE'
527528
- name: '@[email protected]'
528529
version: '0.1.0'
529-
source: https://github.com/callstackincubator/ReactNativeOttrelite
530+
source: https://github.com/callstackincubator/ottrelite
530531
file: '../../../packages/backend-platform/LICENSE'
531532
- name: '@[email protected]'
532533
version: '0.1.0'
533-
source: https://github.com/callstackincubator/ReactNativeOttrelite
534+
source: https://github.com/callstackincubator/ottrelite
534535
file: '../../../packages/backend-wrapper-tracy/LICENSE'
535536
- name: '@[email protected]'
536537
version: '0.1.0'
537-
source: https://github.com/callstackincubator/ReactNativeOttrelite
538+
source: https://github.com/callstackincubator/ottrelite
538539
file: '../../../packages/core/LICENSE'
540+
- name: '@[email protected]'
541+
version: '0.1.0'
542+
source: https://github.com/callstackincubator/ottrelite
543+
file: '../../../packages/interop-otel/LICENSE'
539544
- name: '@[email protected]'
540545
version: '2.0.1'
541546
source: open-telemetry/opentelemetry-js
@@ -1941,7 +1946,7 @@ manual:
19411946
19421947
version: '12.1.0'
19431948
source: https://github.com/tj/commander.js
1944-
file: '../../../node_modules/commander/LICENSE'
1949+
file: '../../../node_modules/react-native/node_modules/commander/LICENSE'
19451950
19461951
version: '29.7.0'
19471952
source: https://github.com/jestjs/jest

0 commit comments

Comments
 (0)