# Utilizando o Sentry

### ⁉️ Monitoramento de Erros e Desempenho no Flutter com Sentry

O Sentry é uma plataforma de monitoramento de erros e desempenho que permite rastrear problemas em tempo real e obter insights detalhados sobre a estabilidade e a performance do seu aplicativo Flutter.

***

#### ✅ Passo 1: Crie uma Conta no Sentry

Acesse <https://sentry.io> e crie uma conta, caso ainda não tenha.

Configure um novo projeto para o seu app Flutter no painel da plataforma.

***

#### ✅ Passo 2: Adicione a Dependência

Inclua o `sentry_flutter` no seu `pubspec.yaml`:

```yaml
dependencies:  
	sentry_flutter:  ^5.0.0
```

Em seguida, execute:

```bash
flutter pub get
```

***

#### ✅ Passo 3: Inicialização no `main()`

No `main()` do seu aplicativo, inicialize o Sentry com a sua DSN (chave fornecida pela plataforma):

```dart
import 'package:flutter/material.dart';
import 'package:sentry_flutter/sentry_flutter.dart';

void main() async {
  await SentryFlutter.init(
    (options) {
      options.dsn = 'SUA_CHAVE_DE_API_AQUI';

      // 🔍 Captura de rastros de performance (navegação, async, etc.)
      options.tracesSampleRate = 1.0; // 100% das transações

      // 🧠 Ativa o rastreamento automático de sessões
      options.enableAutoSessionTracking = true;

      // 📌 Inclui automaticamente stacktraces mesmo em logs manuais
      options.attachStacktrace = true;

      // 🧪 Ativa o modo de debug apenas em desenvolvimento
      options.debug = kDebugMode;

      // 🎥 (Opcional) Captura sessões em vídeo quando há erro
      options.experimental.replay.sessionSampleRate = 0.7; // 70% das sessões
      options.experimental.replay.onErrorSampleRate = 1.0; // 100% com erro

      // 🧵 Número máximo de breadcrumbs (ações anteriores ao erro)
      options.maxBreadcrumbs = 100;

      // 🌍 Define o ambiente automaticamente baseado na BASE_URL
      final baseUrl = dotenv.env['BASE_URL'] ?? '';
      if (baseUrl.contains('deve')) {
        options.environment = 'development';
      } else if (baseUrl.contains('stag')) {
        options.environment = 'staging';
      } else if (baseUrl.contains('hmlg')) {
        options.environment = 'homolog';
      } else {
        options.environment = 'production';
      }
    },
    appRunner: () => runApp(MyApp()),
  );
}
```

> 💡 **Dica:** Envolva seu app em `runZonedGuarded` para capturar exceções não tratadas:

```dart
void main() {
  runZonedGuarded(() async {
    // Inicialização do Sentry e app
  }, (error, stack) {
    Sentry.captureException(error, stackTrace: stack);
  });
}
```

***

#### ✅ Passo 4: Centralize com um `SentryService`

Recomenda-se criar uma classe utilitária para facilitar o uso do Sentry em todo o projeto:

