flex_logger_sentry 1.0.0 copy "flex_logger_sentry: ^1.0.0" to clipboard
flex_logger_sentry: ^1.0.0 copied to clipboard

Sentry integration for FlexLogger - provides error reporting and crash analytics capabilities.

example/lib/main.dart

// Example: FlexLogger + Sentry
//
// To send events to Sentry:
// 1. Create a project at sentry.io and copy the DSN.
// 2. Run with your DSN:
//    flutter run --dart-define=SENTRY_DSN=https://your-key@o0.ingest.sentry.io/project-id
//
// Without SENTRY_DSN the app runs with FlexLogger only (no Sentry provider).

import 'package:flex_logger/flex_logger.dart';
import 'package:flex_logger_sentry/flex_logger_sentry.dart';
import 'package:flutter/material.dart';

/// Filter presets for Sentry integration.
enum SentryFilterPreset {
  warningAndAbove('Warning+ (default)', FilterType.minLevelWarning),
  errorOnly('Error & Critical only', FilterType.minLevelError),
  typeFilter('Type filter (Error & Critical)', FilterType.typeFilter),
  composite('Composite (Error+ in production)', FilterType.composite);

  final String label;
  final FilterType type;

  const SentryFilterPreset(this.label, this.type);

  LogFilter toFilter() {
    return switch (type) {
      FilterType.minLevelWarning => const MinLevelFilter(FlexLogLevel.warning),
      FilterType.minLevelError => const MinLevelFilter(FlexLogLevel.error),
      FilterType.typeFilter => const MultiTypeFilter([ErrorLog, CriticalLog]),
      FilterType.composite => CompositeLogFilter.and([
        const MinLevelFilter(FlexLogLevel.error),
        CompositeLogFilter.not(const DevelopmentOnlyFilter()),
      ]),
    };
  }
}

enum FilterType {
  minLevelWarning,
  minLevelError,
  typeFilter,
  composite,
}

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  final dsn = const String.fromEnvironment(
    'SENTRY_DSN',
    defaultValue: '',
  );

  // Configure providers
  final providers = <LoggerProvider>[];

  if (dsn.isNotEmpty) {
    providers.add(
      SentryLoggerProvider(
        dsn: dsn,
        filter: const MinLevelFilter(FlexLogLevel.warning),
        optionsConfiguration: (options) {
          options.debug = false;
          options.environment = 'example';
          // Uncomment for production:
          // options.release = '1.0.0';
          // options.sampleRate = 0.8;
          // options.tracesSampleRate = 0.2;
        },
      ),
    );
  }

  FlexLogger.instance.configure(providers: providers);
  await FlexLogger.instance.initialize();

  FlexLogger.instance.info('Flex Logger Sentry example started');
  if (dsn.isEmpty) {
    FlexLogger.instance.warning(
      'SENTRY_DSN not set – run with --dart-define=SENTRY_DSN=your-dsn',
    );
  }

  runApp(MyApp(sentryEnabled: dsn.isNotEmpty, dsn: dsn));
}

class MyApp extends StatelessWidget {
  final bool sentryEnabled;
  final String dsn;

