flex_logger_sentry 1.0.4
flex_logger_sentry: ^1.0.4 copied to clipboard
Sentry integration for FlexLogger - provides error reporting and crash analytics capabilities.
// Example: FlexLogger + Sentry
import 'package:flex_logger/flex_logger.dart';
import 'package:flex_logger_sentry/flex_logger_sentry.dart';
import 'package:flutter/material.dart';
/// Replace with your Sentry DSN from sentry.io → Project Settings → Client Keys.
const _kSentryDsn = 'https://your-key@o4508054373466112.ingest.de.sentry.io/4508054375235664';
/// 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 => CompositeLogFilter.or([
const TypeFilter<ErrorLog>(),
const TypeFilter<CriticalLog>(),
]),
FilterType.composite => CompositeLogFilter.and([
const MinLevelFilter(FlexLogLevel.error),
CompositeLogFilter.not(const DevelopmentOnlyFilter()),
]),
};
}
}
enum FilterType {
minLevelWarning,
minLevelError,
typeFilter,
composite,
}
void main() async {
WidgetsFlutterBinding.ensureInitialized();
FlexLogger.instance.configure(
providers: [
SentryLoggerProvider(
dsn: _kSentryDsn,
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;
},
),
],
);
await FlexLogger.instance.initialize();
FlexLogger.instance.info('Flex Logger Sentry example started');
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flex Logger Sentry',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.amber),
useMaterial3: true,
),
home: const MyHomePage(title: 'Sentry Example'),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
const MyHomePage({super.key, required this.title});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
SentryFilterPreset _selectedFilter = SentryFilterPreset.warningAndAbove;
Future<void> _selectFilter(SentryFilterPreset filter) async {
if (filter == _selectedFilter) return;
setState(() => _selectedFilter = filter);
await _reconfigureLogger();
}
@override
void dispose() {
// CRITICAL: Dispose logger (calls Sentry.close())
FlexLogger.instance.dispose();
super.dispose();
}
Future<void> _reconfigureLogger() async {
await FlexLogger.instance.dispose();
FlexLogger.instance.configure(
providers: [
SentryLoggerProvider(
dsn: _kSentryDsn,
filter: _selectedFilter.toFilter(),
optionsConfiguration: (options) {
options.debug = false;
options.environment = 'example';
},
),
],
);
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: [
// Filter configuration
_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 _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),
Wrap(
spacing: 8,
runSpacing: 8,
children: SentryFilterPreset.values.map((filter) {
final selected = filter == _selectedFilter;
return FilterChip(
label: Text(filter.label),
selected: selected,
onSelected: (_) => _selectFilter(filter),
);
}).toList(),
),
],
),
),
);
}
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),
],
),
),
),
],
);
}
}