Skip to content

Commit 12f2d65

Browse files
committed
feat: implement global bugsee exception handler
1 parent 0f12bb3 commit 12f2d65

5 files changed

Lines changed: 104 additions & 114 deletions

File tree

src/app/.env.staging

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ REMOTE_CONFIG_FETCH_INTERVAL_MINUTES=1
88
DIAGNOSTIC_ENABLED=true
99
IS_DATA_OBSCURE=true
1010
DISABLE_LOG_COLLECTION=true
11-
FILTER_LOG_COLLECTION=true
11+
FILTER_LOG_COLLECTION=false
1212
ATTACH_LOG_FILE=true

src/app/lib/business/bugsee/bugsee_manager.dart

Lines changed: 64 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'dart:async';
22
import 'dart:io';
33
import 'package:app/access/bugsee/bugsee_configuration_data.dart';
44
import 'package:app/access/bugsee/bugsee_repository.dart';
5+
import 'package:app/access/persistence_exception.dart';
56
import 'package:app/business/bugsee/bugsee_config_state.dart';
67
import 'package:app/business/logger/logger_manager.dart';
78
import 'package:bugsee_flutter/bugsee_flutter.dart';
@@ -16,22 +17,20 @@ const String bugseeFilterRegex = r'.';
1617

1718
/// Service related to initializing Bugsee service
1819
abstract interface class BugseeManager {
19-
factory BugseeManager({
20-
required Logger logger,
21-
required LoggerManager loggerManager,
22-
required BugseeRepository bugseeRepository,
23-
}) = _BugseeManager;
20+
factory BugseeManager() = _BugseeManager;
2421

2522
/// Current BugseeManager state
2623
BugseeConfigState get bugseeConfigState;
27-
bool get onPressExceptionActivated;
2824

2925
/// Initialize bugsee with given token
3026
/// bugsee is not available in debug mode
3127
/// * [bugseeToken]: nullable bugsee token, if null bugsee won't be initialized make sure you provide
3228
/// [BUGSEE_TOKEN] in the env using `--dart-define` or `launch.json` on vscode
3329
Future<void> initialize({
3430
String? bugseeToken,
31+
required Logger logger,
32+
required LoggerManager loggerManager,
33+
required BugseeRepository bugseeRepository,
3534
});
3635

3736
/// Manually log a provided exception with a stack trace
@@ -47,14 +46,6 @@ abstract interface class BugseeManager {
4746
StackTrace? stackTrace,
4847
Map<String, dynamic>? traces,
4948
Map<String, Map<String, dynamic>?>? events,
50-
Map<String, dynamic>? attributes,
51-
});
52-
53-
/// Manually log an unhandled exception with a stack trace
54-
/// (critical severity exception in Bugsee dashboard)
55-
Future<void> logUnhandledException({
56-
required Exception exception,
57-
StackTrace? stackTrace,
5849
});
5950

6051
/// Manually update the current BugseeEnabled flag in shared prefs and in current manager singleton.
@@ -75,29 +66,26 @@ abstract interface class BugseeManager {
7566
/// Manually update isLogFilterEnabled flag in shared prefs.
7667
Future<void> setIsLogFilterEnabeld(bool value);
7768

78-
/// Manually update whether bugsee will catch exception when pressing
79-
/// dadjoke item or not.
80-
///
81-
/// By is set to `false`
82-
void setOnPressExceptionActivated(bool value);
83-
8469
/// Manually update whether Bugsee attach the log file with the reported
8570
/// exception or not.
8671
///
8772
/// By default the log file is attached
8873
Future<void> setAttachLogFileEnabled(bool value);
74+
75+
//TODO add documentation
76+
Future<void> inteceptor(Object error, StackTrace stackTrace);
77+
Future<void> addAttributes(Map<String, dynamic> attributes);
78+
Future<void> addEmailAttribute(String email);
79+
Future<void> clearEmailAttribute();
80+
Future<void> clearAttribute(String attribute);
8981
}
9082

