Implementasi Sentry Performance Tracking React Native
By Onotrak [apadevteam]

Implementasi Sentry Performance React Native

 

Pengantar

Dokumen ini dibuat untuk mengatasi permasalahan ketika setelah implementasi sentry selesai namun pada sentry performance page / screen tidak terlacak di bagian tersebut. Dokumen ini dibuat khusus untuk React Native yang menggunakan React Navigation versi berapapun. Tidak menutup kemungkinan, dokumen ini juga dapat digunakan untuk referensi seumpama menggunakan React Router atau pun package routing lainya.

 

Kasus

Beberapa kasus yang terjadi disaat implementasi Sentry adalah bagian Sentry Performance yang dimana Screen / Page tidak terdeteksi ketika kita berpindah dari screen satu ke screen lain. 

Gambar Sentry Performance Belum Diimplementasi. Gambar Sentry Performance Sudah Diimplementasi dan Tidak Terlacak.

 

Permasalahan

Permasalahan yang kami temukan disini adalah di beberapa Versi React Navigation memiliki function yang berbeda, disini kami beri contoh implementasi pada React Navigation Versi 4.x dan 5.x.

  • React Navigation v5.x

Pada react navigation v5.x penggunaan function untuk mendeteksi Current Screen cukup mudah, dimana kita hanya mengambil Nama dari current screen dengan menggunakan navigationRef.current.getCurrentRoute().name lalu memasukannya kedalam sentry Instrumentation. Contoh sebagain berikut:

...

import * as Sentry from "@sentry/react-native";

const routingInstrumentation = new Sentry.ReactNavigationV5Instrumentation(); //← V5 pada bagian berikut adalah untuk react navigation versi 5

Sentry.init({

 ...

 sampleRate: 1.0, //← Sample Rate 1.0 = 100% pelacakan untuk performance

 integrations: [

   new Sentry.ReactNativeTracing({

     ...

     routingInstrumentation, //← Memasukan data Current Screen kedalam Sentry  

   })

 ],

});

