Line data Source code
1 : library timber_sentry; 2 : 3 : import 'package:flutter/foundation.dart'; 4 : import 'package:logging/logging.dart' as $logging; 5 : import 'package:sentry/sentry.dart'; 6 : // ignore: implementation_imports 7 : import 'package:sentry/src/hub.dart'; 8 : import 'package:timber/timber.dart'; 9 : 10 : import 'provider.dart'; 11 : 12 3 : final _logger = $logging.Logger('SentryTree'); 13 : 14 : class SentryTree extends Tree with CrashReportTree, LogTree { 15 : final ReleaseProvider releaseProvider; 16 : final EnvironmentProvider environmentProvider; 17 : final UserProvider userProvider; 18 : final ContextsProvider contextsProvider; 19 : final SentryLevel minEventLevel; 20 : final SentryLevel minBreadcrumbLevel; 21 : final Hub hub; 22 : 23 2 : SentryTree(this.hub, 24 : {SentryOptions sentryOptions, 25 : this.userProvider, 26 : this.contextsProvider, 27 : this.environmentProvider, 28 : this.releaseProvider, 29 : this.minBreadcrumbLevel = SentryLevel.info, 30 : this.minEventLevel = SentryLevel.error}) { 31 : /* 32 : Sentry.init((options) async { 33 : return options 34 : ..debug = sentryOptions?.debug ?? options.release 35 : ..release = sentryOptions?.release ?? options.release 36 : ..environment = sentryOptions?.environment ?? 37 : await environmentProvider?.provide() ?? 38 : options.environment 39 : ..beforeBreadcrumb = 40 : sentryOptions?.beforeBreadcrumb ?? options.beforeBreadcrumb 41 : ..compressPayload = sentryOptions?.compressPayload 42 : ..diagnosticLevel = sentryOptions?.diagnosticLevel 43 : ..dist = sentryOptions?.dist ?? options.dist 44 : ..dsn = sentryOptions?.dsn ?? options.dsn 45 : ..logger = _defaultLogger 46 : ..sampleRate = sentryOptions?.sampleRate ?? options.sampleRate 47 : ..maxBreadcrumbs = 48 : sentryOptions?.maxBreadcrumbs ?? options.maxBreadcrumbs; 49 : });*/ 50 : } 51 : 52 : /// do not log if it's lower than min. required level. 53 1 : bool _isLoggable(SentryLevel level, SentryLevel minLevel) => 54 3 : level.ordinal >= minLevel.ordinal; 55 : 56 : /// Captures a Sentry Event if the min. level is equal or higher than the min. required level. 57 : @override 58 1 : void performLog($logging.LogRecord record) async { 59 2 : final level = record.level.toSentryLevel; 60 : 61 : // Capture Event 62 : 63 1 : _captureEvent(level, record); 64 1 : _addBreadcrumb(level, record); 65 : } 66 : 67 : /// Captures an event with the given record 68 1 : void _captureEvent(SentryLevel sentryLevel, $logging.LogRecord record) async { 69 2 : if (_isLoggable(sentryLevel, minEventLevel)) { 70 4 : final sentryId = await hub.captureEvent(SentryEvent( 71 2 : level: record.level.toSentryLevel, 72 1 : stackTrace: record.stackTrace, 73 1 : exception: record.error, 74 2 : message: Message(record.message), 75 1 : logger: record.loggerName, 76 : )); 77 : } 78 : } 79 : 80 : /// Adds a breadcrumb 81 1 : void _addBreadcrumb(SentryLevel sentryLevel, $logging.LogRecord record) { 82 : // checks the breadcrumb level 83 2 : if (_isLoggable(sentryLevel, minBreadcrumbLevel)) { 84 3 : hub.addBreadcrumb(record.toBreadcrumb); 85 : } 86 : } 87 : 88 : @override 89 1 : void performReportError(dynamic error, dynamic stackTrace) async { 90 2 : _logger.info('performReportError'); 91 2 : _logger.info('Reporting to Sentry.io... '); 92 : // 프로덕션 모드에서는 exception과 stacktrace를 Sentry로 보냅니다. 93 2 : await _captureError(error, stackTrace); 94 : } 95 : 96 1 : Future<SentryId> _captureError(dynamic error, dynamic stackTrace) async { 97 : try { 98 : // Capture Event 99 4 : final eventId = await hub.captureEvent(SentryEvent( 100 : stackTrace: stackTrace, 101 2 : release: await releaseProvider?.provide(), 102 : exception: error, 103 2 : environment: await environmentProvider?.provide(), 104 2 : user: await userProvider?.provide(), 105 2 : contexts: await contextsProvider?.provide())); 106 3 : _logger.info('Success! Event ID: $eventId'); 107 : return eventId; 108 : } catch (e) { 109 3 : _logger.info('Failed to report to Sentry.io: $e', e); 110 : return null; 111 : } 112 : } 113 : 114 : @override 115 1 : void performReportFlutterError(FlutterErrorDetails errorDetails) async { 116 2 : _logger.info('Reporting to Sentry.io...'); 117 : // 프로덕션 모드에서는 exception과 stacktrace를 Sentry로 보냅니다. 118 2 : await _captureFlutterError(errorDetails); 119 : } 120 : 121 1 : Future<void> _captureFlutterError(FlutterErrorDetails errorDetails) async { 122 : try { 123 4 : final eventId = await hub.captureEvent(SentryEvent( 124 1 : stackTrace: errorDetails.stack, 125 2 : release: await releaseProvider?.provide(), 126 1 : exception: errorDetails.exception, 127 2 : message: Message(errorDetails.toString()), 128 2 : environment: await environmentProvider?.provide(), 129 2 : user: await userProvider?.provide(), 130 2 : contexts: await contextsProvider?.provide())); 131 : 132 3 : _logger.info('Success! Event ID: $eventId'); 133 : } catch (e) { 134 3 : _logger.info('Failed to report to Sentry.io: $e', e); 135 : } 136 : } 137 : 138 1 : @override 139 : void dispose() { 140 2 : return hub?.close(); 141 : } 142 : } 143 : 144 : extension LevelX on $logging.Level { 145 : /// Converts from Logging Level to SentryLevel. 146 : /// Fallback to SentryLevel.DEBUG. 147 1 : SentryLevel get toSentryLevel { 148 2 : if (this >= $logging.Level.FINEST && this < $logging.Level.INFO) { 149 : return SentryLevel.debug; 150 2 : } else if (this >= $logging.Level.INFO && this < $logging.Level.WARNING) { 151 : return SentryLevel.info; 152 2 : } else if (this >= $logging.Level.WARNING && this < $logging.Level.SEVERE) { 153 : return SentryLevel.warning; 154 2 : } else if (this >= $logging.Level.SEVERE && this < $logging.Level.SHOUT) { 155 : return SentryLevel.error; 156 2 : } else if (this >= $logging.Level.SHOUT && this < $logging.Level.OFF) { 157 : return SentryLevel.fatal; 158 : } else { 159 : return SentryLevel.debug; 160 : } 161 : } 162 : } 163 : 164 : extension LogRecordX on $logging.LogRecord { 165 1 : Breadcrumb get toBreadcrumb { 166 1 : return Breadcrumb( 167 2 : level: level.toSentryLevel, 168 1 : message: message, 169 1 : type: loggerName, 170 1 : data: object, 171 1 : timestamp: time, 172 : ); 173 : } 174 : } 175 : 176 : /* 177 : extension SentryLevelX on SentryLevel { 178 : $logging.Level get toLevel { 179 : switch (this) { 180 : case SentryLevel.debug: 181 : return $logging.Level.FINEST; 182 : case SentryLevel.fatal: 183 : return $logging.Level.SHOUT; 184 : case SentryLevel.warning: 185 : return $logging.Level.WARNING; 186 : case SentryLevel.error: 187 : return $logging.Level.SEVERE; 188 : case SentryLevel.info: 189 : return $logging.Level.INFO; 190 : default: 191 : return $logging.Level.FINEST; 192 : } 193 : } 194 : } 195 : */