继由《Flutter应用监控体系Docker+Sentry部署》这篇文章后,其实还想写一些在Flutter项目中,如何加入Sentry来进行监控。一直没时间没动力写写,今天来补一补这口锅~
一、创建项目
首先,我们之前搭建了本地的Docker+Sentry,那我们可打开本地部署的Sentry网页,并创建项目。
创建Flutter项目
二、获取创建的Flutter项目的DNS
在Sentry网页中Settings -> Projects -> 选择你创建的项目 -> Client Keys(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();
}
五、无
差不多了,基本用法就这些了~