Skip to content

Commit

Permalink
feat(instrumentation-react-native-navigation) cleaning up solution + …
Browse files Browse the repository at this point in the history
…adding comments + renaming spanCreator file
  • Loading branch information
facostaembrace committed Aug 5, 2024
1 parent 8716b2a commit ab87452
Show file tree
Hide file tree
Showing 10 changed files with 130 additions and 116 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ As mentioned before, <NavigationTracker /> relies on `@react-native/navigation`
### Note

`useProvider` hook in this example returns an instance of a configured provided.
It doesn't matter which provider you choose; you just need to pass down one (if needed) with all your configurations. To create that provider, you may want to refer to the official [OpenTelemetry JS documentation](https://github.com/open-telemetry/opentelemetry-js). You can also review our suggested implementation (`experimental/testUtils/hooks/useProvider.ts`), but keep in mind that this is the simplest provider with minimal configurations.
It doesn't matter which provider you choose; you just need to pass down one (if needed) with all your configurations. To create that provider, you may want to refer to the official [OpenTelemetry JS documentation](https://github.com/open-telemetry/opentelemetry-js). You can also review our suggested implementation (`./test/hooks/useProvider.ts`), but keep in mind that this is the simplest provider with minimal configurations.

## Useful links

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import { forwardRef, ReactNode } from 'react';
import { TracerProvider } from '@opentelemetry/api';

