Flutter项目中如何加入Sentry监控

继由《Flutter应用监控体系Docker+Sentry部署》这篇文章后,其实还想写一些在Flutter项目中,如何加入Sentry来进行监控。一直没时间没动力写写,今天来补一补这口锅~

一、创建项目

首先,我们之前搭建了本地的Docker+Sentry,那我们可打开本地部署的Sentry网页,并创建项目。


Create Project
创建Flutter项目
Flutter项目

二、获取创建的Flutter项目的DNS

在Sentry网页中Settings -> Projects -> 选择你创建的项目 -> Client Keys(DNS)


DNS

三、pub.dev Sentry插件

可以在pub.dev上搜索sentry,会出来很多关于Sentry的插件,我们需要的可能是这几个:sentry_flutter、sentry_dio、sentry、sentry_link。

  • sentry: Sentry的Dary插件。
  • sentry_flutter: Sentry用于Flutter项目的插件,如果是flutter项目,用这个最好。
  • sentry_dio: Dio的Sentry拓展插件,用于Sentry可以监控Dio网络请求的插件。
  • sentry_link: 如果你的网络请求是GraphQL的话,可以使用这个插件,协助完成Sentry对GraphQL请求的监控,当然也可以将GraphQl转为Http请求(参见《Flutter中使用Dio代替GraphQL请求》)。

四、Flutter中加入Sentry监控

4.1 引入插件

首先,需要Sentry_flutter插件,然后根据你使用的网络请求按需选择插件,sentry_dio(Dio请求)、sentry_link(GraphQL请求)、如果是使用的http client发起请求的话,直接用sentry_flutter就行,无需其他插件。

dependencies:
  flutter:
    sdk: flutter
  sentry_flutter: ^6.17.0
  sentry_dio: ^6.20.1
4.2 初始化Sentry

首先,我们得在main.dart文件中,初始化sentry。插件SDK会自动捕获错误。

SentryOptions除了设置DNS、environment外还可以设置其他如:采样率、是否压缩、附件最大值等等,使用的时候可以按需配置。

import 'package:flutter/widgets.dart';
import 'package:sentry_flutter/sentry_flutter.dart';

Future<void> main() async {
  await SentryFlutter.init(
    (options) {
      options.dsn = 'https://example@sentry.io/add-your-dsn-here';  (这是Sentry创建项目的时候的DNS,参见“二、获取创建的Flutter项目的DNS”)
      options.environment = 'Dev'; (设置环境,如:Dev、Stage、Live等)
    },
    // Init your App.
    appRunner: () => runApp(MyApp()),
  );
}
4.3 AssetBundle 的性能监控

Sentry还能监控我们在pubspec.yaml配置的Asset性能。

import 'package:flutter/widgets.dart';
import 'package:sentry_flutter/sentry_flutter.dart';

