|
1 | | -import React, { createContext, useContext, useEffect, useMemo } from 'react'; |
2 | | -import { Primitive } from '@sentry/types'; |
| 1 | +import * as SentryR from '@sentry/react'; |
| 2 | +import * as Sentry from 'sentry-expo'; |
| 3 | +import React, { createContext, useCallback, useContext, useEffect, useMemo } from 'react'; |
3 | 4 | import { CaptureConsole } from '@sentry/integrations'; |
4 | 5 | import { Integrations } from '@sentry/tracing'; |
| 6 | +import { Primitive } from '@sentry/types'; |
5 | 7 | import { Platform } from 'react-native'; |
6 | | -import * as Sentry from 'sentry-expo'; |
7 | | -import * as SentryR from '@sentry/react'; |
8 | | -import Constants from 'expo-constants'; |
9 | | -import PropTypes from 'prop-types'; |
10 | 8 |
|
11 | | -import { MonitoringContextType } from './types'; |
| 9 | +import { MonitoringConfigType, MonitoringContextType } from './types'; |
12 | 10 |
|
13 | | -const tracingOrigins = ['localhost', 'cna.dev.monk.ai', 'cna.staging.monk.ai', 'cna.preview.monk.ai', 'cna.monk.ai']; |
14 | | -const MonitoringConstants = { |
15 | | - type: { |
16 | | - UPLOAD: 'upload', // logs linked to the upload |
17 | | - CAMERA: 'camera', // logs linked to the camera |
18 | | - FUNC: 'func', // logs linked to a function |
19 | | - APP: 'app', // logs linked to the application |
20 | | - HTTP: 'http', // logs linked to the api |
21 | | - }, |
22 | | - operation: { |
23 | | - HTTP: 'http', |
24 | | - USER_TIME: 'user-time-per-action', |
25 | | - USER_CAMERA_TIME: 'user-camera-time', |
26 | | - USER_UPLOAD_CENTER_TIME: 'user-upload-center-time', |
27 | | - USER_ACTION: 'user-action', |
28 | | - RESPONSE_TIME: 'response-time', |
29 | | - FUNC: 'func', |
30 | | - }, |
31 | | -}; |
| 11 | +export * from './types'; |
32 | 12 |
|
33 | | -const Tracing = Integrations.BrowserTracing; |
34 | | -const setTag = (key: string, value: Primitive): void => SentryR.setTag(key, value); |
35 | | -const setUser = (id: string) => SentryR.setUser({ id }); |
36 | | -const MonitoringContext = createContext<MonitoringContextType | null>(null); |
| 13 | +const platform = Platform.select({ |
| 14 | + web: Sentry.Browser, |
| 15 | + native: Sentry.Browser, |
| 16 | +}); |
37 | 17 |
|
38 | | -function MonitoringProvider({ children, config }) { |
39 | | - useEffect(() => { |
40 | | - Sentry.init({ |
41 | | - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access |
42 | | - dsn: (config.dns || Constants.manifest.extra.SENTRY_DSN) as string, |
43 | | - environment: Constants.manifest.extra.ENV as string, |
44 | | - debug: Constants.manifest.extra.ENV !== 'production', |
45 | | - enableAutoSessionTracking: true, |
46 | | - enableInExpoDevelopment: true, |
47 | | - sessionTrackingIntervalMillis: 10000, |
48 | | - tracesSampleRate: Constants.manifest.extra.ENV !== 'production' ? 1.0 : 0.2, |
49 | | - integrations: [ |
50 | | - ...(Platform.select({ |
51 | | - web: [new CaptureConsole({ levels: ['log'] })], |
52 | | - native: [], |
53 | | - })), |
54 | | - new Tracing({ |
55 | | - tracingOrigins, |
56 | | - }), |
57 | | - ], |
58 | | - } as Sentry.SentryExpoNativeOptions); |
59 | | - }, []); |
| 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 | +} |
60 | 29 |
|
61 | | - /** |
62 | | - * @param error {Error} - Caught error to send to Sentry.io |
63 | | - * @param type {string} - tag of the error's type |
64 | | - * @param extras {Record} - Useful information that can be sent (request's body for example) |
65 | | - * @param additionalTags - (Optional) Additional tags to add to the error |
66 | | - */ |
67 | | - const errorHandler = (error: Error | string): string => { |
68 | | - if (!Sentry || (!Sentry?.Browser && !Sentry?.Native)) { return null; } |
| 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 | +} |
69 | 38 |
|
70 | | - return Platform.select({ |
71 | | - web: Sentry.Browser, |
72 | | - native: Sentry.Browser, |
73 | | - }).captureException(error); |
74 | | - }; |
| 39 | +/** |
| 40 | + * Monitoring context which will create wrapper for monitoring functionality. |
| 41 | +*/ |
| 42 | +export const MonitoringContext = createContext<MonitoringContextType | null>(null); |
75 | 43 |
|
76 | | - /** |
77 | | - * @param name {string} - Name of transaction |
78 | | - * @param operation {string} - Operation of transaction to be performed |
79 | | - * @param data {{[key: string]: number | string}} - Data to be added on transaction |
80 | | - */ |
81 | | - const measurePerformance = (name: string, operation: string, data: { [key: string]: number | string } | null) => { |
82 | | - const transaction = Platform.select({ |
83 | | - web: Sentry.Browser, |
84 | | - native: Sentry.Browser, |
85 | | - }).startTransaction({ name, data }); |
86 | | - const transactionOperation = transaction.startChild({ op: operation }); |
| 44 | +/** |
| 45 | + * Monitoring wrapper used to abstract Sentry functionality. |
| 46 | + * |
| 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. |
| 49 | +*/ |
| 50 | +export function MonitoringProvider({ children, config }: MonitoringConfigType) { |
| 51 | + useEffect(() => { |
| 52 | + Sentry.init({ |
| 53 | + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access |
| 54 | + dsn: config.dsn, |
| 55 | + environment: config.environment, |
| 56 | + debug: config.debug, |
| 57 | + enableAutoSessionTracking: config.enableAutoSessionTracking, |
| 58 | + enableInExpoDevelopment: config.enableInExpoDevelopment, |
| 59 | + sessionTrackingIntervalMillis: config.sessionTrackingIntervalMillis, |
| 60 | + tracesSampleRate: config.tracesSampleRate, |
| 61 | + integrations: [ |
| 62 | + ...(Platform.select({ |
| 63 | + web: [new CaptureConsole({ levels: ['log'] })], |
| 64 | + native: [], |
| 65 | + })), |
| 66 | + new Integrations.BrowserTracing({ tracingOrigins: config.tracingOrigins }), |
| 67 | + ], |
| 68 | + } as Sentry.SentryExpoNativeOptions); |
| 69 | + }, []); |
87 | 70 |
|
88 | | - return () => { |
89 | | - transactionOperation.finish(); |
90 | | - transaction.finish(); |
91 | | - }; |
92 | | - }; |
| 71 | + /** |
| 72 | + * Error handler function which is used to capture errors in sentry. |
| 73 | + * |
| 74 | + * @param error {Error | string} - Caught error that to be send to Sentry.io |
| 75 | + */ |
| 76 | + const errorHandler = useCallback((error: Error | string): string | null => { |
| 77 | + if (!Sentry || (!Sentry?.Browser && !Sentry?.Native)) { return null; } |
| 78 | + |
| 79 | + return platform.captureException(error); |
| 80 | + }, []); |
| 81 | + |
| 82 | + /** |
| 83 | + * Measure the performance of application based on functionality and operation based on it. |
| 84 | + * Return type of the function is the IIFE, which will helps to close the transaction and complete the measurement. |
| 85 | + * |
| 86 | + * @param name {string} - Name of transaction |
| 87 | + * @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, data }); |
| 93 | + const transactionOperation = transaction.startChild({ op: operation }); |
| 94 | + |
| 95 | + return () => { |
| 96 | + transactionOperation.finish(); |
| 97 | + transaction.finish(); |
| 98 | + }; |
| 99 | + }, []); |
93 | 100 |
|
94 | 101 | const monitoringContextValue = useMemo( |
95 | 102 | () => ({ errorHandler, measurePerformance }), |
96 | 103 | [errorHandler, measurePerformance], |
97 | 104 | ); |
98 | 105 |
|
99 | | - return ( |
100 | | - <MonitoringContext.Provider value={monitoringContextValue}> |
101 | | - {children} |
102 | | - </MonitoringContext.Provider> |
103 | | - ); |
| 106 | + return ( |
| 107 | + <MonitoringContext.Provider value={monitoringContextValue}> |
| 108 | + {children} |
| 109 | + </MonitoringContext.Provider> |
| 110 | + ); |
104 | 111 | } |
105 | 112 |
|
106 | | -const useMonitoring = () => { |
| 113 | +/** |
| 114 | + * Custom hook which will provide monitoring context which will expose all the functionality. |
| 115 | +*/ |
| 116 | +export function useMonitoring() { |
107 | 117 | return useContext(MonitoringContext); |
108 | 118 | } |
109 | | - |
110 | | -export { |
111 | | - MonitoringConstants, |
112 | | - MonitoringContext, |
113 | | - setTag, |
114 | | - setUser, |
115 | | - Tracing, |
116 | | - MonitoringProvider, |
117 | | - useMonitoring, |
118 | | -}; |
119 | | - |
120 | | -MonitoringProvider.propTypes = { |
121 | | - config: PropTypes.shape({ |
122 | | - dns: PropTypes.string, |
123 | | - }), |
124 | | -}; |
125 | | - |
126 | | -MonitoringProvider.defaultProps = { |
127 | | - config: { |
128 | | - dns: '', |
129 | | - }, |
130 | | -}; |
0 commit comments