  const MyApp({
    super.key,
    required this.sentryEnabled,
    required this.dsn,
  });

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flex Logger Sentry',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.amber),
        useMaterial3: true,
      ),
      home: MyHomePage(
        title: 'Sentry Example',
        sentryEnabled: sentryEnabled,
        dsn: dsn,
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  final String title;
  final bool sentryEnabled;
  final String dsn;

  const MyHomePage({
    super.key,
    required this.title,
    required this.sentryEnabled,
    required this.dsn,
  });

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  SentryFilterPreset _selectedFilter = SentryFilterPreset.warningAndAbove;

  @override
  void dispose() {
    // CRITICAL: Dispose logger (calls Sentry.close())
    FlexLogger.instance.dispose();
    super.dispose();
  }

  Future<void> _reconfigureLogger() async {
    if (!widget.sentryEnabled) {
      FlexLogger.instance.warning('Cannot reconfigure - Sentry DSN not set');
      return;
    }

    await FlexLogger.instance.dispose();

    final providers = <LoggerProvider>[
      SentryLoggerProvider(
        dsn: widget.dsn,
        filter: _selectedFilter.toFilter(),
        optionsConfiguration: (options) {
          options.debug = false;
          options.environment = 'example';
        },
      ),
    ];

    FlexLogger.instance.configure(providers: providers);
    await FlexLogger.instance.initialize();

    FlexLogger.instance.info(
      'Logger reconfigured with filter: ${_selectedFilter.label}',
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: SingleChildScrollView(
          padding: const EdgeInsets.all(24.0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              // Status message
              _buildStatusCard(),

              const SizedBox(height: 24),

              // Filter configuration
              if (widget.sentryEnabled) _buildFilterSection(),

              const SizedBox(height: 24),

              // Info about Sentry behavior
              _buildInfoCard(),

              const SizedBox(height: 24),
              const Divider(),
              const SizedBox(height: 16),

              // All log levels
              const Text(
                'Test All Log Levels:',
                style: TextStyle(fontWeight: FontWeight.w600),
              ),
              const SizedBox(height: 8),
              const Text(
                'Check console and Sentry dashboard',
                style: TextStyle(fontSize: 12),
              ),
              const SizedBox(height: 12),
              Wrap(
                spacing: 8,
                runSpacing: 8,
                alignment: WrapAlignment.center,
                children: [
                  ElevatedButton(
                    onPressed: () => FlexLogger.instance.debug('Debug message (breadcrumb only)'),
                    child: const Text('Debug'),
                  ),
                  ElevatedButton(
                    onPressed: () => FlexLogger.instance.info('Info message (breadcrumb only)'),
                    child: const Text('Info'),
                  ),
                  ElevatedButton(
                    onPressed: () => FlexLogger.instance.success('Success message (breadcrumb only)'),
                    child: const Text('Success'),
                  ),
                  ElevatedButton(
                    onPressed: () => FlexLogger.instance.warning('Warning (event + breadcrumb)'),
                    child: const Text('Warning'),
                  ),
                  ElevatedButton(
                    onPressed: () => FlexLogger.instance.error('Error message (event + breadcrumb)'),
                    child: const Text('Error'),
                  ),
                  ElevatedButton(
                    onPressed: () => FlexLogger.instance.critical('Critical (event + breadcrumb)'),
                    child: const Text('Critical'),
                  ),
                ],
              ),

              const SizedBox(height: 24),
              const Divider(),
              const SizedBox(height: 16),

              // Exception examples
              const Text(
                'Test Exception Handling:',
                style: TextStyle(fontWeight: FontWeight.w600),
              ),
              const SizedBox(height: 12),
              Wrap(
                spacing: 8,
                runSpacing: 8,
                alignment: WrapAlignment.center,
                children: [
                  ElevatedButton.icon(
                    onPressed: () {
                      try {
                        throw Exception('Demo Exception for Sentry');
                      } catch (e, st) {
                        FlexLogger.instance.error('Caught Exception', e, st);
                      }
                    },
                    icon: const Icon(Icons.bug_report),
                    label: const Text('Exception'),
                  ),
                  ElevatedButton.icon(
                    onPressed: () {
                      try {
                        throw StateError('Demo Error for Sentry');
                      } catch (e, st) {
                        FlexLogger.instance.error('Caught Error', e, st);
                      }
                    },
                    icon: const Icon(Icons.error_outline),
                    label: const Text('Error'),
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildStatusCard() {
    return Card(
      color: widget.sentryEnabled ? Theme.of(context).colorScheme.primaryContainer : Theme.of(context).colorScheme.errorContainer,
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          children: [
            Icon(
              widget.sentryEnabled ? Icons.check_circle : Icons.warning,
              size: 48,
              color: widget.sentryEnabled ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.error,
            ),
            const SizedBox(height: 12),
            Text(
              widget.sentryEnabled ? 'Sentry is enabled' : 'Sentry not configured',
              style: const TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.bold,
              ),
              textAlign: TextAlign.center,
            ),
            const SizedBox(height: 8),
            Text(
              widget.sentryEnabled ? 'Logs are sent to Sentry.\nWarnings and errors create issues.' : 'Run with --dart-define=SENTRY_DSN=your-dsn\nto enable Sentry integration.',
              textAlign: TextAlign.center,
              style: Theme.of(context).textTheme.bodySmall,
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildFilterSection() {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text(
              'Sentry Filter:',
              style: TextStyle(fontWeight: FontWeight.w600, fontSize: 16),
            ),
            const SizedBox(height: 12),

            // Filter dropdown
            DropdownButton<SentryFilterPreset>(
              value: _selectedFilter,
              isExpanded: true,
              items: SentryFilterPreset.values
                  .map(
                    (filter) => DropdownMenuItem(
                      value: filter,
                      child: Text(filter.label),
                    ),
                  )
                  .toList(),
              onChanged: (value) {
                if (value != null) {
                  setState(() => _selectedFilter = value);
                }
              },
            ),

            const SizedBox(height: 16),

            // Apply button
            ElevatedButton.icon(
              onPressed: _reconfigureLogger,
              icon: const Icon(Icons.refresh),
              label: const Text('Apply Filter'),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildInfoCard() {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Row(
              children: [
                Icon(Icons.info_outline, size: 20),
                SizedBox(width: 8),
                Text(
                  'How Sentry Integration Works:',
                  style: TextStyle(fontWeight: FontWeight.w600),
                ),
              ],
            ),
            const SizedBox(height: 12),
            _buildInfoRow('Debug, Info, Success', 'Breadcrumbs only (context for errors)'),
            const SizedBox(height: 8),
            _buildInfoRow('Warning, Error, Critical', 'Breadcrumbs + Events (creates issues)'),
            const SizedBox(height: 8),
            _buildInfoRow('Exceptions with stacktrace', 'Full error context sent to Sentry'),
          ],
        ),
      ),
    );
  }

  Widget _buildInfoRow(String label, String description) {
    return Row(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        const Text('• ', style: TextStyle(fontWeight: FontWeight.bold)),
        Expanded(
          child: RichText(
            text: TextSpan(
              style: Theme.of(context).textTheme.bodySmall,
              children: [
                TextSpan(
                  text: '$label: ',
                  style: const TextStyle(fontWeight: FontWeight.w500),
                ),
                TextSpan(text: description),
              ],
            ),
          ),
        ),
      ],
    );
  }
}
0
likes
0
points
279
downloads

Publisher

verified publisherkrajna.dev

Weekly Downloads

Sentry integration for FlexLogger - provides error reporting and crash analytics capabilities.

Homepage
Repository (GitLab)
View/report issues

Topics

#logging #sentry #error-tracking #crash-reporting

License

unknown (license)

Dependencies

flex_logger, flutter, sentry_flutter

More

Packages that depend on flex_logger_sentry