m8ty_crash_facade
A crash reporting facade that decouples app code from specific providers (Firebase Crashlytics, Dynatrace, Sentry). Uses rxdart PublishSubject to broadcast events — provider adapters subscribe and forward to their platform SDK.
Architecture
M8tyCrashFacade.instance is the singleton entry point.
Provider adapters subscribe to M8tyCrashFacade.instance.stream.
Multiple providers can subscribe simultaneously.
Providers handle their own SDK initialization independently.
API Surface
Event | Method | Purpose |
|---|
RecordError
| recordError(exception, stackTrace:, fatal:)
| Report a live exception |
RecordFlutterError
| recordFlutterError(details, fatal:)
| Report a Flutter framework error |
ReportError
| reportError(errorName, errorCode)
| Report a named non-crashing error |
ReportCrash
| reportCrash(errorName, reason, stackTrace)
| Report a named crash with strings |
ReportAction
| reportAction(actionName, values)
| Report a user action with key-value data |
LogMessage
| log(message)
| Log a free-form message |
SetUserId
| setUserId(userId)
| Identify the user |
SetCustomKey
| setCustomKey(key, value)
| Attach metadata to future reports |
Key Rules
Always use M8tyCrashFacade.instance — do not construct it directly.
Use reportAction for user actions with key-value data (maps to Dynatrace's enterAction/leaveAction pattern).
Use recordError for live exceptions, reportError for named non-crashing errors, reportCrash for pre-formatted crash strings.
Wire both FlutterError.onError and PlatformDispatcher.instance.onError for global crash capture.
Provider adapters must handle all CrashEvent subtypes (sealed class ensures exhaustiveness).
setUserId(null) clears the user context.
Examples
Report from app code
final crash = M8tyCrashFacade.instance;
crash.recordError(exception, stackTrace: stackTrace, fatal: true);
crash.reportError('checkout_validation_failed', 422);
crash.reportCrash('NullPointerException', 'reason', 'stackTrace');
crash.reportAction('Changed theme mode', {'ui_mode': 'dark'});
crash.log('User tapped checkout');
crash.setUserId('user-123');
crash.setUserId(null); // clear user
crash.setCustomKey('screen', 'home');
Wire global Flutter error handlers
void main() {
FlutterError.onError = (details) {
M8tyCrashFacade.instance.recordFlutterError(details, fatal: true);
};
PlatformDispatcher.instance.onError = (error, stack) {
M8tyCrashFacade.instance.recordError(error, stackTrace: stack, fatal: true);
return true;
};
runApp(const MyApp());
}
Write a provider adapter
M8tyCrashFacade.instance.stream.listen((event) {
switch (event) {
case RecordError(:final exception, :final stackTrace, :final fatal):
// forward to provider SDK
case RecordFlutterError(:final details, :final fatal):
// forward flutter error
case ReportError(:final errorName, :final errorCode):
// forward named error
case ReportCrash(:final errorName, :final reason, :final stackTrace):
// forward crash
case ReportAction(:final actionName, :final values):
// forward action
case LogMessage(:final message):
// forward log
case SetUserId(:final userId):
// forward user id
case SetCustomKey(:final key, :final value):
// forward metadata
}
});
03 June 2026