@@ -182,6 +182,23 @@ class PerformanceScreen extends StatelessWidget {
182182 'Demonstrates the new SpanV2 API with streaming trace lifecycle. Creates spans and sets attributes.' ,
183183 buttonTitle: 'Emit SpanV2' ,
184184 ),
185+ if (Sentry .currentHub.options.traceLifecycle ==
186+ SentryTraceLifecycle .stream) ...[
187+ TooltipButton (
188+ onPressed: () => makeFailingWebRequest (context),
189+ key: const Key ('http_failing_request' ),
190+ text:
191+ 'Requests a 404 inside a span. The captured error should be linked to the http.client span in Sentry.' ,
192+ buttonTitle: 'Dart: Failing web request' ,
193+ ),
194+ TooltipButton (
195+ onPressed: () => makeFailingWebRequestWithDio (context),
196+ key: const Key ('dio_failing_request' ),
197+ text:
198+ 'Requests a 404 through Dio inside a span. The captured error should be linked to the http.client span in Sentry.' ,
199+ buttonTitle: 'Dio: Failing web request' ,
200+ ),
201+ ],
185202 ],
186203 ),
187204 ),
@@ -343,6 +360,72 @@ Future<void> makeWebRequest(BuildContext context) async {
343360 }
344361}
345362
363+ /// A URL that reliably answers 404, to demo linking an error to its
364+ /// `http.client` span.
365+ final _failingUrl = Uri .parse ('${exampleUrl }0' );
366+
367+ final _failingStatusCodes = [SentryStatusCode (404 )];
368+
369+ Future <void > makeFailingWebRequest (BuildContext context) async {
370+ final client = SentryHttpClient (
371+ failedRequestStatusCodes: _failingStatusCodes,
372+ );
373+
374+ late SentryId traceId;
375+ int ? statusCode;
376+ await Sentry .startSpan ('http-failing-request' , (span) async {
377+ traceId = span.traceId;
378+ statusCode = (await client.get (_failingUrl)).statusCode;
379+ });
380+
381+ if (! context.mounted) return ;
382+ await _showLinkedErrorDialog (context, traceId, statusCode);
383+ }
384+
385+ Future <void > makeFailingWebRequestWithDio (BuildContext context) async {
386+ final dio = Dio ();
387+ dio.addSentry (failedRequestStatusCodes: _failingStatusCodes);
388+
389+ late SentryId traceId;
390+ int ? statusCode;
391+ await Sentry .startSpan ('dio-failing-request' , (span) async {
392+ traceId = span.traceId;
393+ try {
394+ await dio.getUri <String >(_failingUrl);
395+ } on DioException catch (exception) {
396+ statusCode = exception.response? .statusCode;
397+ }
398+ });
399+
400+ if (! context.mounted) return ;
401+ await _showLinkedErrorDialog (context, traceId, statusCode);
402+ }
403+
404+ Future <void > _showLinkedErrorDialog (
405+ BuildContext context,
406+ SentryId traceId,
407+ int ? statusCode,
408+ ) async {
409+ await showDialog <void >(
410+ context: context,
411+ builder: (context) {
412+ return AlertDialog (
413+ title: Text ('Captured $statusCode ' ),
414+ content: SelectableText (
415+ 'Search this trace in Sentry to see the error linked to the '
416+ 'http.client span:\n\n $traceId ' ,
417+ ),
418+ actions: [
419+ MaterialButton (
420+ onPressed: () => Navigator .pop (context),
421+ child: const Text ('Close' ),
422+ ),
423+ ],
424+ );
425+ },
426+ );
427+ }
428+
346429Future <void > _showWebResponseDialog (
347430 BuildContext context, int ? statusCode, String body) async {
348431 await showDialog <void >(
0 commit comments