Skip to content

Commit 917d572

Browse files
author
deepakglobant
committed
feat: set user in Sentry and added custom measurement
1 parent fe5762d commit 917d572

File tree

8 files changed

+189
-160
lines changed

8 files changed

+189
-160
lines changed

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,10 @@
4949
"@react-navigation/native": "^6.0.10",
5050
"@react-navigation/native-stack": "^6.6.1",
5151
"@reduxjs/toolkit": "^1.8.1",
52-
"@sentry/react": "^6.19.6",
52+
"@sentry/browser": "^7.36.0",
53+
"@sentry/react": "^7.36.0",
5354
"@sentry/react-native": "^4.13.0",
54-
"@sentry/tracing": "^6.19.7",
55+
"@sentry/tracing": "^7.36.0",
5556
"axios": "^0.26.1",
5657
"expo": "^44.0.6",
5758
"expo-application": "~4.0.1",
Lines changed: 76 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,71 @@
1-
import * as SentryR from '@sentry/react';
2-
import * as Sentry from 'sentry-expo';
3-
import React, { createContext, useCallback, useContext, useEffect, useMemo } from 'react';
4-
import { CaptureConsole } from '@sentry/integrations';
5-
import { Integrations } from '@sentry/tracing';
1+
import * as Sentry from '@sentry/browser';
2+
import { BrowserTracing } from '@sentry/tracing';
3+
import React, { createContext, PropsWithChildren, useCallback, useContext, useEffect, useMemo } from 'react';
64
import { Primitive } from '@sentry/types';
7-
import { Platform } from 'react-native';
85

9-
import { MonitoringConfigType, MonitoringContextType, SentryTransactionStatus } from './types';
6+
import { MonitoringContext, MonitoringProps, SentryTransactionStatus } from './types';
107

118
export * from './types';
129

13-
const platform = Platform.select({
14-
web: Sentry.Browser,
15-
native: Sentry.Browser,
16-
});
17-
18-
/**
19-
* Set key:value that will be sent as tags data with the event.
20-
*
21-
* Can also be used to unset a tag, by passing `undefined`.
22-
*
23-
* @param key String key of tag
24-
* @param value Value of tag
25-
*/
26-
export function setTag(key: string, value: Primitive): void {
27-
SentryR.setTag(key, value);
28-
}
29-
30-
/**
31-
* Updates user context information for future events.
32-
*
33-
* @param user User context object to be set in the current context. Pass `null` to unset the user.
34-
*/
35-
export function setUser(id: string): void {
36-
SentryR.setUser({ id });
37-
}
38-
3910
/**
4011
* Monitoring context which will create wrapper for monitoring functionality.
4112
*/
42-
export const MonitoringContext = createContext<MonitoringContextType | null>(null);
13+
export const Context = createContext<MonitoringContext | null>(null);
4314

4415
/**
4516
* Monitoring wrapper used to abstract Sentry functionality.
4617
*
47-
* @param {object} children - Provider children components that will be shared inside context provider.
48-
* @param {MonitoringConfig} config - Configuration for sentry to override default configuration.
18+
* @param {MonitoringProps} data - Configuration for sentry to override default configuration.
19+
* @return {React.ReactNode}
4920
*/
50-
export function MonitoringProvider({ children, config }: MonitoringConfigType) {
21+
export function MonitoringProvider({ children, config }: PropsWithChildren<MonitoringProps>) {
5122
useEffect(() => {
5223
Sentry.init({
53-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
5424
dsn: config.dsn,
5525
environment: config.environment,
5626
debug: config.debug,
57-
enableAutoSessionTracking: config.enableAutoSessionTracking,
58-
enableInExpoDevelopment: config.enableInExpoDevelopment,
59-
sessionTrackingIntervalMillis: config.sessionTrackingIntervalMillis,
6027
tracesSampleRate: config.tracesSampleRate,
6128
integrations: [
62-
...(Platform.select({
63-
web: [new CaptureConsole({ levels: ['log'] })],
64-
native: [],
65-
})),
66-
new Integrations.BrowserTracing({ tracingOrigins: config.tracingOrigins }),
29+
new BrowserTracing({ tracePropagationTargets: config.tracingOrigins }),
6730
],
68-
} as Sentry.SentryExpoNativeOptions);
31+
});
32+
}, []);
33+
34+
/**
35+
* Updates user context information for future events.
36+
*
37+
* @param id {string} set user for in sentry
38+
* @return {void}
39+
*/
40+
const setMonitoringUser = useCallback((id: string): void => {
41+
Sentry.setUser({ id });
42+
}, []);
43+
44+
/**
45+
* Set key:value that will be sent as tags data with the event.
46+
*
47+
* Can also be used to unset a tag, by passing `undefined`.
48+
*
49+
* @param key String key of tag
50+
* @param value Value of tag
51+
* @return {void}
52+
*/
53+
const setMonitoringTag = useCallback((key: string, value: Primitive): void => {
54+
Sentry.setTag(key, value);
6955
}, []);
7056