import useTraceRef from '../utils/hooks/useTracerRef';
import useTracerRef from '../utils/hooks/useTracerRef';
import useNativeNavigationTracker, {
NativeNavRef,
} from '../hooks/useNativeNavigationTracker';
Expand All @@ -36,7 +36,7 @@ const NativeNavigationTracker = forwardRef<
NativeNavigationTrackerProps
>(({ children, provider, config }, ref) => {
// Initializing a Trace instance
const tracer = useTraceRef(provider, config);
const tracer = useTracerRef(provider, config);

useNativeNavigationTracker(ref, tracer, config);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import { forwardRef, ReactNode } from 'react';
import { TracerProvider } from '@opentelemetry/api';

import useTraceRef from '../utils/hooks/useTracerRef';
import useTracerRef from '../utils/hooks/useTracerRef';
import useNavigationTracker, { NavRef } from '../hooks/useNavigationTracker';
import { NavigationTrackerConfig } from '../types/navigation';

Expand All @@ -34,7 +34,7 @@ const NavigationTracker = forwardRef<
NavigationTrackerProps
>(({ children, provider, config }, ref) => {
// Initializing a Trace instance
const tracer = useTraceRef(provider, config);
const tracer = useTracerRef(provider, config);

useNavigationTracker(ref, tracer, config);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,40 @@
* limitations under the License.
*/
import { AppState, AppStateStatus } from 'react-native';
import { useEffect } from 'react';
import { MutableRefObject, useCallback, useEffect } from 'react';
import { spanCreatorAppState } from '../utils/spanFactory';
import { TracerRef } from '../utils/hooks/useTracerRef';
import { SpanRef } from '../utils/hooks/useSpanRef';
import { Attributes } from '@opentelemetry/api';

type CallbackFn = (currentState: AppStateStatus) => void;
const useAppStateListener = (
tracer: TracerRef,
span: SpanRef,
view: MutableRefObject<string | null>,
attributes?: Attributes
) => {
/**
* App State Span Factory
*/
const initAppStateSpan = useCallback(
(currentState: AppStateStatus) => {
const appStateHandler = spanCreatorAppState(tracer, span, attributes);

const useAppStateListener = (callback?: CallbackFn) => {
if (view?.current === null) {
return;
}

appStateHandler(view?.current, currentState);
},
[span, tracer, attributes]
);

/**
* App State Listener changes
*/
useEffect(() => {
const handleAppStateChange = (currentState: AppStateStatus) => {
callback?.(currentState);
initAppStateSpan(currentState);
};

const subscription = AppState.addEventListener(
Expand All @@ -32,7 +58,7 @@ const useAppStateListener = (callback?: CallbackFn) => {
return () => {
subscription.remove();
};
}, [callback]);
}, [initAppStateSpan]);
};

export default useAppStateListener;
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,9 @@
* limitations under the License.
*/

import { AppStateStatus } from 'react-native';
import { ForwardedRef, useCallback, useEffect, useMemo, useRef } from 'react';
import { ForwardedRef, useEffect, useMemo, useRef } from 'react';

import spanCreator, {
spanCreatorAppState,
spanEnd,
} from '../utils/spanCreator';
import { spanCreator, spanEnd } from '../utils/spanFactory';
import { TracerRef } from '../utils/hooks/useTracerRef';
import useSpanRef from '../utils/hooks/useSpanRef';
import {
Expand All @@ -38,19 +34,29 @@ const useNativeNavigationTracker = (
tracer: TracerRef,
config?: NavigationTrackerConfig
) => {
const { attributes: customAttributes, debug } = config ?? {};
const console = useConsole(!!debug);

const navigationElRef = useMemo(() => {
const isMutableRef = ref !== null && typeof ref !== 'function';
return isMutableRef ? ref.current : undefined;
}, [ref]);

const navView = useRef<string | null>(null);
const { attributes: customAttributes, debug } = config ?? {};
const console = useConsole(!!debug);

// Initializing a Span
const view = useRef<string | null>(null);
const span = useSpanRef();

/**
* Navigation Span Factory
*/
const initNativeNavigationSpan = useMemo(
() => spanCreator(tracer, span, view, customAttributes),
[customAttributes]
);

/**
* Registering the componentDidAppear and componentDidDisappear listeners
* to start and end spans depending on the navigation lifecycle
*/
useEffect(() => {
if (!navigationElRef) {
console.warn(
Expand All @@ -71,7 +77,7 @@ const useNativeNavigationTracker = (
return;
}

spanCreator(tracer, span, navView, componentName, customAttributes);
initNativeNavigationSpan(componentName);
});

navigationElRef.registerComponentDidDisappearListener(
Expand All @@ -88,35 +94,23 @@ const useNativeNavigationTracker = (
spanEnd(span);
}
);
}, [navigationElRef, span, tracer, customAttributes]);
}, [navigationElRef, span, initNativeNavigationSpan]);

/**
* Start and end spans depending on the app state changes
*/
useAppStateListener(tracer, span, view, customAttributes);

/**
* Ending the final span depending on the app lifecycle
*/
useEffect(
() => () => {
// making sure the final span is ended when the app is unmounted
const isFinalView = true;
spanEnd(span, undefined, isFinalView);
spanEnd(span, undefined, true);
},
[span]
);

const handleAppStateListener = useCallback(
(currentState: AppStateStatus) => {
const appStateHandler = spanCreatorAppState(
tracer,
span,
customAttributes
);

if (navView?.current === null) {
return;
}

appStateHandler(navView?.current, currentState);
},
[span, tracer, customAttributes]
);

useAppStateListener(handleAppStateListener);
};

export default useNativeNavigationTracker;
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,9 @@
* limitations under the License.
*/

import { AppStateStatus } from 'react-native';
import { ForwardedRef, useCallback, useEffect, useMemo, useRef } from 'react';
import { ForwardedRef, useEffect, useMemo, useRef } from 'react';

import spanCreator, {
spanCreatorAppState,
spanEnd,
} from '../utils/spanCreator';
import { spanCreator, spanEnd } from '../utils/spanFactory';
import { TracerRef } from '../utils/hooks/useTracerRef';
import useSpanRef from '../utils/hooks/useSpanRef';
import {
Expand All @@ -38,20 +34,29 @@ const useNavigationTracker = (
tracer: TracerRef,
config?: NavigationTrackerConfig
) => {
const { attributes: customAttributes, debug } = config ?? {};
const console = useConsole(!!debug);

const navigationElRef = useMemo(() => {
const isMutableRef = ref !== null && typeof ref !== 'function';
return isMutableRef ? ref.current : undefined;
}, [ref]);

// tracking specific (no otel related)
const navView = useRef<string | null>(null);
const { attributes: customAttributes, debug } = config ?? {};
const console = useConsole(!!debug);

// Initializing a Span
const span = useSpanRef();
const view = useRef<string | null>(null);

/**
* Native Navigation Span Factory
*/
const initNavigationSpan = useMemo(
() => spanCreator(tracer, span, view, customAttributes),
[customAttributes]
);

/**
* Registering the Navigation 'state' Listener
* to start and end spans depending on the navigation lifecycle
*/
useEffect(() => {
if (!navigationElRef) {
console.warn(
Expand All @@ -74,38 +79,26 @@ const useNavigationTracker = (
return;
}

spanCreator(tracer, span, navView, routeName, customAttributes);
initNavigationSpan(routeName);
});
}
}, [navigationElRef, span, tracer, customAttributes]);
}, [navigationElRef, initNavigationSpan]);

/**
* Start and end spans depending on the app state changes
*/
useAppStateListener(tracer, span, view, customAttributes);

/**
* Ending the final span depending on the app lifecycle
*/
useEffect(
() => () => {
// making sure the final span is ended when the app is unmounted
const isFinalView = true;
spanEnd(span, undefined, isFinalView);
spanEnd(span, undefined, true);
},
[span]
);

const handleAppStateListener = useCallback(
(currentState: AppStateStatus) => {
const appStateHandler = spanCreatorAppState(
tracer,
span,
customAttributes
);

if (navView?.current === null) {
return;
}

appStateHandler(navView?.current, currentState);
},
[span, tracer, customAttributes]
);

useAppStateListener(handleAppStateListener);
};

export default useNavigationTracker;
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ const useTracerRef = (
const tracerRef = useRef<Tracer | null>(null);
const console = useConsole(!!debug);

// using the layout effect to make sure the tracer is initialized before the component is rendered
useEffect(() => {
if (tracerRef.current === null) {
if (!provider) {
Expand Down
Loading

0 comments on commit ab87452

Please sign in to comment.