export default function Routing() {

  const navigationRef = useRef();

  const routeNameRef = useRef();

  const onNavigatorContainerStateChange = () => {

    try {

      const currentRouteName = navigationRef?.current?.getCurrentRoute() === undefined ? 

                              '' : navigationRef.current.getCurrentRoute().name;

      routeNameRef.current = currentRouteName;

      routingInstrumentation.onRouteWillChange({

        name: currentRouteName,

        op: 'navigation'

      });

      console.log('onotrak route change' , currentRouteName);

    } catch (err) {

      console.log('onotrak [err] navigator container state change', err);

    }

  };

  const onNavigatorReady = () => {

    console.log('onotrak navigationRef', navigationRef);

    try {

      routeNameRef.current = navigationRef.current.getCurrentRoute().name;

      routingInstrumentation.registerNavigationContainer(navigationRef);

    } catch (err) {

      console.log('onotrak [err] navigator on ready', err);

    }

  };

  return (

  <NavigationContainer

    ref={navigationRef}

    onStateChange={onNavigatorContainerStateChange}

    onReady={() => {

       onNavigatorReady();

    }}

  >

  <Stack.Navigator screenOptions={{headerShown: false}}>

    <Stack.Screen...

File RouteNavigation.js react navigation versi 5.x

Pada Cuplikan Code diatas kita pertama menentukan Versi React Navigation yang telah di install di project masing-masing. Jika menggunakan React Navigation Versi 5, maka kita menggunakan Sentry.ReactNavigationV5Instrumentation(). Setelah itu kita gunakan pada Sentry.ReactNativeTracing(). 

Pada bagian NavigationContainer di atribut  onStateChange,  kita membuat function onNavigatorContainerStateChange yang digunakan untuk mendeteksi Current Screen pada Routing

Gambar console log "navigationRef.current.getCurrentRoute()" 

Pada gambar diatas, kami mencoba melihat isi object dari navigationRef.current.getCurrentRoute()) yang digunakan untuk mengambil Current Screen ketika atribut onStateChange={} terpanggil. Setelah mendapatkan nama dari Current Screen maka kita memasukanya ke atribut name  kedalam object routingInstrumentation.onRouteWillChange({}).

Pada bagian NavigationContainer di atribut onReady={()=> {}}, kita membuat function onNavigatorReady(). yang akan digunakan untuk mendaftarkan atribut  ke Sentry dengan menggunakan routingInstrumentation.registerNavigationContainer(navigationRef).

Gambar console log navigationRef
  • React Navigation v4.x

Pada react navigation v4.x penggunaan function untuk mendeteksi Current Screen cukup jauh berbeda dengan implementasi di React Navigation v5.x. dimana kita perlu membuat function sendiri untuk mengambil Nama dari Current Screen

...

import React, { useRef } from 'react';

import * as Sentry from "@sentry/react-native";

const routingInstrumentation = new Sentry.ReactNavigationV4Instrumentation(); //← V4 pada bagian berikut adalah untuk react navigation versi 4

Sentry.init({

 ...

 sampleRate: 1.0, //← Sample Rate 1.0 = 100% pelacakan untuk performance

 integrations: [

   new Sentry.ReactNativeTracing({

     ...

     routingInstrumentation, //← Memasukan data Current Screen kedalam Sentry  

   })

 ],

});

...

const Routing() {

  const navigationRef = useRef();

  const onNavigatorContainerStateChange = (currentScreen) => {

    console.log('onotrak navigationRef', navigationRef);

    try {

      routingInstrumentation.onRouteWillChange({

        name: currentScreen,

        op: 'navigation'

      });

      console.log('onotrak route change' , currentScreen);

    } catch (err) {

      console.log('onotrak [err] navigator container state change', err);

    }

  };

  const getCurrentRouteName = (navigationState) => {

    if (!navigationState) {

      return null;

    }

    const route = navigationState.routes[navigationState.index];

    console.log('onotrak route', route);

    if (route.routes) {

      return getCurrentRouteName(route);

    }

    return route.routeName;

  };

  return (

  <Provider store={store} uriPrefix={prefix}>

    <NavigationContainer

      ref={navigationRef}

      onNavigationStateChange={(currentState) => {

        console.log('onotrak currentState', currentState);

        const currentScreen = getCurrentRouteName(currentState);

        if (currentScreen) {

          onNavigatorContainerStateChange(currentScreen);

        }

      }}

    />

  </Provider>

...

File RouteNavigation.js react navigation versi 4.x

Pada Cuplikan Code diatas kita pertama menentukan Versi React Navigation yang telah di install di project masing-masing. Jika menggunakan React Navigation Versi 4, maka kita menggunakan Sentry.ReactNavigationV4Instrumentation(). Setelah itu kita gunakan pada Sentry.ReactNativeTracing(). 

Pada bagian NavigationContainer di atribut  onNavigationStateChange={(currentState) => {}} kita membawa parameter untuk mengetahui current state current route.

Gambar console log currentState 

Seperti pada gambat diatas, kami membuat log pada atribut onNavigationStateChange dimana lokasi saat ini adalah di Screen Login maka pada index di dalam currentState adalah index ke-0 sama berdasarkan array routes.

Setelah mengetahui routes pada onNavigationStateChange, selanjutnya kita membuat dua buah function

Gambar function getCurrentRouteName().

Yang pertama adalah  getCurrentRouteName() yang digunakan untuk mendeteksi Current Screen pada Routing. Pada function ini, kita membuat looping dengan maksud mengetahui child routes / screen terdalam dari nested array routesyang ada seperti pada gambar. Dengan membawa currentState yang diambil dari onNavigationStateChange kita dapat mengetahui routes  yang terdapat pada project kita. Setelah memiliki data dari currentState, selanjutnya kita mengambil object array yang ada di dalam routes tersebut dengan membawa data index yang diambil dari currentState.index. Namun karena data tersebut berupa Nested Array, jadi kita perlu looping data route tersebut dengan membuat kondisi dimana jika di dalam object array masih memiliki object routes, maka kita mengulai pengambilan data tersebut sampai menemukan child atau routes terdalam. 

Gambar Nested Array dari Routes.

Setelah kita menemukan child dari nested array tersebut, kita me-return data nya dengan mengambil atribut routeName. Pada gambar diatas diketahui dimana Deep Child nya adalah screen AppraisalList. Dengan begitu, function diatas akan mengembelikan data berupa nama dari routes terdalam atau routes yang saat ini sedang digunakan oleh user.

Pertanyaainya Mengapa Kita perlu Ribet Hanya Untuk Mengambil Data Deep Child Pada React Navigation Versi 4?

Jadi seperti yang kami katakan dari awal, terdapat perbedaan dalam pengambilan data di React Navigation Versi 4 dan di React Navigation Versi 5, perhatikan gambar berikut:

Gambar console log navigationRef Versi 5.x

Pada gambar pertama diatas ini adalah console log dari react navigation versi 5 yang dimana memiliki atribut bernama getCurrentRoute()yang digunakan untuk mengambil nama route / screen yang sedang ditampilkan saat ini dengan mengambil navigationRef.current.getCurrentRoute().name

Sedangkan pada gambar kedua diatas ini adalah console log di react navigation versi 4. Dan dapat kita ketahui, atribut bernama getCurrentRoute() tidak ada. 

Selanjutnya kita kembali lagi ke awal. Saat implementasi awal tadi kita membuat 2 buah function yang dimana fucntion yang kedua tidak jauh berbeda dengan yang diimplementasi di react navigation versi 5. Function tersebut adalahonNavigatorContainerStateChange disini perbedaanya adalah ketika di react navigation versi 5 kita mengambil data dari navigationRef.current.getCurrentRoute().name namun di react navigation versi 4 ini, kita mengambilnya dari function getCurrentRouteName() yang pertama kita buat tadi, sehingga kita dapat langsung membawanya setelah function getCurrentRouteName() me-return data.

 

Kesimpulan

Jadi kesimpulan dari Dokumen / Artikel ini adalah apapun yang digunakan untuk Routing di dalam project kita, menggunakan React Navigation atau menggunakan React Router, yang paling utama adalah bagaimana agar kita dapat mencari / mendeteksi Current Screen pada saat aplikasi digunakan dan mengirimkanya ke Sentry. Secara keseluruhan untuk flow nya tidak jauh beda, hanya saja cara yang di gunakan di setiap package 
mungkin memiliki cara yang berbeda antara satu dan lainya.

 

Penutup

Mohon maaf bila ada salah kata atau penulisan maupun salah dalam menjelaskan. Karena ini aktikel pertama saya, jadi saya meminta maaf sebesar-besarnya bagi para pembaca.🙏 
Sekian dan terimakasih!

Created by: onotrak



Dont work only focus on getting Money
By Agung Riyanto [apadevteam]