Future<void> main() async {
  await SentryFlutter.init(
    (options) {
      options.dsn = 'https://example@sentry.io/add-your-dsn-here';  
      options.environment = 'Dev'; (
    },
    // Init your App.
    appRunner: () => runApp(
      DefaultAssetBundle(
        bundle: SentryAssetBundle(),
        child: MyApp(),
      ),
    ),
  );
}
4.4 监控页面路由Navigation

可以在你的MaterialApp、WidgetsApp或者CupertinoApp下添加observers。

MaterialApp(
   navigatorObservers: [
      SentryNavigatorObserver()
   ],
   ...
);
4.5 网络请求监控

网络请求可以分为三种情况,三种请求使用方式不一样。

4.5.1 使用HttpClient请求时
  • 可以直接使用SentryHttpClient(),并且可以设置你需要监控的http Status Code
import 'package:sentry/sentry.dart';

var client = var client = SentryHttpClient(
  failedRequestStatusCodes: [
    SentryStatusCode.range(400, 404),
    SentryStatusCode(500),
  ],
);;
try {
 var uriResponse = await client.post('https://example.com/whatsit/create',
     body: {'name': 'doodle', 'color': 'blue'});
 print(await client.get(uriResponse.bodyFields['uri']));
} finally {
 client.close();
}
  • 如果你使用的是http.Client(),SentryHttpClient可以包装它
import 'package:sentry/sentry.dart';
import 'package:http/http.dart' as http;

final myClient = http.Client();

var client = SentryHttpClient(client: myClient);
try {
var uriResponse = await client.post('https://example.com/whatsit/create',
     body: {'name': 'doodle', 'color': 'blue'});
 print(await client.get(uriResponse.bodyFields['uri']));
} finally {
 client.close();
}
4.5.2 使用Dio请求时

需要添加sentry_dio: ^6.20.1插件,它会对Dio进行拓展。它可以设置一些参数值,控制网络请求监控。

    Dio dio = Dio();

    dio.addSentry(
      captureFailedRequests: true,
      maxRequestBodySize: MaxRequestBodySize.always,
      maxResponseBodySize: MaxResponseBodySize.always,
    );
使用Dio进行网络请求时,我之前聊过如何进行http 代理,《Flutter中Dio动态设置Http代理IP和端口》《Flutter中Dio如何抓取Https》

但是如果当Dio请求网络代理和Dio sentry监控碰到一起之后,会产生报错:

_dio.httpClientAdapter is SentryDioClientAdapter , not sub type of DefaultHttpClientAdapter.

因为进过Sentry_dio插件包装Dio之后,Dio的网络适配器不再是DefaultHttpClientAdapter,而是包装为SentryDioClientAdapter。所以导致报错,SentryDioClientAdapter又不对外可见,压根就无法直接引用,所以,我想出了这个方法。

  • 在Dio创建实例的时候,保存下原始的HttpClientAdapter:
    Dio dio = Dio();

    httpClientAdapter = dio.httpClientAdapter;

    dio.addSentry(
      captureFailedRequests: true,
      maxRequestBodySize: MaxRequestBodySize.always,
      maxResponseBodySize: MaxResponseBodySize.always,
    );
  • 然后,在设置代理的时候判断下类型:
String proxy = "PROXY ${ipController.text}:${portController.text}";

if(!(dio?.httpClientAdapter is DefaultHttpClientAdapter)){
  dio?.httpClientAdapter = HttpRequest().httpClientAdapter;
}

(dio?.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
    (client) {
  client.findProxy = (url) {
    return proxy;
  };

  //Trust certificate for https proxy
  client.badCertificateCallback = (cert, host, port){
    return true;
  };
  return client;
};

参见Github issue: How to set PROXY when use sentry dio

4.5.3 使用GraphQL请求时

需要添加sentry_link: ^0.2.1插件,我们只需要添加SentryGql.link()到我们的links里就行。

初始化时,添加LinkException的捕捉
Sentry.init((options) {
  options.addGqlExtractors();
});

final link = Link.from([
    AuthLink(getToken: () async => 'Bearer $personalAccessToken'),
    SentryGql.link(
      shouldStartTransaction: true,
      graphQlErrorsMarkTransactionAsFailed: true,
    ),
    HttpLink(
      'https://api.github.com/graphql',
      httpClient: SentryHttpClient(),
      serializer: SentryRequestSerializer(),
      parser: SentryResponseParser(),
    ),
  ]);
4.6 网络请求的性能监控

上面是网络请求的监听,这里要监控下网络请求的性能,

    transaction = Sentry.getSpan() ??
        Sentry.startTransaction(
          'dio-mobile-request',
          'request',
          bindToScope: true,
        );
    
    ISentrySpan? span = transaction.startChild(
        'Get',
        description: path,
      );
    }

    try{
      if(errorResponse == null) {
        response = await dio!.get().catchError((error) {
          errorResponse = getErrorResponse(error);
        });
        span?.status = SpanStatus.fromHttpStatusCode(response.statusCode ?? -1);
      }
    }catch (exception) {
      print(exception);
      span?.status = SpanStatus.internalError();
      span?.throwable = exception;
    }finally{
      await span?.finish();
    }

五、无

差不多了,基本用法就这些了~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345