Sentry is an error tracking and performance monitoring platform that helps you solve problems and continuously learn about your apps. The `@amazon-devices/sentry__react-native` library implements the [React Native SDK for Sentry](https://github.com/getsentry/sentry-react-native) on the Kepler platform.

Some of the features offered by Sentry are not set up for Kepler. You can post questions or report issues on the [Kepler Developer Forums](https://community.amazondeveloper.com/).


## Installation

1. Add the JavaScript library dependency in the `package.json` file.

    ```json
    dependencies: {
        "@sentry/react-native": "npm:@amazon-devices/sentry__react-native@~1.0.10"
    }
    ```
2. Install dependencies using `npm install` command.

## Examples

Initialize Sentry on the top-level of you app.

To initialize Sentry use the `Sentry.init({...})` method. The only required parameter is the `dsn`, short for [Data Source Name](https://docs.sentry.io/concepts/key-terms/dsn-explainer/). Find the `dsn` from the Sentry project's settings page.


```js
import * as Sentry from '@sentry/react-native';
import React from 'react';
import {View, Button, Text} from 'react-native';

// init Sentry somewhere top-level outside of component
Sentry.init({
  // set environment variable SENTRY_DSN to your project's dsn
  // or inline your DSN here
  dsn: process.env.SENTRY_DSN,
});

export function App() {
  const captureMessage = () => {
    // send message directly to Sentry
    Sentry.captureMessage('SentryAppDemo message');
  };

  const captureException = () => {
    // capture exception and send it to Sentry
    Sentry.captureException(new Error('SentryAppDemo error'));
  };

  return (
    <View
      style={{
        backgroundColor: '#181a1b',
        padding: 32,
        flex: 1,
        flexDirection: 'column',
        gap: 16,
      }}>
      <Text style={{fontSize: 32, color: 'white'}}>Sentry App Demo</Text>
      <View style={{width: '25%'}}>
        <Button onPress={captureMessage} title="Capture Message" />
      </View>
      <View style={{width: '25%'}}>
        <Button onPress={captureException} title="Capture Exception" />
      </View>
    </View>
  );
}
```

After initializing Sentry all uncaught exceptions are found automatically and reported by Sentry. You don't need to send events manually.

You can also add extra information to the Sentry events using `Sentry.setContext()` or `Sentry.setUser()`, shown below.

```js
import * as Sentry from '@sentry/react-native';
import React from 'react';
import {View, Button, Text} from 'react-native';

// init Sentry somewhere top-level outside of component
Sentry.init({
  // set environment variable SENTRY_DSN to your project's dsn
  // or inline your DSN here
  dsn: 'process.env.SENTRY_DSN',
});

export function App() {
  const setContext = () => {
    // add custom data to Sentry events
    Sentry.setContext('ExampleContext', {
      category: 'ExampleCategory',
      message: 'ExampleMessage',
      level: 'info',
    });
  };

  const throwError = () => {
    // throw error without catching - Sentry will report this for us
    throw new Error('SentryAppDemo uncaught error');
  };

  return (
    <View
      style={{
        backgroundColor: '#181a1b',
        padding: 32,
        flex: 1,
        flexDirection: 'column',
        gap: 16,
      }}>
      <Text style={{fontSize: 32, color: 'white'}}>Sentry App Demo</Text>
      <View style={{width: '25%'}}>
        <Button onPress={setContext} title="Set Context" />
      </View>
      <View style={{width: '25%'}}>
        <Button onPress={throwError} title="Throw Error" />
      </View>
    </View>
  );
}
```

## API reference

- `Sentry.init(options: ReactNativeOptions)` - initializes Sentry. After calling it all errors will be reported by Sentry. If you application crashes or throws uncaught exception before the call to `Sentry.init()` it won't be caught by Sentry.
- `Sentry.nativeCrash()` - this method triggers native crash, tested and verified to work on Kepler devices and simulator.
- [`Sentry.setUser(user: User)`](https://docs.sentry.io/platforms/react-native/enriching-events/identify-user/) - sets user data (e.g., `username`, `email`) that will be included in Sentry events.
- [`Sentry.setContext(contextKey: string, contextData: Object)`](https://docs.sentry.io/platforms/react-native/enriching-events/context/#structured-context) - sets custom data to be add under the passed `contextKey` that will be included in Sentry events.
- `Sentry.flush()` - Wait for all Sentry events to be sent.
- `Sentry.captureMessage(message: string)` - Captures a message event and sends it to Sentry.
- `Sentry.captureException(exception: Error)` - Captures an exception event and sends it to Sentry.

## Additional configuration

### Add readable stack traces to Sentry errors

After the app is built, you need to notify Sentry about the app release name, version, and dist number and send sourcemaps of the JavaScript bundle and debug files. This ensures that Sentry catches events and correctly maps the information with readable stack traces.

After building the app, the folder structure might look like this:
```sh
├── sentrydemoapp
│   ├── build
│   │   ├── lib
│   │   │   ├── rn-bundles
│   │   │   │   ├── Debug #use the path for debug build
│   │   │   │   ├── Release #use the path for release build
│   │   ├── x86_64-release
│   │   │   ├── debug #use the path for app meant for simulator for x86 machines
│   │   ├── armv7-release
│   │   │   ├── debug #use the path for app meant for Fire TV Stick
│   │   ├── aarch64-release
│   │   │   ├── debug #use the path for app meant for simulator for M-series machines
```

1. In the Sentry initialization create a release version and a dist version. You need to define `$SENTRY_RELEASE_VERSION` (for example, `my-kepler-project@2.3.12`) and `$SENTRY_DIST_NUMBER` (for example `52`). See [Sentry official docs](https://docs.sentry.io/platforms/react-native/sourcemaps/troubleshooting/optional-release-and-distribution/) for more information.
    ```js
    Sentry.init({
      release: process.env.SENTRY_RELEASE_VERSION,
      dist: process.env.SENTRY_DIST_NUMBER,
    });
    ```
2. Add Sentry Metro Serializer to `metro.config.js` and rebuild the application

    ```js
    ...
    const {createSentryMetroSerializer} = require('@sentry/react-native/dist/js/tools/sentryMetroSerializer');
    ...

    const sentryMetroSerializer = createSentryMetroSerializer()

    const config = {
      serializer: {
        customSerializer(entryPoint, preModules, graph, options) {
          return sentryMetroSerializer(entryPoint, preModules, graph, options)
        },
      },
    };

    module.exports = mergeConfig(getDefaultConfig(__dirname), config);
    ```
3. Install `sentry-cli`. See
   [Sentry official docs](https://docs.sentry.io/cli/installation/#automatic-installation) for more information.
    ```sh
    curl -sL https://sentry.io/get-cli/ | sh
    ```
4. Create a new Sentry release. You need to pass the previously defined `$SENTRY_RELEASE_VERSION`. See [Sentry official docs](https://docs.sentry.io/platforms/react-native/configuration/releases/) for more information.
    ```sh
    sentry-cli releases new $SENTRY_RELEASE_VERSION
    ```
5. Upload source maps for JavaScript symbolication. Please note that `sentry-wizard` is not yet supported. See [Sentry official docs](https://docs.sentry.io/platforms/react-native/sourcemaps/) for more information.
    ```sh
    # inside Kepler app directory
    # BUILD_TYPE is either Debug or Release
    # --release and --dist flags are optional when using Debug IDs
    sentry-cli sourcemaps upload "build/lib/rn-bundles/$BUILD_TYPE" --release "$SENTRY_RELEASE_VERSION" --dist "$SENTRY_DIST_NUMBER"
    ```

After sending the information to Sentry, you will receive precise information regarding where errors occur in your app.

## Implementation details

- Please note that `sentry-wizard` and Sentry `React Native Metro Plugin` are not yet supported.
- [`@sentry/wizard`](https://github.com/getsentry/sentry-wizard) - doesn't work on Kepler projects.
- [`withSentryConfig` metro tool](https://docs.sentry.io/platforms/react-native/sourcemaps/uploading/hermes/#manual-upload) - doesn't work on Kepler projects.
- [`Tracing`](https://docs.sentry.io/concepts/key-terms/tracing/) is not implemented.
- [`Profiling`](https://docs.sentry.io/product/explore/profiling/) is not implemented.

### Known issues

- Sentry offline support is not working on Kepler.

### Known limitations

| API | Current Behaviour |
|-----|-------------------|
| [`Sentry.addBreadcrumb()`](https://docs.sentry.io/platforms/react-native/enriching-events/breadcrumbs/) | Does not peform any actions |
| [`Sentry.init(options: ReactNativeOptions)`](https://docs.sentry.io/platforms/react-native/configuration/options/) | Certain options are not supported. Please see the table of ReactNativeOptions below. |

`Sentry.init()` missing options

| Sentry.init Option | Current Behaviour |
|--------------------|-------------------|
| [`options.enableNativeCrashHandling`](https://docs.sentry.io/platforms/react-native/configuration/options/#enableNativeCrashHandling) | Cannot be disabled at the moment |
| [`options.sessionTrackingIntervalMillis`](https://docs.sentry.io/platforms/react-native/configuration/options/#sessionTrackingIntervalMillis) | Not supported |
| `options.enableNdk` | [NDK](https://developer.android.com/ndk) only works on Android |
| [`options.enableNdkScopeSync`](https://docs.sentry.io/platforms/react-native/configuration/options/#enableNdkScopeSync) | [NDK](https://developer.android.com/ndk) only works on Android |
| [`options.attachThreads`](https://docs.sentry.io/platforms/react-native/configuration/options/#attachThreads) | Android-only option |
| [`options.sendDefaultPii`](https://docs.sentry.io/platforms/react-native/configuration/options/#send-default-pii) | Android-only option |
| [`options.enableAutoPerformanceTracing`](https://docs.sentry.io/platforms/react-native/configuration/options/#enableAutoPerformanceTracing) | [performance monitoring](https://docs.sentry.io/product/performance/) is not working
| [`options.enableWatchdogTerminationTracking`](https://docs.sentry.io/platforms/react-native/configuration/options/#enableWatchdogTerminationTracking) | iOS only option |
| [`options.enableAppHangTracking`](https://docs.sentry.io/platforms/react-native/configuration/app-hangs/) | iOS-only option |
| [`options.appHangTimeoutInterval`](https://docs.sentry.io/platforms/react-native/configuration/app-hangs/) | iOS-only option |
| [`options.attachScreenshot`](https://docs.sentry.io/platforms/react-native/configuration/options/#attach-screenshot) | Not supported  |
| [`options.attachViewHierarchy`](https://docs.sentry.io/platforms/react-native/configuration/options/#attach-view-hierarchy) | Not supported  |

## Supported versions

| Package Version | Based On | @amazon-devices/react-native-kepler version |
|-----------------|----------|-----------------------------------|
| 1.0.0           | 5.15.2   | 2.x.x                             |