7157
/**
7258
* Error handler function which is used to capture errors in sentry.
7359
*
7460
* @param error {Error | string} - Caught error that to be send to Sentry.io
61+
* @returns {string | null}
7562
*/
7663
const errorHandler = useCallback((error: Error | string): string | null => {
77-
if (!Sentry || (!Sentry?.Browser && !Sentry?.Native)) { return null; }
64+
if (!Sentry) {
65+
return null;
66+
}
7867

79-
return platform.captureException(error);
68+
return Sentry.captureException(error);
8069
}, []);
8170

8271
/**
@@ -85,35 +74,60 @@ export function MonitoringProvider({ children, config }: MonitoringConfigType) {
8574
*
8675
* @param name {string} - Name of transaction
8776
* @param operation {string} - Operation of transaction to be performed
88-
* @param data {{[key: string]: number | string}} - Data to be added on transaction
89-
*/
90-
// eslint-disable-next-line @typescript-eslint/ban-types
91-
const measurePerformance = useCallback((name: string, operation: string, data?: { [key: string]: number | string }): Function => {
92-
const transaction = platform.startTransaction({ name, op: operation });
93-
const transactionOperation = transaction.startChild({ op: operation, data });
77+
* @param [data] {{[key: string]: number | string}} - Data to be added on transaction
78+
* @returns {() => void} - Which will helps to close the transaction and complete the measurement.
79+
*/
80+
const measurePerformance = useCallback((name: string, op: string, data?: { [key: string]: number | string }): (() => void) => {
81+
// This will create a new Transaction
82+
const transaction = Sentry.startTransaction({ name, data, op });
83+
84+
// Set transaction on scope to associate with errors and get included span instrumentation
85+
// If there's currently an unfinished transaction, it may be dropped
86+
Sentry.getCurrentHub().configureScope((scope) => {
87+
scope.setSpan(transaction);
88+
});
89+
9490
return () => {
95-
transactionOperation.setStatus(SentryTransactionStatus);
96-
transactionOperation.finish();
9791
transaction.setStatus(SentryTransactionStatus);
9892
transaction.finish();
9993
};
10094
}, []);
10195

96+
/**
97+
* Set the custom measurement on particular transaction
98+
*
99+
* @param transactionName Name of the transaction
100+
* @param name Name of the measurement
101+
* @param value Value of the measurement
102+
* @param [unit] Unit of the measurement. (Defaults to an empty string)
103+
* @return {void}
104+
*/
105+
const setMeasurement = useCallback((transactionName: string, name: string, value: number, unit?: string): void => {
106+
const transaction = Sentry.startTransaction({ name: transactionName, op: name });
107+
108+
setTimeout(() => {
109+
transaction.setMeasurement(name, value, unit);
110+
transaction.setMeasurement('frames_total', value, unit);
111+
transaction.setStatus(SentryTransactionStatus);
112+
transaction.finish();
113+
}, 100);
114+
}, []);
115+
102116
const monitoringContextValue = useMemo(
103-
() => ({ errorHandler, measurePerformance }),
104-
[errorHandler, measurePerformance],
117+
() => ({ setMonitoringUser, setMonitoringTag, errorHandler, measurePerformance, setMeasurement }),
118+
[setMonitoringUser, setMonitoringTag, errorHandler, measurePerformance, setMeasurement],
105119
);
106120

107121
return (
108-
<MonitoringContext.Provider value={monitoringContextValue}>
122+
<Context.Provider value={monitoringContextValue}>
109123
{children}
110-
</MonitoringContext.Provider>
124+
</Context.Provider>
111125
);
112126
}
113127

114128
/**
115129
* Custom hook which will provide monitoring context which will expose all the functionality.
116130
*/
117131
export function useMonitoring() {
118-
return useContext(MonitoringContext);
132+
return useContext(Context);
119133
}

packages/corejs/src/monitoring/types.ts

Lines changed: 14 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,6 @@ export interface MonitoringConfig {
1414
* Enable debug functionality in the SDK itself
1515
*/
1616
debug: boolean;
17-
/**
18-
* Should sessions be tracked to Sentry Health or not.
19-
*/
20-
enableAutoSessionTracking: boolean;
21-
/**
22-
* Enable sentry in expo development of not.
23-
*/
24-
enableInExpoDevelopment: boolean;
25-
/**
26-
* The interval to end a session if the App goes to the background.
27-
*/
28-
sessionTrackingIntervalMillis: number;
2917
/**
3018
* Sample rate to determine trace sampling.
3119
*
@@ -39,13 +27,18 @@ export interface MonitoringConfig {
3927
/**
4028
* Array of all the origin to browser trace.
4129
*/
42-
tracingOrigins: Array<string>;
30+
tracingOrigins: string[];
4331
}
4432

4533
/**
4634
* Monitoring context interface
4735
*/
48-
export interface MonitoringContextType {
36+
export interface MonitoringContext {
37+
/**
38+
* Set current user for sentry.
39+
*/
40+
setMonitoringUser: (id: string) => void;
41+
4942
/**
5043
* Store the error in the monitoring application.
5144
*/
@@ -54,40 +47,22 @@ export interface MonitoringContextType {
5447
/**
5548
* Start Measure Performance
5649
*/
57-
measurePerformance: (name: string, operation: string, data: { [key: string]: number | string } | null) => void;
50+
measurePerformance: (name: string, op: string, data: { [key: string]: number | string } | null) => (() => void);
51+
52+
/**
53+
* Set custom measurement value
54+
*/
55+
setMeasurement: (transactionName: string, name: string, value: number, unit: string) => void;
5856
}
5957

6058
/**
6159
* Monitoring configuration interface
6260
*/
63-
export interface MonitoringConfigType {
64-
/**
65-
* Provider children components that will be shared inside context provider.
66-
*/
67-
children: object;
68-
61+
export interface MonitoringProps {
6962
/**
7063
* Configuration to initialize Sentry
7164
*/
7265
config: MonitoringConfig;
7366
}
7467

75-
export const enum MonitoringOperations {
76-
UPLOAD = 'upload',
77-
CAMERA = 'camera',
78-
FUNC = 'func',
79-
APP = 'app',
80-
HTTP = 'http',
81-
}
82-
8368
export const SentryTransactionStatus = 'success';
84-
85-
export const enum MonitoringTransaction {
86-
HTTP = 'http',
87-
USER_TIME = 'user-time-per-action',
88-
USER_CAMERA_TIME = 'user-camera-time',
89-
USER_UPLOAD_CENTER_TIME = 'user-upload-center-time',
90-
USER_ACTION = 'user-action',
91-
RESPONSE_TIME = 'response-time',
92-
FUNC = 'func',
93-
}

packages/corejs/tsconfig.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@
1010
"esModuleInterop": true,
1111
"moduleResolution": "node",
1212
"module": "commonjs",
13-
"lib": [ "es2015" ]
13+
"skipLibCheck": true,
14+
"lib": [ "es2015" ],
1415
},
1516
"include": ["src"],
16-
"exclude": ["node_modules"]
17+
"exclude": [
18+
"node_modules"
19+
]
1720
}

src/components/SilentAuth.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@ import { TokenResponse } from 'expo-auth-session/src/TokenRequest';
33
import { ASYNC_STORAGE_AUTH_KEY, onAuthenticationSuccess } from 'hooks/useSignIn';
44
import { useEffect, useState } from 'react';
55
import { useDispatch } from 'react-redux';
6+
import { useMonitoring } from '@monkvision/corejs';
7+
// eslint-disable-next-line camelcase
8+
import jwt_decode from 'jwt-decode';
69

710
export default function SilentAuth() {
811
const [hasBeenDone, setHasBeenDone] = useState(false);
912
const dispatch = useDispatch();
13+
const { setMonitoringUser } = useMonitoring();
1014

1115
useEffect(() => {
1216
if (!hasBeenDone) {
@@ -16,6 +20,11 @@ export default function SilentAuth() {
1620
authentication.issuedAt = Number(authentication.issuedAt);
1721
authentication.expiresIn = Number(authentication.expiresIn);
1822
if (TokenResponse.isTokenFresh(authentication) && !!authentication.accessToken) {
23+
const loggedInUser = jwt_decode(authentication.accessToken);
24+
if (loggedInUser && loggedInUser.sub) {
25+
setMonitoringUser(loggedInUser.sub);
26+
}
27+
1928
onAuthenticationSuccess(authentication, dispatch);
2029
} else {
2130
AsyncStorage.removeItem(ASYNC_STORAGE_AUTH_KEY)

src/hooks/useSignIn/index.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
import monk from '@monkvision/corejs';
1+
import monk, { useMonitoring } from '@monkvision/corejs';
22
import AsyncStorage from '@react-native-async-storage/async-storage';
3+
// eslint-disable-next-line camelcase
4+
import jwt_decode from 'jwt-decode';
35

46
import discoveries from 'config/discoveries';
57
import { makeRedirectUri, ResponseType, useAuthRequest } from 'expo-auth-session';
@@ -51,6 +53,7 @@ export default function useSignIn(callbacks = {}) {
5153
const [isLoading, setIsLoading] = useState(false);
5254
const start = () => setIsLoading(true);
5355
const stop = () => setIsLoading(false);
56+
const { setMonitoringUser } = useMonitoring();
5457

5558
const [request, response, promptAsync] = useAuthRequest(
5659
{
@@ -76,9 +79,13 @@ export default function useSignIn(callbacks = {}) {
7679
useEffect(() => {
7780
if (response?.type === 'success' && response.authentication?.accessToken) {
7881
stop();
79-
8082
onAuthenticationSuccess(response.authentication, dispatch);
8183

84+
const loggedInUser = jwt_decode(response.authentication.accessToken);
85+
if (loggedInUser && loggedInUser.sub) {
86+
setMonitoringUser(loggedInUser.sub);
87+
}
88+
8289
const dataToStore = JSON.stringify(response.authentication);
8390
AsyncStorage.setItem(ASYNC_STORAGE_AUTH_KEY, dataToStore).then(() => {
8491
if (typeof onSuccess === 'function') { onSuccess(response); }

src/main.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import { render } from 'react-dom';
3-
import Constants from 'expo-constants';
43
import { registerRootComponent } from 'expo';
4+
import Constants from 'expo-constants';
55
import { Platform } from 'react-native';
66
import * as Sentry from 'sentry-expo';
77
import App from 'components/App';
@@ -12,9 +12,6 @@ const config = {
1212
dsn: Constants.manifest.extra.SENTRY_DSN,
1313
environment: Constants.manifest.extra.ENV,
1414
debug: Constants.manifest.extra.ENV !== 'production',
15-
enableAutoSessionTracking: true,
16-
enableInExpoDevelopment: true,
17-
sessionTrackingIntervalMillis: 10000,
1815
tracesSampleRate: 1,
1916
tracingOrigins: ['localhost', 'cna.dev.monk.ai', 'cna-staging.dev.monk.ai', 'cna.preview.monk.ai', 'cna.monk.ai'],
2017
};

0 commit comments

Comments
 (0)