```dart
class SentryService {
  /// Captura uma exceção manualmente e adiciona contexto personalizado.
  static Future<void> captureException(
    dynamic exception,
    StackTrace? stackTrace, {
    Map<String, dynamic>? extra, // 🔍 Dados adicionais do erro
    String? tag,                 // 🏷️ Tag para agrupar o erro por fluxo (ex: 'checkout', 'login')
    String? level,               // 🔔 Nível de severidade: error, warning, info
  }) async {
    try {
      await Sentry.captureException(
        exception,
        stackTrace: stackTrace,
        withScope: (scope) {
          if (tag != null) {
            scope.setTag('flow', tag); // exemplo: flow: login
          }
          if (extra != null) {
            scope.setContexts('extra_data', extra); // dados como valores de input, status de flags etc.
          }
          if (level != null) {
            scope.level = _getSentryLevel(level); // define o nível de erro
          }
        },
      );
    } catch (e) {
      log('Erro ao capturar exceção no Sentry', error: e);
    }
  }

  /// Converte o nível textual (info, warning, error) para o enum do Sentry.
  static SentryLevel _getSentryLevel(String? level) {
    switch (level?.toLowerCase()) {
      case 'error':
        return SentryLevel.error;
      case 'warning':
        return SentryLevel.warning;
      case 'info':
        return SentryLevel.info;
      default:
        return SentryLevel.error;
    }
  }

  /// Adiciona um breadcrumb (registro de ação do usuário) ao escopo atual.
  static void addBreadcrumb(
    String message, {
    String? category,                 // categoria lógica (ex: "http", "ui", "auth")
    Map<String, dynamic>? data,       // detalhes adicionais (headers, payload, etc.)
  }) {
    Sentry.addBreadcrumb(
      Breadcrumb(
        message: message,             // descrição textual da ação
        category: category ?? 'app',  // categoria da ação
        data: data,                   // map com dados úteis
        level: SentryLevel.info,
      ),
    );
  }

  /// Define o usuário atual, associando erros e eventos a ele.
  static void setUserContext({
    required String email,
    required bool isLogged,     // true se o usuário estiver autenticado
    required bool fetchedUser,  // true se os dados do usuário já foram buscados
    String? clientId,           // ID do cliente
    String? companyId,          // ID da empresa vinculada
  }) {
    Sentry.configureScope((scope) {
      scope.setUser(SentryUser(
        email: email,
        id: clientId,
        data: {
          'isLogged': isLogged,
          'fetchedUser': fetchedUser,
          'companyId': companyId,
        },
      ));
    });
  }
}
```

**Exemplos de Uso**

**Capturar erro manualmente com contexto:**

```dart
try {
  // lógica de negócio
} catch (e, st) {
  await SentryService.captureException(
    e,
    st,
    tag: 'checkout',
    extra: {'step': 'confirm_payment'},
    level: 'error',
  );
}
```

**Adicionar uma ação importante como breadcrumb:**

```dart
SentryService.addBreadcrumb(
  'Usuário pressionou botão de salvar',
  category: 'ui.interaction',
  data: {'form_valid': true},
);
```

**Definir o contexto do usuário:**

```
SentryService.setUserContext(
  email: 'usuario@exemplo.com',
  isLogged: true,
  fetchedUser: true,
  clientId: 'abc123',
  companyId: 'empresa456',
);
```

***

#### ✅ Passo 5: Boas Práticas no Uso

* Utilize `SentryService.captureException()` sempre que capturar manualmente um erro com `try/catch`.
* Registre ações ou eventos importantes com `SentryService.addBreadcrumb()`.
* Assim que possível, chame `SentryService.setUserContext()` para associar eventos a usuários específicos.
* Use `Sentry.captureMessage()` para registrar ocorrências importantes que **não** geram exceptions.
* Inclua informações adicionais no escopo, como versão do app, permissões, device info, etc.
* Use `Sentry.startTransaction()` se quiser medir performance manualmente em tarefas críticas.

***

#### 📊 Monitoramento de Desempenho

O Sentry também permite rastrear a performance do app:

* **Traces automáticos:** com `tracesSampleRate: 1.0`, o Sentry coleta dados de navegação e async tasks.
* **Session Replay:** gravações da sessão do usuário em erros críticos.
* **Transações manuais:** com `startTransaction()` para rastrear tarefas específicas.

***

#### 🎯 Benefícios de uma Integração Completa

* **Rastreabilidade aprimorada:** com breadcrumbs e contexto de usuário.
* **Diagnóstico eficiente:** stacktrace rico e metadados sobre ambiente, versão, etc.
* **Correções mais rápidas:** alertas proativos e session replay ajudam a reproduzir bugs.
* **Melhor experiência para o usuário:** menos falhas e melhor performance.

***

#### ✅ Conclusão

Ao seguir esse padrão de integração com o Sentry no Flutter, você garante um monitoramento robusto, com contexto rico, alertas inteligentes e rastreamento de performance. Use o `SentryService` como interface principal para padronizar e facilitar a captura de erros, mensagens e contexto de uso.