9183
final class _BugseeManager implements BugseeManager {
92-
final Logger logger;
93-
final LoggerManager loggerManager;
94-
final BugseeRepository bugseeRepository;
95-
96-
_BugseeManager({
97-
required this.logger,
98-
required this.loggerManager,
99-
required this.bugseeRepository,
100-
});
84+
late Logger logger;
85+
late LoggerManager loggerManager;
86+
late BugseeRepository bugseeRepository;
87+
88+
_BugseeManager();
10189

10290
BugseeConfigState _currentState = const BugseeConfigState();
10391

@@ -107,15 +95,19 @@ final class _BugseeManager implements BugseeManager {
10795
late bool _isBugSeeInitialized;
10896
late BugseeConfigurationData configurationData;
10997

110-
@override
111-
bool onPressExceptionActivated = false;
112-
11398
BugseeLaunchOptions? launchOptions;
11499

115100
@override
116101
Future<void> initialize({
117102
String? bugseeToken,
103+
required Logger logger,
104+
required LoggerManager loggerManager,
105+
required BugseeRepository bugseeRepository,
118106
}) async {
107+
this.logger = logger;
108+
this.loggerManager = loggerManager;
109+
this.bugseeRepository = bugseeRepository;
110+
119111
configurationData = await bugseeRepository.getBugseeConfiguration();
120112
configurationData = configurationData.copyWith(
121113
isLogCollectionEnabled: configurationData.isLogCollectionEnabled ??
@@ -231,7 +223,6 @@ final class _BugseeManager implements BugseeManager {
231223
StackTrace? stackTrace,
232224
Map<String, dynamic>? traces,
233225
Map<String, Map<String, dynamic>?>? events,
234-
Map<String, dynamic>? attributes,
235226
}) async {
236227
if (_currentState.isBugseeEnabled) {
237228
if (traces != null) {
@@ -246,26 +237,10 @@ final class _BugseeManager implements BugseeManager {
246237
}
247238
}
248239

249-
if (attributes != null) {
250-
for (var attribute in attributes.entries) {
251-
await Bugsee.setAttribute(attribute.key, attribute.value);
252-
}
253-
}
254-
255240
await Bugsee.logException(exception, stackTrace);
256241
}
257242
}
258243

259-
@override
260-
Future<void> logUnhandledException({
261-
required Exception exception,
262-
StackTrace? stackTrace,
263-
}) async {
264-
if (_currentState.isBugseeEnabled) {
265-
await Bugsee.logUnhandledException(exception);
266-
}
267-
}
268-
269244
@override
270245
Future<void> setIsBugseeEnabled(bool value) async {
271246
if (_currentState.isConfigurationValid) {
@@ -345,11 +320,6 @@ final class _BugseeManager implements BugseeManager {
345320
}
346321
}
347322

348-
@override
349-
void setOnPressExceptionActivated(bool value) {
350-
onPressExceptionActivated = value;
351-
}
352-
353323
@override
354324
Future<void> setAttachLogFileEnabled(bool value) async {
355325
if (_currentState.isBugseeEnabled) {
@@ -360,4 +330,44 @@ final class _BugseeManager implements BugseeManager {
360330
);
361331
}
362332
}
333+
334+
@override
335+
Future<void> inteceptor(
336+
Object error,
337+
StackTrace stackTrace,
338+
) async {
339+
String? message = switch (error.runtimeType) {
340+
const (PersistenceException) => (error as PersistenceException).message,
341+
_ => null,
342+
};
343+
await logException(
344+
exception: Exception(error),
345+
stackTrace: stackTrace,
346+
traces: {
347+
'message': message,
348+
},
349+
);
350+
}
351+
352+
@override
353+
Future<void> addAttributes(Map<String, dynamic> attributes) async {
354+
for (var attribute in attributes.entries) {
355+
await Bugsee.setAttribute(attribute.key, attribute.value);
356+
}
357+
}
358+
359+
@override
360+
Future<void> clearAttribute(String attribute) async {
361+
await Bugsee.clearAttribute(attribute);
362+
}
363+
364+
@override
365+
Future<void> addEmailAttribute(String email) async {
366+
await Bugsee.setEmail(email);
367+
}
368+
369+
@override
370+
Future<void> clearEmailAttribute() async {
371+
await Bugsee.clearEmail();
372+
}
363373
}

src/app/lib/main.dart

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'dart:async';
12
import 'dart:io';
23

34
import 'package:alice/alice.dart';
@@ -36,8 +37,14 @@ import 'package:logger/logger.dart';
3637
late Logger _logger;
3738

3839
Future<void> main() async {
39-
await initializeComponents();
40-
runApp(const App());
40+
_initializeBugseeManager();
41+
runZonedGuarded(
42+
() async {
43+
await initializeComponents();
44+
runApp(const App());
45+
},
46+
GetIt.I.get<BugseeManager>().inteceptor,
47+
);
4148
}
4249

4350
Future initializeComponents({bool? isMocked}) async {
@@ -119,17 +126,19 @@ Future _registerAndLoadLoggers() async {
119126
GetIt.I.registerSingleton(_logger);
120127
}
121128

122-
Future _registerBugseeManager() async {
129+
void _initializeBugseeManager() {
123130
GetIt.I.registerSingleton<BugseeRepository>(BugseeRepository());
124131
GetIt.I.registerSingleton<BugseeManager>(
125-
BugseeManager(
126-
logger: GetIt.I.get<Logger>(),
127-
loggerManager: GetIt.I.get<LoggerManager>(),
128-
bugseeRepository: GetIt.I.get<BugseeRepository>(),
129-
),
132+
BugseeManager(),
130133
);
134+
}
135+
136+
Future _registerBugseeManager() async {
131137
GetIt.I.get<BugseeManager>().initialize(
132138
bugseeToken: const String.fromEnvironment('BUGSEE_TOKEN'),
139+
logger: GetIt.I.get<Logger>(),
140+
loggerManager: GetIt.I.get<LoggerManager>(),
141+
bugseeRepository: GetIt.I.get<BugseeRepository>(),
133142
);
134143
}
135144

src/app/lib/presentation/dad_jokes/dad_joke_list_item.dart

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,6 @@ final class DadJokeListItem extends StatelessWidget {
3939
titleAlignment: ListTileTitleAlignment.top,
4040
contentPadding: const EdgeInsets.all(16),
4141
onTap: () async {
42-
if (_bugseeManager.onPressExceptionActivated) {
43-
_bugseeManager.logException(
44-
exception: Exception(),
45-
attributes: {
46-
'id': dadJoke.id,
47-
'title': dadJoke.title,
48-
},
49-
);
50-
}
51-
5242
if (dadJoke.isFavorite) {
5343
await _dadJokesService.removeFavoriteDadJoke(dadJoke);
5444
} else {

src/app/lib/presentation/diagnostic/bugsee_configuration_widget.dart

Lines changed: 22 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,11 @@ class _BugseeConfigurationWidgetState extends State<BugseeConfigurationWidget> {
2020
final BugseeManager bugseeManager = GetIt.I.get<BugseeManager>();
2121

2222
late BugseeConfigState state;
23-
bool onPressItemLogException = false;
2423

2524
@override
2625
void initState() {
2726
super.initState();
2827
state = bugseeManager.bugseeConfigState;
29-
onPressItemLogException = bugseeManager.onPressExceptionActivated;
3028
}
3129

3230
@override
@@ -113,17 +111,6 @@ class _BugseeConfigurationWidgetState extends State<BugseeConfigurationWidget> {
113111
});
114112
},
115113
),
116-
DiagnosticSwitch(
117-
label: 'Log exception on pressing dad joke item',
118-
value: onPressItemLogException,
119-
onChanged: (value) async {
120-
bugseeManager.setOnPressExceptionActivated(value);
121-
setState(() {
122-
onPressItemLogException =
123-
bugseeManager.onPressExceptionActivated;
124-
});
125-
},
126-
),
127114
DiagnosticSwitch(
128115
label: 'Attach log file',
129116
value: state.attachLogFile,
@@ -142,24 +129,6 @@ class _BugseeConfigurationWidgetState extends State<BugseeConfigurationWidget> {
142129
bugseeManager.logException(exception: Exception());
143130
},
144131
),
145-
DiagnosticButton(
146-
label: 'Log an unhandled exception',
147-
onPressed: () {
148-
bugseeManager.logUnhandledException(exception: Exception());
149-
},
150-
),
151-
DiagnosticButton(
152-
label: 'Log Exception with traces',
153-
onPressed: () {
154-
bugseeManager.logException(
155-
exception: Exception(),
156-
traces: {
157-
'date': DateTime.now().millisecondsSinceEpoch,
158-
'id': Random().nextInt(20),
159-
},
160-
);
161-
},
162-
),
163132
DiagnosticButton(
164133
label: 'Log Exception with events',
165134
onPressed: () {
@@ -175,17 +144,29 @@ class _BugseeConfigurationWidgetState extends State<BugseeConfigurationWidget> {
175144
},
176145
),
177146
DiagnosticButton(
178-
label: 'Delete all attribute',
147+
label: 'Add email attributes',
179148
onPressed: () {
180-
bugseeManager.logException(
181-
exception: Exception(),
182-
events: {
183-
'data': {
184-
'date': DateTime.now().millisecondsSinceEpoch,
185-
'id': Random().nextInt(20),
186-
},
187-
},
188-
);
149+
bugseeManager.addEmailAttribute('john.doe@nventive.com');
150+
},
151+
),
152+
DiagnosticButton(
153+
label: 'Add name attribute',
154+
onPressed: () {
155+
bugseeManager.addAttributes({
156+
'name': 'John Doe',
157+
});
158+
},
159+
),
160+
DiagnosticButton(
161+
label: 'Clear email attribute',
162+
onPressed: () {
163+
bugseeManager.clearEmailAttribute();
164+
},
165+
),
166+
DiagnosticButton(
167+
label: 'Clear name attribute',
168+
onPressed: () {
169+
bugseeManager.clearAttribute('name');
189170
},
190171
),
191172
DiagnosticButton(

0 commit comments

Comments
 (0)